From 8903d19eef7f2da75239f5f569f9fd7fbe833ecb Mon Sep 17 00:00:00 2001 From: Kenneth Lausdahl Date: Mon, 29 Oct 2018 23:50:52 +0100 Subject: [PATCH] added parity patch from https://github.com/PaulStoffregen/AltSoftSerial/issues/5 --- AltSoftSerial.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++---- AltSoftSerial.h | 8 ++- 2 files changed, 154 insertions(+), 14 deletions(-) diff --git a/AltSoftSerial.cpp b/AltSoftSerial.cpp index 72ff290..279dd83 100644 --- a/AltSoftSerial.cpp +++ b/AltSoftSerial.cpp @@ -56,13 +56,17 @@ static volatile uint8_t tx_buffer_head; static volatile uint8_t tx_buffer_tail; #define TX_BUFFER_SIZE 68 static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; +static uint8_t tx_parity; +static uint8_t data_bits, stop_bits; +static uint8_t parity; // 0 for none, 1 for odd, 2 for even +static uint8_t total_bits, almost_total_bits; // these are sums calculated during .begin() to speed up the loop in ISR(CAPTURE_INTERRUPT) #ifndef INPUT_PULLUP #define INPUT_PULLUP INPUT #endif -void AltSoftSerial::init(uint32_t cycles_per_bit) +void AltSoftSerial::init(uint32_t cycles_per_bit, uint8_t config) { if (cycles_per_bit < 7085) { CONFIG_TIMER_NOPRESCALE(); @@ -85,6 +89,7 @@ void AltSoftSerial::init(uint32_t cycles_per_bit) tx_state = 0; tx_buffer_head = 0; tx_buffer_tail = 0; + setBitCounts(config); ENABLE_INT_INPUT_CAPTURE(); } @@ -119,6 +124,8 @@ void AltSoftSerial::writeByte(uint8_t b) tx_state = 1; tx_byte = b; tx_bit = 0; + if (parity) + tx_parity = parity_even_bit(b) == (parity==2); ENABLE_INT_COMPARE_A(); CONFIG_MATCH_CLEAR(); SET_COMPARE_A(GET_TIMER_COUNT() + 16); @@ -135,7 +142,7 @@ ISR(COMPARE_A_INTERRUPT) state = tx_state; byte = tx_byte; target = GET_COMPARE_A(); - while (state < 9) { + while (state < (data_bits+1)) { target += ticks_per_bit; bit = byte & 1; byte >>= 1; @@ -154,9 +161,21 @@ ISR(COMPARE_A_INTERRUPT) return; } } - if (state == 9) { - tx_state = 10; + if((!parity && state == (data_bits + 1)) || state == (data_bits + 2)) { + tx_state = data_bits + 3; CONFIG_MATCH_SET(); + SET_COMPARE_A(target + (stop_bits * ticks_per_bit)); + return; + } else if (state == (data_bits + 1)) { + tx_state = data_bits + 2; + if (tx_parity != tx_bit) { + if (tx_parity) { + CONFIG_MATCH_SET(); + } else { + CONFIG_MATCH_CLEAR(); + } + tx_bit = tx_parity; + } SET_COMPARE_A(target + ticks_per_bit); return; } @@ -172,6 +191,8 @@ ISR(COMPARE_A_INTERRUPT) tx_buffer_tail = tail; tx_byte = tx_buffer[tail]; tx_bit = 0; + if (parity) + tx_parity = parity_even_bit(tx_byte) == (parity==2); CONFIG_MATCH_CLEAR(); SET_COMPARE_A(target + ticks_per_bit); // TODO: how to detect timing_error? @@ -191,7 +212,7 @@ void AltSoftSerial::flushOutput(void) ISR(CAPTURE_INTERRUPT) { - uint8_t state, bit, head; + uint8_t state, bit, head, rx_parity; uint16_t capture, target; int16_t offset; @@ -217,21 +238,27 @@ ISR(CAPTURE_INTERRUPT) while (1) { offset = capture - target; if (offset < 0) break; + if (state >= 1 && state <= data_bits) // only store data bits rx_byte = (rx_byte >> 1) | rx_bit; target += ticks_per_bit; state++; - if (state >= 9) { + if (state >= total_bits) { // this is 9 for 8N1 or 10 for 8E1 DISABLE_INT_COMPARE_B(); - head = rx_buffer_head + 1; - if (head >= RX_BUFFER_SIZE) head = 0; - if (head != rx_buffer_tail) { - rx_buffer[head] = rx_byte; - rx_buffer_head = head; + if (!parity || (parity_even_bit(rx_byte) == (parity==2)) == rx_parity) { + head = rx_buffer_head + 1; + if (head >= RX_BUFFER_SIZE) head = 0; + if (head != rx_buffer_tail) { + rx_buffer[head] = rx_byte; + rx_buffer_head = head; + } } CONFIG_CAPTURE_FALLING_EDGE(); rx_bit = 0; rx_state = 0; return; + } else if (state < almost_total_bits) { + // in parity bit + rx_parity = rx_bit; } } rx_target = target; @@ -248,7 +275,7 @@ ISR(COMPARE_B_INTERRUPT) CONFIG_CAPTURE_FALLING_EDGE(); state = rx_state; bit = rx_bit ^ 0x80; - while (state < 9) { + while (state < (data_bits + 1)) { rx_byte = (rx_byte >> 1) | bit; state++; } @@ -303,6 +330,115 @@ void AltSoftSerial::flushInput(void) rx_buffer_head = rx_buffer_tail; } +void AltSoftSerial::setBitCounts(uint8_t config) { + parity = 0; + stop_bits = 1; + switch (config) { + case SERIAL_5N1: + data_bits = 5; + break; + case SERIAL_6N1: + data_bits = 6; + break; + case SERIAL_7N1: + data_bits = 7; + break; + case SERIAL_8N1: + data_bits = 8; + break; + case SERIAL_5N2: + data_bits = 5; + stop_bits = 2; + break; + case SERIAL_6N2: + data_bits = 6; + stop_bits = 2; + break; + case SERIAL_7N2: + data_bits = 7; + stop_bits = 2; + break; + case SERIAL_8N2: + data_bits = 8; + stop_bits = 2; + break; + case SERIAL_5O1: + parity = 1; + data_bits = 5; + break; + case SERIAL_6O1: + parity = 1; + data_bits = 6; + break; + case SERIAL_7O1: + parity = 1; + data_bits = 7; + break; + case SERIAL_8O1: + parity = 1; + data_bits = 8; + break; + case SERIAL_5O2: + parity = 1; + data_bits = 5; + stop_bits = 2; + break; + case SERIAL_6O2: + parity = 1; + data_bits = 6; + stop_bits = 2; + break; + case SERIAL_7O2: + parity = 1; + data_bits = 7; + stop_bits = 2; + break; + case SERIAL_8O2: + parity = 1; + data_bits = 8; + stop_bits = 2; + break; + case SERIAL_5E1: + parity = 2; + data_bits = 5; + break; + case SERIAL_6E1: + parity = 2; + data_bits = 6; + break; + case SERIAL_7E1: + parity = 2; + data_bits = 7; + break; + case SERIAL_8E1: + parity = 2; + data_bits = 8; + break; + case SERIAL_5E2: + parity = 2; + data_bits = 5; + stop_bits = 2; + break; + case SERIAL_6E2: + parity = 2; + data_bits = 6; + stop_bits = 2; + break; + case SERIAL_7E2: + parity = 2; + data_bits = 7; + stop_bits = 2; + break; + case SERIAL_8E2: + parity = 2; + data_bits = 8; + stop_bits = 2; + break; + } + + total_bits = data_bits + (parity ? 1 : 0) + stop_bits; + almost_total_bits = total_bits - stop_bits; +} #ifdef ALTSS_USE_FTM0 void ftm0_isr(void) diff --git a/AltSoftSerial.h b/AltSoftSerial.h index eccb8d8..099cb01 100644 --- a/AltSoftSerial.h +++ b/AltSoftSerial.h @@ -25,6 +25,7 @@ #define AltSoftSerial_h #include +#include #if ARDUINO >= 100 #include "Arduino.h" @@ -44,7 +45,9 @@ class AltSoftSerial : public Stream public: AltSoftSerial() { } ~AltSoftSerial() { end(); } - static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); } + //static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); } + static void begin(uint32_t baud, uint8_t config = SERIAL_8N1) { init((F_CPU + baud / 2) / baud, config); } + static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud, SERIAL_8N1); } static void end(); int peek(); int read(); @@ -68,8 +71,9 @@ class AltSoftSerial : public Stream static void enable_timer0(bool enable) { } static bool timing_error; private: - static void init(uint32_t cycles_per_bit); + static void init(uint32_t cycles_per_bit, uint8_t config); static void writeByte(uint8_t byte); + static void setBitCounts(uint8_t config); }; #endif