diff --git a/IODevice.h b/IODevice.h index bccf39b..6f12969 100644 --- a/IODevice.h +++ b/IODevice.h @@ -408,6 +408,6 @@ private: #include "IO_MCP23008.h" #include "IO_MCP23017.h" #include "IO_PCF8574.h" -#include "IO_DNOU8.h" +#include "IO_LEWDUINO.h" #endif // iodevice_h diff --git a/IO_DNOU8.h b/IO_DNOU8.h deleted file mode 100644 index b73f1f0..0000000 --- a/IO_DNOU8.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * © 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 . - */ -#ifndef IO_DNOU8_h - #define IO_DNOU8_h -#include -#include "IODevice.h" -#define GET_BIT(bit) ((_pinValues[bit/8] >>(bit%8) == 1)) -#define SET_BIT(bit) _pinValues[bit/8] |= 1<<(bit%8) -#define CLR_BIT(bit) _pinValues[bit/8] &= ~(1<<(bit%8)) - -class IO_DNOU8 : public IODevice { -public: - static void create(VPIN firstVpin, int nPins, byte latchPin, byte clockPin, byte dataPin ) - { - new IO_DNOU8( firstVpin, nPins, latchPin, clockPin, dataPin); - } - -protected: - IO_DNOU8(VPIN firstVpin, int nPins, byte latchPin, byte clockPin, byte dataPin) : - IODevice(firstVpin, nPins) { - _latchPin=latchPin; - _clockPin=clockPin; - _dataPin=dataPin; - _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 { - _xmitPending=true; // will cause transmission of all zeros first time out - _deviceState = DEVSTATE_NORMAL; - pinMode(_latchPin,OUTPUT); - pinMode(_clockPin,OUTPUT); - pinMode(_dataPin,OUTPUT); - _display(); - } - -void _loop(unsigned long currentMicros) override { - (void)currentMicros; // Not needed - - if (!_xmitPending) return; // Nothing to do - - #ifdef DIAG_IO - // We will create a DIAG on the fly - USB_SERIAL.print("<* DNOU8 "); - #endif - - // stream out the bitmap (highest pin first) - _xmitPending=false; - digitalWrite(_latchPin, LOW); - - for (int xmitBit=_nShiftBytes*8 -1; xmitBit>=0; xmitBit--) { - bool bit=GET_BIT(xmitBit); - #ifdef DIAG_IO - USB_SERIAL.print(bit?'1':'0'); - #endif - digitalWrite(_dataPin,bit); - digitalWrite(_clockPin,HIGH); - digitalWrite(_clockPin,LOW); - } - - digitalWrite(_latchPin, HIGH); - #ifdef DIAG_IO - USB_SERIAL.print(" *>\n"); - #endif - } - - 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() - } - - int _read(VPIN vpin) override { - int pin = vpin - _firstVpin; - return GET_BIT(pin); - } - - void _display() override { - DIAG(F("IO_DNOU8 Configured on VPins:%d-%d"), (int)_firstVpin, - (int)_firstVpin+_nPins-1); - } - -private: - bool _xmitPending=false; - int _nShiftBytes=0; - VPIN _latchPin,_clockPin,_dataPin; - byte* _pinValues; -}; - -#endif \ No newline at end of file diff --git a/IO_LEWDUINO.h b/IO_LEWDUINO.h new file mode 100644 index 0000000..dfa549d --- /dev/null +++ b/IO_LEWDUINO.h @@ -0,0 +1,159 @@ +/* + * © 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 . + */ +#ifndef IO_DNIN8_h + #define IO_DNIN8_h +#include +#define PIN_MASK(bit) (0x80>>(bit%8)) +#define GET_BIT(bit) (_pinValues[bit/8] & PIN_MASK(bit) ) +#define SET_BIT(bit) _pinValues[bit/8] |= PIN_MASK(bit) +#define CLR_BIT(bit) _pinValues[bit/8] &= ~PIN_MASK(bit) +#define DIAG_IO + + + +class IO_LEWDUINO : public IODevice { + +public: + IO_LEWDUINO(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,INPUT_PULLUP); + _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(20); + //set latch to LOW to enable the data to be transmitted serially + ArduinoPins::fastWriteDigital(_latchPin, LOW); + + // stream in the bitmap useing mapping order provided at constructor + for (int xmitBit=0;xmitBit<_nShiftBytes*8; xmitBit++) { + ArduinoPins::fastWriteDigital(_clockPin, LOW); + delayMicroseconds(4); + bool data = ArduinoPins::fastReadDigital(_dataPin); + byte map=_pinMap[xmitBit%8]; + //DIAG(F("DIN x=%d,d=%d m=%x"),xmitBit,data,map); + if (data) _pinValues[xmitBit/8] |= map; + else _pinValues[xmitBit/8] &= ~map; + ArduinoPins::fastWriteDigital(_clockPin, HIGH); + } + // DIAG(F("DIN %x"),_pinValues[0]); + } + +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 { + return GET_BIT(vpin - _firstVpin); + } + + 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_LEWDUINO %SPUT Configured on VPins:%d-%d"), + _pinMap?F("IN"):F("OUT"), + (int)_firstVpin, + (int)_firstVpin+_nPins-1); + } + +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 latchPin, byte clockPin, 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}; + new IO_LEWDUINO( firstVpin, nPins, latchPin, clockPin, dataPin,pinmap); + } + +}; + +class IO_DNIN8K { +public: + static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin ) + { + static const byte pinmap[8]={0x80,0x01,0x02,0x04,0x40,0x20,0x10,0x08}; // TODO + new IO_LEWDUINO( firstVpin, nPins, clockPin, latchPin, dataPin,pinmap); + } +}; + +class IO_DNOUT8 { +public: + static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin ) + { + new IO_LEWDUINO( firstVpin, nPins, clockPin, latchPin, dataPin,NULL); + } + +}; +#endif \ No newline at end of file