diff --git a/NeoSWSerial.cpp b/NeoSWSerial.cpp index 4ab4599..9c9384c 100644 --- a/NeoSWSerial.cpp +++ b/NeoSWSerial.cpp @@ -50,6 +50,7 @@ static uint8_t rxTail; // buffer pointer output static uint8_t rxBitMask, txBitMask; // port bit masks static volatile uint8_t *txPort; // port register +static bool inv; //invert the signal on the line //#define DEBUG_NEOSWSERIAL #ifdef DEBUG_NEOSWSERIAL @@ -115,8 +116,13 @@ void NeoSWSerial::listen() txBitMask = digitalPinToBitMask( txPin ); txPort = portOutputRegister( digitalPinToPort( txPin ) ); + inv = inverse; + // set idle state: logic 1 if (txPort) - *txPort |= txBitMask; // high = idle + if (inv) + *txPort &= ~txBitMask; // set TX line low + else + *txPort |= txBitMask; // set TX line high pinMode(txPin, OUTPUT); if (F_CPU == 8000000L) { @@ -132,7 +138,7 @@ void NeoSWSerial::listen() flush(); // Set up timings based on baud rate - + switch (_baudRate) { case 9600: txBitWidth = TICKS_PER_BIT_9600 ; @@ -212,7 +218,7 @@ void NeoSWSerial::setBaudRate(uint16_t baudRate) int NeoSWSerial::available() { uint8_t avail = ((rxHead - rxTail + RX_BUFFER_SIZE) % RX_BUFFER_SIZE); - + if (avail == 0) { cli(); if (checkRxTime()) { @@ -266,6 +272,9 @@ void NeoSWSerial::startChar() void NeoSWSerial::rxISR( uint8_t rxPort ) { uint8_t t0 = TCNTX; // time of data transition (plus ISR latency) + if (inv) { + rxPort = ~rxPort; + } uint8_t d = rxPort & rxBitMask; // read RX data level if (rxState == WAITING_FOR_START_BIT) { @@ -337,6 +346,7 @@ bool NeoSWSerial::checkRxTime() if (rxState != WAITING_FOR_START_BIT) { uint8_t d = *rxPort & rxBitMask; + if (inv) d = ~d; if (d) { // Ended on a 1, see if it has been too long @@ -410,13 +420,13 @@ ISR(PCINT0_vect) #elif defined(__AVR_ATtiny25__) | \ defined(__AVR_ATtiny45__) | \ - defined(__AVR_ATtiny85__) + defined(__AVR_ATtiny85__) PCINT_ISR(0, PINB); #elif defined(__AVR_ATtiny24__) | \ defined(__AVR_ATtiny44__) | \ - defined(__AVR_ATtiny84__) + defined(__AVR_ATtiny84__) PCINT_ISR(0, PINA); PCINT_ISR(1, PINB); @@ -471,7 +481,7 @@ size_t NeoSWSerial::write(uint8_t txChar) uint8_t width; // ticks for one bit uint8_t txBit = 0; // first bit is start bit - uint8_t b = 0; // start bit is low + bool b = false; // start bit is logic 0 uint8_t PCIbit = bit(digitalPinToPCICRbit(rxPin)); uint8_t prevSREG = SREG; @@ -479,13 +489,13 @@ size_t NeoSWSerial::write(uint8_t txChar) uint8_t t0 = TCNTX; // start time - // TODO: This would benefit from an early break after + // TODO: This would benefit from an early break after // the last 0 data bit. Then we could wait for the - // remaining 1 data bits and stop bit with interrupts + // remaining 1 data bits and stop bit with interrupts // re-enabled. while (txBit++ < 9) { // repeat for start bit + 8 data bits - if (b) // if bit is set + if (b != inv) // if desired state is high *txPort |= txBitMask; // set TX line high else *txPort &= ~txBitMask; // else set TX line low @@ -495,7 +505,7 @@ size_t NeoSWSerial::write(uint8_t txChar) (width == TICKS_PER_BIT_9600/4) && (txBit & 0x01)) { // The width is 6.5 ticks, so add a tick every other bit - width++; + width++; } // Hold the line for the bit duration @@ -516,7 +526,12 @@ size_t NeoSWSerial::write(uint8_t txChar) // Q: would a signed >> pull in a 1? } - *txPort |= txBitMask; // stop bit is high + // stop bit is logic 1 + if (inv) + *txPort &= ~txBitMask; // else set TX line low + else + *txPort |= txBitMask; // set TX line high + SREG = prevSREG; // interrupts on for stop bit while ((uint8_t)(TCNTX - t0) < width) { if (checkRxTime()) diff --git a/NeoSWSerial.h b/NeoSWSerial.h index 316db49..817f32e 100644 --- a/NeoSWSerial.h +++ b/NeoSWSerial.h @@ -13,8 +13,8 @@ // // Constructor: NeoSWSerial ss(RX_PIN, TX_PIN); // -// Any of the pins supported by SoftwareSerial may be used. Pins (0-19) -// on the Uno may be used. Other boards can use any of the pins +// Any of the pins supported by SoftwareSerial may be used. Pins (0-19) +// on the Uno may be used. Other boards can use any of the pins // allowed by digitalPinToPCMSK in pins_arduino.h // // This code uses a pin change interrupt on the selected RX pin. @@ -25,9 +25,9 @@ // Supported baud rates are 9600 (default), 19200 and 38400. // The baud rate is selectable at run time. // -// The size of the RX buffer may be changed by editing the -// accompanying .cpp file. For optimal performance of the interrupt -// service routines, the buffer size should be chosen to be a +// The size of the RX buffer may be changed by editing the +// accompanying .cpp file. For optimal performance of the interrupt +// service routines, the buffer size should be chosen to be a // power of 2 (i.e., 2, 4, 8, 16, 32, 64,...). // // Nov/Dec 2014 jboyton - Created @@ -38,7 +38,8 @@ // Nov 2015 SlashDev - Add support for other boards, // add end() and attach/detachInterrupt // Jun 2016 SlashDev - Add support for all character values -// +// Jan 2017 Matthew Marks - Added support for inverse logic + class NeoSWSerial : public Stream { @@ -46,10 +47,11 @@ class NeoSWSerial : public Stream NeoSWSerial & operator =( const NeoSWSerial & ); // Not allowed public: - NeoSWSerial(uint8_t receivePin, uint8_t transmitPin) + NeoSWSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false) { rxPin = receivePin; txPin = transmitPin; + inverse = inverse_logic; _isr = (isr_t) NULL; } @@ -70,6 +72,7 @@ class NeoSWSerial : public Stream private: uint8_t rxPin, txPin; + bool inverse; volatile uint8_t *rxPort; uint16_t _baudRate; @@ -84,5 +87,6 @@ class NeoSWSerial : public Stream public: // visible only so the ISRs can call it... static void rxISR( uint8_t port_input_register ); + static bool invert; // invert levels on line }; #endif