diff -ru AltSoftSerialOrig/AltSoftSerial.cpp AltSoftSerial/AltSoftSerial.cpp
--- AltSoftSerialOrig/AltSoftSerial.cpp 2013-09-14 17:50:20.679368900 +0200
+++ AltSoftSerial/AltSoftSerial.cpp 2013-09-14 17:46:02.268588700 +0200
@@ -52,13 +52,17 @@
static volatile uint8_t tx_buffer_tail;
#define TX_BUFFER_SIZE 68
static volatile uint8_t tx_buffer[RX_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();
@@ -82,6 +86,7 @@
tx_state = 0;
tx_buffer_head = 0;
tx_buffer_tail = 0;
+ setBitCounts(config);
ENABLE_INT_INPUT_CAPTURE();
}
@@ -116,6 +121,8 @@
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);
@@ -132,7 +139,7 @@
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;
@@ -151,9 +158,23 @@
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;
}
@@ -169,6 +190,8 @@
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?
@@ -189,7 +212,7 @@
#if 1
ISR(CAPTURE_INTERRUPT)
{
- uint8_t state, bit, head;
+ uint8_t state, bit, head, rx_parity;
uint16_t capture, target;
int16_t offset;
@@ -217,22 +240,28 @@
offset = capture - target;
if (offset < 0) break;
//PORTD |= 1;
- rx_byte = (rx_byte >> 1) | rx_bit;
+ if (state >= 1 && state <= data_bits) // only store data bits
+ rx_byte = (rx_byte >> 1) | rx_bit;
target += ticks_per_bit;
//PORTD &= ~1;
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;
@@ -251,7 +280,7 @@
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++;
}
@@ -389,5 +418,112 @@
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;
+}
diff -ru AltSoftSerialOrig/AltSoftSerial.h AltSoftSerial/AltSoftSerial.h
--- AltSoftSerialOrig/AltSoftSerial.h 2013-09-14 17:50:20.680369000 +0200
+++ AltSoftSerial/AltSoftSerial.h 2013-09-10 18:40:55.316404600 +0200
@@ -25,6 +25,7 @@
#define AltSoftSerial_h
#include <inttypes.h>
+#include <util/parity.h>
#if ARDUINO >= 100
#include "Arduino.h"
@@ -38,7 +39,7 @@
public:
AltSoftSerial() { }
~AltSoftSerial() { end(); }
- static void begin(uint32_t baud) { init((F_CPU + baud / 2) / baud); }
+ static void begin(uint32_t baud, uint8_t config = SERIAL_8N1) { init((F_CPU + baud / 2) / baud, config); }
static void end();
int peek();
int read();
@@ -62,8 +63,9 @@
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