1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-23 04:41:24 +01:00

Squashed commit of the following:

commit e06668f042
Author: Asbelos <asbelos@btinternet.com>
Date:   Mon Dec 26 10:09:34 2022 +0000

    speedup

commit 3e5d3b1caa
Author: Asbelos <asbelos@btinternet.com>
Date:   Sun Dec 25 22:11:56 2022 +0000

    Rename

commit 81099af42b
Author: Asbelos <asbelos@btinternet.com>
Date:   Sun Dec 25 21:35:38 2022 +0000

    spelling and polling

commit 9240e7c6ba
Author: Asbelos <asbelos@btinternet.com>
Date:   Sun Dec 25 20:52:07 2022 +0000

    input working

commit 6c1c681a26
Author: Asbelos <asbelos@btinternet.com>
Date:   Wed Dec 21 11:18:39 2022 +0000

    input working

    1 board, no kit map, output untested

commit 5ce67fac97
Author: Asbelos <asbelos@btinternet.com>
Date:   Sun Dec 18 15:32:37 2022 +0000

    Include IO_DNU08 automatically

commit ac8d453d2c
Author: Asbelos <asbelos@btinternet.com>
Date:   Sun Dec 18 12:28:13 2022 +0000

    BNOU8 HAL driver
This commit is contained in:
Asbelos 2022-12-26 10:41:15 +00:00
parent 1d61a8f3f9
commit 0be25f6e7f
3 changed files with 214 additions and 3 deletions

View File

@ -161,6 +161,8 @@ public:
// once the GPIO port concerned has been read.
void setGPIOInterruptPin(int16_t pinNumber);
// Method to check if pins will overlap before creating new device.
static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1, uint8_t i2cAddress=0);
protected:
@ -234,9 +236,6 @@ protected:
// pin low if an input changes state.
int16_t _gpioInterruptPin = -1;
// Method to check if pins will overlap before creating new device.
static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1, uint8_t i2cAddress=0);
// Static support function for subclass creation
static void addDevice(IODevice *newDevice);
@ -408,5 +407,6 @@ private:
#include "IO_MCP23008.h"
#include "IO_MCP23017.h"
#include "IO_PCF8574.h"
#include "IO_duinoNodes.h"
#endif // iodevice_h

172
IO_duinoNodes.h Normal file
View File

@ -0,0 +1,172 @@
/*
* © 2022, Chris Harlow. All rights reserved.
*
* This file is part of DCC++EX API
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef IO_duinoNodes_h
#define IO_duinoNodes_h
#include <Arduino.h>
#include "defines.h"
#include "IODevice.h"
#define PIN_MASK(bit) (0x80>>(bit%8))
#define GET_BIT(x) (_pinValues[(x)/8] & PIN_MASK((x)) )
#define SET_BIT(x) _pinValues[(x)/8] |= PIN_MASK((x))
#define CLR_BIT(x) _pinValues[(x)/8] &= ~PIN_MASK((x))
#define DIAG_IO
class IO_duinoNodes : public IODevice {
public:
IO_duinoNodes(VPIN firstVpin, int nPins,
byte clockPin, byte latchPin, byte dataPin,
const byte* pinmap) :
IODevice(firstVpin, nPins) {
_latchPin=latchPin;
_clockPin=clockPin;
_dataPin=dataPin;
_pinMap=pinmap;
_nShiftBytes=(nPins+7)/8; // rounded up to multiples of 8 bits
_pinValues=(byte*) calloc(_nShiftBytes,1);
// Connect to HAL so my _write, _read and _loop will be called as required.
IODevice::addDevice(this);
}
// Called by HAL to start handling this device
void _begin() override {
_deviceState = DEVSTATE_NORMAL;
pinMode(_latchPin,OUTPUT);
pinMode(_clockPin,OUTPUT);
pinMode(_dataPin,_pinMap?INPUT_PULLUP:OUTPUT);
_display();
}
// loop called by HAL supervisor
void _loop(unsigned long currentMicros) override {
if (_pinMap) _loopInput(currentMicros);
else if (_xmitPending) _loopOutput();
}
void _loopInput(unsigned long currentMicros) {
if (currentMicros-_prevMicros < POLL_MICROS) return; // Nothing to do
_prevMicros=currentMicros;
//set latch to HIGH to freeze & store parallel data
ArduinoPins::fastWriteDigital(_latchPin, HIGH);
delayMicroseconds(1);
//set latch to LOW to enable the data to be transmitted serially
ArduinoPins::fastWriteDigital(_latchPin, LOW);
// stream in the bitmap using mapping order provided at constructor
for (int xmitByte=0;xmitByte<_nShiftBytes; xmitByte++) {
byte newByte=0;
for (int xmitBit=0;xmitBit<8; xmitBit++) {
ArduinoPins::fastWriteDigital(_clockPin, LOW);
delayMicroseconds(1);
bool data = ArduinoPins::fastReadDigital(_dataPin);
byte map=_pinMap[xmitBit];
if (data) newByte |= map;
else newByte &= ~map;
ArduinoPins::fastWriteDigital(_clockPin, HIGH);
delayMicroseconds(1);
}
_pinValues[xmitByte]=newByte;
// DIAG(F("DIN %x=%x"),xmitByte, newByte);
}
}
void _loopOutput() {
// stream out the bitmap (highest pin first)
_xmitPending=false;
ArduinoPins::fastWriteDigital(_latchPin, LOW);
for (int xmitBit=_nShiftBytes*8 -1; xmitBit>=0; xmitBit--) {
ArduinoPins::fastWriteDigital(_dataPin,GET_BIT(xmitBit));
ArduinoPins::fastWriteDigital(_clockPin,HIGH);
ArduinoPins::fastWriteDigital(_clockPin,LOW);
}
digitalWrite(_latchPin, HIGH);
}
int _read(VPIN vpin) override {
int pin=vpin - _firstVpin;
bool b=GET_BIT(pin);
return b?1:0;
}
void _write(VPIN vpin, int value) override {
int pin = vpin - _firstVpin;
bool oldval=GET_BIT(pin);
bool newval=value!=0;
if (newval==oldval) return; // no change
if (newval) SET_BIT(pin);
else CLR_BIT(pin);
_xmitPending=true; // shift register will be sent on next _loop()
}
void _display() override {
DIAG(F("IO_duinoNodes %SPUT Configured on VPins:%d-%d shift=%d"),
_pinMap?F("IN"):F("OUT"),
(int)_firstVpin,
(int)_firstVpin+_nPins-1, _nShiftBytes*8);
}
private:
static const unsigned long POLL_MICROS=100000; // 10 / S
unsigned long _prevMicros;
int _nShiftBytes=0;
VPIN _latchPin,_clockPin,_dataPin;
byte* _pinValues;
bool _xmitPending; // Only relevant in output mode
const byte* _pinMap; // NULL in output mode
};
class IO_DNIN8 {
public:
static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin )
{
// input arrives as board pin 0,7,6,5,1,2,3,4
static const byte pinmap[8]={0x80,0x01,0x02,0x04,0x40,0x20,0x10,0x08};
if (IODevice::checkNoOverlap(firstVpin,nPins))
new IO_duinoNodes( firstVpin, nPins, clockPin, latchPin, dataPin,pinmap);
}
};
class IO_DNIN8K {
public:
static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin )
{
// input arrives as board pin 0, 1, 2, 3, 4, 5, 6, 7
static const byte pinmap[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
if (IODevice::checkNoOverlap(firstVpin,nPins))
new IO_duinoNodes( firstVpin, nPins, clockPin, latchPin, dataPin,pinmap);
}
};
class IO_DNOU8 {
public:
static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin )
{
if (IODevice::checkNoOverlap(firstVpin,nPins))
new IO_duinoNodes( firstVpin, nPins, clockPin, latchPin, dataPin,NULL);
}
};
#endif

View File

@ -0,0 +1,39 @@
Using Lew's Duino Gear boards:
1. DNIN8 Input
This is a shift-register implementation of a digital input collector.
Multiple DNIN8 may be connected in sequence but it is IMPORTANT that the software
configuratuion correctly represents the number of boards connected otherwise the results will be meaningless.
Use in myAnimation.h
HAL(IO_DNIN8, firstVpin, numPins, clockPin, latchPin, dataPin)
e.g.
HAL(IO_DNIN8, 400, 16, 40, 42, 44)
OR Use in myHal.cpp
IO_DNIN8::create( firstVpin, numPins, clockPin, latchPin, dataPin)
This will create virtaul pins 400-415 using two DNIN8 boards connected in sequence.
Vpins 400-407 will be on the first board (closest to the CS) and 408-415 on the second.
Note: 16 pins uses two boards. You may specify a non-multiple-of-8 pins but this will be rounded up to a multiple of 8 and you must connect ONLY the number of boards that this takes.
This example uses Arduino GPIO pins 40,42,44 as these are conveniently side-by-side on a Mega which is easier when you are using a 3 strand cable.
The DNIN8K module works the same but you must use DNIN8K in the HAL setup instead of DNIN8. NO you cant mix 8 and 8k versions in the same string of boards but you can create another string of boards.
DNOU8 works the same way,
Use in myAnimation.h
HAL(IO_DNOU8, firstVpin, numPins, clockPin, latchPin, dataPin)
e.g.
HAL(IO_DNIN8, 450, 16, 45, 47, 49)
OR Use in myHal.cpp
IO_DNIN8::create( firstVpin, numPins, clockPin, latchPin, dataPin)
This creates a string of input pins 450-465. Note the clock/latch/data pins must be different to any DNIN8/k pins.