123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
-
-
-
-
-
-
-
- #define _DEBUG 0
- #define _DEBUG_PIN1 11
- #define _DEBUG_PIN2 13
-
-
-
- #include <avr/interrupt.h>
- #include <avr/pgmspace.h>
- #include <Arduino.h>
- #include "SoftwareSerial8e1.h"
- #include <util/delay_basic.h>
-
-
-
-
- SoftwareSerial8e1 *SoftwareSerial8e1::active_object = 0;
- uint8_t SoftwareSerial8e1::_receive_buffer[_SS_MAX_RX_BUFF];
- volatile uint8_t SoftwareSerial8e1::_receive_buffer_tail = 0;
- volatile uint8_t SoftwareSerial8e1::_receive_buffer_head = 0;
-
-
-
-
-
-
- #if _DEBUG
- inline void DebugPulse(uint8_t pin, uint8_t count)
- {
- volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin));
-
- uint8_t val = *pport;
- while (count--)
- {
- *pport = val | digitalPinToBitMask(pin);
- *pport = val;
- }
- }
- #else
- inline void DebugPulse(uint8_t, uint8_t) {}
- #endif
-
-
-
-
-
-
- inline void SoftwareSerial8e1::tunedDelay(uint16_t delay) {
- _delay_loop_2(delay);
- }
-
-
-
- bool SoftwareSerial8e1::listen()
- {
- if (!_rx_delay_stopbit)
- return false;
-
- if (active_object != this)
- {
- if (active_object)
- active_object->stopListening();
-
- _buffer_overflow = false;
- _receive_buffer_head = _receive_buffer_tail = 0;
- active_object = this;
-
- setRxIntMsk(true);
- return true;
- }
-
- return false;
- }
-
-
- bool SoftwareSerial8e1::stopListening()
- {
- if (active_object == this)
- {
- setRxIntMsk(false);
- active_object = NULL;
- return true;
- }
- return false;
- }
-
-
-
-
- void SoftwareSerial8e1::recv()
- {
-
- #if GCC_VERSION < 40302
-
-
-
- asm volatile(
- "push r18 \n\t"
- "push r19 \n\t"
- "push r20 \n\t"
- "push r21 \n\t"
- "push r22 \n\t"
- "push r23 \n\t"
- "push r26 \n\t"
- "push r27 \n\t"
- ::);
- #endif
-
- uint8_t d = 0;
-
-
-
- if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
- {
-
-
-
- setRxIntMsk(false);
-
-
- tunedDelay(_rx_delay_centering);
- DebugPulse(_DEBUG_PIN2, 1);
-
-
- for (uint8_t i=8; i > 0; --i)
- {
- tunedDelay(_rx_delay_intrabit);
- d >>= 1;
- DebugPulse(_DEBUG_PIN2, 1);
- if (rx_pin_read())
- d |= 0x80;
- }
-
- if (_inverse_logic)
- d = ~d;
-
-
- uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
- if (next != _receive_buffer_head)
- {
-
- _receive_buffer[_receive_buffer_tail] = d;
- _receive_buffer_tail = next;
- }
- else
- {
- DebugPulse(_DEBUG_PIN1, 1);
- _buffer_overflow = true;
- }
-
-
- tunedDelay(_rx_delay_stopbit);
- DebugPulse(_DEBUG_PIN1, 1);
-
-
- tunedDelay(_rx_delay_stopbit);
- DebugPulse(_DEBUG_PIN1, 1);
-
-
- setRxIntMsk(true);
-
- }
-
- #if GCC_VERSION < 40302
-
-
- asm volatile(
- "pop r27 \n\t"
- "pop r26 \n\t"
- "pop r23 \n\t"
- "pop r22 \n\t"
- "pop r21 \n\t"
- "pop r20 \n\t"
- "pop r19 \n\t"
- "pop r18 \n\t"
- ::);
- #endif
- }
-
- uint8_t SoftwareSerial8e1::rx_pin_read()
- {
- return *_receivePortRegister & _receiveBitMask;
- }
-
-
-
-
-
-
- inline void SoftwareSerial8e1::handle_interrupt()
- {
- if (active_object)
- {
- active_object->recv();
- }
- }
-
- #if defined(PCINT0_vect)
- ISR(PCINT0_vect)
- {
- SoftwareSerial8e1::handle_interrupt();
- }
- #endif
-
- #if defined(PCINT1_vect)
- ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect));
- #endif
-
- #if defined(PCINT2_vect)
- ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect));
- #endif
-
- #if defined(PCINT3_vect)
- ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect));
- #endif
-
-
-
-
- SoftwareSerial8e1::SoftwareSerial8e1(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic ) :
- _rx_delay_centering(0),
- _rx_delay_intrabit(0),
- _rx_delay_stopbit(0),
- _tx_delay(0),
- _buffer_overflow(false),
- _inverse_logic(inverse_logic)
- {
- setTX(transmitPin);
- setRX(receivePin);
- }
-
-
-
-
- SoftwareSerial8e1::~SoftwareSerial8e1()
- {
- end();
- }
-
- void SoftwareSerial8e1::setTX(uint8_t tx)
- {
-
-
-
-
- digitalWrite(tx, _inverse_logic ? LOW : HIGH);
- pinMode(tx, OUTPUT);
- _transmitBitMask = digitalPinToBitMask(tx);
- uint8_t port = digitalPinToPort(tx);
- _transmitPortRegister = portOutputRegister(port);
- }
-
- void SoftwareSerial8e1::setRX(uint8_t rx)
- {
- pinMode(rx, INPUT);
- if (!_inverse_logic)
- digitalWrite(rx, HIGH);
- _receivePin = rx;
- _receiveBitMask = digitalPinToBitMask(rx);
- uint8_t port = digitalPinToPort(rx);
- _receivePortRegister = portInputRegister(port);
- }
-
- uint16_t SoftwareSerial8e1::subtract_cap(uint16_t num, uint16_t sub) {
- if (num > sub)
- return num - sub;
- else
- return 1;
- }
-
-
-
-
-
- void SoftwareSerial8e1::begin(long speed)
- {
- _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0;
-
-
- uint16_t bit_delay = (F_CPU / speed) / 4;
-
-
-
-
-
-
- _tx_delay = subtract_cap(bit_delay, 15 / 4);
-
-
- if (digitalPinToPCICR(_receivePin)) {
- #if GCC_VERSION > 40800
-
-
-
-
-
-
-
-
-
-
-
-
-
- _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4);
-
-
- _rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4);
-
-
-
-
-
-
-
-
- _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4);
- #else
-
-
-
- _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 97 + 29 - 11) / 4);
- _rx_delay_intrabit = subtract_cap(bit_delay, 11 / 4);
- _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (44 + 17) / 4);
- #endif
-
-
-
-
-
- *digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin));
-
-
- _pcint_maskreg = digitalPinToPCMSK(_receivePin);
- _pcint_maskvalue = _BV(digitalPinToPCMSKbit(_receivePin));
-
- tunedDelay(_tx_delay);
- }
-
- #if _DEBUG
- pinMode(_DEBUG_PIN1, OUTPUT);
- pinMode(_DEBUG_PIN2, OUTPUT);
- #endif
-
- listen();
- }
-
- void SoftwareSerial8e1::setRxIntMsk(bool enable)
- {
- if (enable)
- *_pcint_maskreg |= _pcint_maskvalue;
- else
- *_pcint_maskreg &= ~_pcint_maskvalue;
- }
-
- void SoftwareSerial8e1::end()
- {
- stopListening();
- }
-
-
-
- int SoftwareSerial8e1::read()
- {
- if (!isListening())
- return -1;
-
-
- if (_receive_buffer_head == _receive_buffer_tail)
- return -1;
-
-
- uint8_t d = _receive_buffer[_receive_buffer_head];
- _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
- return d;
- }
-
- int SoftwareSerial8e1::available()
- {
- if (!isListening())
- return 0;
-
- return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF;
- }
-
- size_t SoftwareSerial8e1::write(uint8_t b)
- {
- if (_tx_delay == 0) {
- setWriteError();
- return 0;
- }
-
-
-
-
-
-
- volatile uint8_t *reg = _transmitPortRegister;
- uint8_t reg_mask = _transmitBitMask;
- uint8_t inv_mask = ~_transmitBitMask;
- uint8_t oldSREG = SREG;
- bool inv = _inverse_logic;
- uint16_t delay = _tx_delay;
- uint8_t p = 0;
- for (uint8_t t = 0x80; t; t >>= 1)
- if (b & t) p++;
-
- if (inv)
- b = ~b;
-
- cli();
-
-
- if (inv)
- *reg |= reg_mask;
- else
- *reg &= inv_mask;
-
- tunedDelay(delay);
-
-
- for (uint8_t i = 8; i > 0; --i)
- {
- if (b & 1)
- *reg |= reg_mask;
- else
- *reg &= inv_mask;
-
- tunedDelay(delay);
- b >>= 1;
- }
-
- if (p & 0x01)
- *reg |= reg_mask;
- else
- *reg &= inv_mask;
- tunedDelay(_tx_delay);
-
-
- if (inv)
- *reg &= inv_mask;
- else
- *reg |= reg_mask;
-
- SREG = oldSREG;
- tunedDelay(_tx_delay);
-
-
-
-
- return 1;
- }
-
- void SoftwareSerial8e1::flush()
- {
-
- }
-
- int SoftwareSerial8e1::peek()
- {
- if (!isListening())
- return -1;
-
-
- if (_receive_buffer_head == _receive_buffer_tail)
- return -1;
-
-
- return _receive_buffer[_receive_buffer_head];
- }
|