Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RS485 Data Dropping #52

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
73 changes: 73 additions & 0 deletions examples/RS485Deferred/RS485Deferred.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
The purpose of this example is to demonstrate how the Arudino Mega will drop incoming RS485 data if
processing is done in the ISR.

#define DCSBIOS_DEFER_RS485_PROCESSING is enabled in this sketch, comment
it out to see the problem. You don't need all LED's to be physicallyconnected, just any one that is
supposed to be blinking.

Even though the sketch uses efficient direct register access, this sketch will still drop data and
not blink the LEDs in sync with the sim unless DCSBIOS_DEFER_RS485_PROCESSING is defined.
*/

#define DCSBIOS_RS485_SLAVE 23 // The following #define tells DCS-BIOS that this is a RS-485 slave device. It also sets the address of this slave device. The slave address should be between 1 and 126 and must be unique among all devices on the same bus.
#define TXENABLE_PIN 2 // The Arduino pin that is connected to the /RE and DE pins on the RS-485 transceiver.
#define DCSBIOS_DEFER_RS485_PROCESSING // Defer RS485 processing from the ISR to loop().
#include "DcsBios.h"

void onClA1Change(unsigned int newValue) { if (newValue == 1) { PORTE |= (1 << 5); } else { PORTE &= ~(1 << 5); } } DcsBios::IntegerBuffer clA1Buffer(0x10d4, 0x0001, 0, onClA1Change);
void onClA2Change(unsigned int newValue) { if (newValue == 1) { PORTG |= (1 << 5); } else { PORTG &= ~(1 << 5); } } DcsBios::IntegerBuffer clA2Buffer(0x10d4, 0x0002, 1, onClA2Change);
void onClA3Change(unsigned int newValue) { if (newValue == 1) { PORTE |= (1 << 3); } else { PORTE &= ~(1 << 3); } } DcsBios::IntegerBuffer clA3Buffer(0x10d4, 0x0004, 2, onClA3Change);
void onClA4Change(unsigned int newValue) { if (newValue == 1) { PORTH |= (1 << 3); } else { PORTH &= ~(1 << 3); } } DcsBios::IntegerBuffer clA4Buffer(0x10d4, 0x0008, 3, onClA4Change);
void onClB1Change(unsigned int newValue) { if (newValue == 1) { PORTH |= (1 << 4); } else { PORTH &= ~(1 << 4); } } DcsBios::IntegerBuffer clB1Buffer(0x10d4, 0x0010, 4, onClB1Change);
void onClB2Change(unsigned int newValue) { if (newValue == 1) { PORTH |= (1 << 5); } else { PORTH &= ~(1 << 5); } } DcsBios::IntegerBuffer clB2Buffer(0x10d4, 0x0020, 5, onClB2Change);
void onClB3Change(unsigned int newValue) { if (newValue == 1) { PORTH |= (1 << 6); } else { PORTH &= ~(1 << 6); } } DcsBios::IntegerBuffer clB3Buffer(0x10d4, 0x0040, 6, onClB3Change);
void onClB4Change(unsigned int newValue) { if (newValue == 1) { PORTB |= (1 << 4); } else { PORTB &= ~(1 << 4); } } DcsBios::IntegerBuffer clB4Buffer(0x10d4, 0x0080, 7, onClB4Change);
void onClC1Change(unsigned int newValue) { if (newValue == 1) { PORTB |= (1 << 5); } else { PORTB &= ~(1 << 5); } } DcsBios::IntegerBuffer clC1Buffer(0x10d4, 0x0100, 8, onClC1Change);
void onClC2Change(unsigned int newValue) { if (newValue == 1) { PORTB |= (1 << 6); } else { PORTB &= ~(1 << 6); } } DcsBios::IntegerBuffer clC2Buffer(0x10d4, 0x0200, 9, onClC2Change);
void onClC3Change(unsigned int newValue) { if (newValue == 1) { PORTJ |= (1 << 1); } else { PORTJ &= ~(1 << 1); } } DcsBios::IntegerBuffer clC3Buffer(0x10d4, 0x0400, 10, onClC3Change);
void onClC4Change(unsigned int newValue) { if (newValue == 1) { PORTJ |= (1 << 0); } else { PORTJ &= ~(1 << 0); } } DcsBios::IntegerBuffer clC4Buffer(0x10d4, 0x0800, 11, onClC4Change);
void onClD1Change(unsigned int newValue) { if (newValue == 1) { PORTH |= (1 << 1); } else { PORTH &= ~(1 << 1); } } DcsBios::IntegerBuffer clD1Buffer(0x10d4, 0x1000, 12, onClD1Change);
void onClD2Change(unsigned int newValue) { if (newValue == 1) { PORTH |= (1 << 0); } else { PORTH &= ~(1 << 0); } } DcsBios::IntegerBuffer clD2Buffer(0x10d4, 0x2000, 13, onClD2Change);
void onClD3Change(unsigned int newValue) { if (newValue == 1) { PORTD |= (1 << 3); } else { PORTD &= ~(1 << 3); } } DcsBios::IntegerBuffer clD3Buffer(0x10d4, 0x4000, 14, onClD3Change);
void onClD4Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 0); } else { PORTF &= ~(1 << 0); } } DcsBios::IntegerBuffer clD4Buffer(0x10d4, 0x8000, 15, onClD4Change);
void onClE1Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 1); } else { PORTF &= ~(1 << 1); } } DcsBios::IntegerBuffer clE1Buffer(0x10d6, 0x0001, 0, onClE1Change);
void onClE2Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 2); } else { PORTF &= ~(1 << 2); } } DcsBios::IntegerBuffer clE2Buffer(0x10d6, 0x0002, 1, onClE2Change);
void onClE3Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 3); } else { PORTF &= ~(1 << 3); } } DcsBios::IntegerBuffer clE3Buffer(0x10d6, 0x0004, 2, onClE3Change);
void onClE4Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 4); } else { PORTF &= ~(1 << 4); } } DcsBios::IntegerBuffer clE4Buffer(0x10d6, 0x0008, 3, onClE4Change);
void onClF1Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 5); } else { PORTF &= ~(1 << 5); } } DcsBios::IntegerBuffer clF1Buffer(0x10d6, 0x0010, 4, onClF1Change);
void onClF2Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 6); } else { PORTF &= ~(1 << 6); } } DcsBios::IntegerBuffer clF2Buffer(0x10d6, 0x0020, 5, onClF2Change);
void onClF3Change(unsigned int newValue) { if (newValue == 1) { PORTF |= (1 << 7); } else { PORTF &= ~(1 << 7); } } DcsBios::IntegerBuffer clF3Buffer(0x10d6, 0x0040, 6, onClF3Change);
void onClF4Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 0); } else { PORTK &= ~(1 << 0); } } DcsBios::IntegerBuffer clF4Buffer(0x10d6, 0x0080, 7, onClF4Change);
void onClG1Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 1); } else { PORTK &= ~(1 << 1); } } DcsBios::IntegerBuffer clG1Buffer(0x10d6, 0x0100, 8, onClG1Change);
void onClG2Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 2); } else { PORTK &= ~(1 << 2); } } DcsBios::IntegerBuffer clG2Buffer(0x10d6, 0x0200, 9, onClG2Change);
void onClG3Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 3); } else { PORTK &= ~(1 << 3); } } DcsBios::IntegerBuffer clG3Buffer(0x10d6, 0x0400, 10, onClG3Change);
void onClG4Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 4); } else { PORTK &= ~(1 << 4); } } DcsBios::IntegerBuffer clG4Buffer(0x10d6, 0x0800, 11, onClG4Change);
void onClH1Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 5); } else { PORTK &= ~(1 << 5); } } DcsBios::IntegerBuffer clH1Buffer(0x10d6, 0x1000, 12, onClH1Change);
void onClH2Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 6); } else { PORTK &= ~(1 << 6); } } DcsBios::IntegerBuffer clH2Buffer(0x10d6, 0x2000, 13, onClH2Change);
void onClH3Change(unsigned int newValue) { if (newValue == 1) { PORTK |= (1 << 7); } else { PORTK &= ~(1 << 7); } } DcsBios::IntegerBuffer clH3Buffer(0x10d6, 0x4000, 14, onClH3Change);
void onClH4Change(unsigned int newValue) { if (newValue == 1) { PORTD |= (1 << 2); } else { PORTD &= ~(1 << 2); } } DcsBios::IntegerBuffer clH4Buffer(0x10d6, 0x8000, 15, onClH4Change);
void onClI1Change(unsigned int newValue) { if (newValue == 1) { PORTD |= (1 << 1); } else { PORTD &= ~(1 << 1); } } DcsBios::IntegerBuffer clI1Buffer(0x10d8, 0x0001, 0, onClI1Change);
void onClI2Change(unsigned int newValue) { if (newValue == 1) { PORTD |= (1 << 0); } else { PORTD &= ~(1 << 0); } } DcsBios::IntegerBuffer clI2Buffer(0x10d8, 0x0002, 1, onClI2Change);
void onClI3Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 0); } else { PORTA &= ~(1 << 0); } } DcsBios::IntegerBuffer clI3Buffer(0x10d8, 0x0004, 2, onClI3Change);
void onClI4Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 1); } else { PORTA &= ~(1 << 1); } } DcsBios::IntegerBuffer clI4Buffer(0x10d8, 0x0008, 3, onClI4Change);
void onClJ1Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 2); } else { PORTA &= ~(1 << 2); } } DcsBios::IntegerBuffer clJ1Buffer(0x10d8, 0x0010, 4, onClJ1Change);
void onClJ2Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 3); } else { PORTA &= ~(1 << 3); } } DcsBios::IntegerBuffer clJ2Buffer(0x10d8, 0x0020, 5, onClJ2Change);
void onClJ3Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 4); } else { PORTA &= ~(1 << 4); } } DcsBios::IntegerBuffer clJ3Buffer(0x10d8, 0x0040, 6, onClJ3Change);
void onClJ4Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 5); } else { PORTA &= ~(1 << 5); } } DcsBios::IntegerBuffer clJ4Buffer(0x10d8, 0x0080, 7, onClJ4Change);
void onClK1Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 6); } else { PORTA &= ~(1 << 6); } } DcsBios::IntegerBuffer clK1Buffer(0x10d8, 0x0100, 8, onClK1Change);
void onClK2Change(unsigned int newValue) { if (newValue == 1) { PORTA |= (1 << 7); } else { PORTA &= ~(1 << 7); } } DcsBios::IntegerBuffer clK2Buffer(0x10d8, 0x0200, 9, onClK2Change);
void onClK3Change(unsigned int newValue) { if (newValue == 1) { PORTC |= (1 << 7); } else { PORTC &= ~(1 << 7); } } DcsBios::IntegerBuffer clK3Buffer(0x10d8, 0x0400, 10, onClK3Change);
void onClK4Change(unsigned int newValue) { if (newValue == 1) { PORTC |= (1 << 6); } else { PORTC &= ~(1 << 6); } } DcsBios::IntegerBuffer clK4Buffer(0x10d8, 0x0800, 11, onClK4Change);
void onClL1Change(unsigned int newValue) { if (newValue == 1) { PORTC |= (1 << 5); } else { PORTC &= ~(1 << 5); } } DcsBios::IntegerBuffer clL1Buffer(0x10d8, 0x1000, 12, onClL1Change);
void onClL2Change(unsigned int newValue) { if (newValue == 1) { PORTC |= (1 << 4); } else { PORTC &= ~(1 << 4); } } DcsBios::IntegerBuffer clL2Buffer(0x10d8, 0x2000, 13, onClL2Change);
void onClL3Change(unsigned int newValue) { if (newValue == 1) { PORTC |= (1 << 3); } else { PORTC &= ~(1 << 3); } } DcsBios::IntegerBuffer clL3Buffer(0x10d8, 0x4000, 14, onClL3Change);
void onClL4Change(unsigned int newValue) { if (newValue == 1) { PORTC |= (1 << 2); } else { PORTC &= ~(1 << 2); } } DcsBios::IntegerBuffer clL4Buffer(0x10d8, 0x8000, 15, onClL4Change);

void setup() {
DcsBios::setup();
}

void loop() {
DcsBios::loop();
}
1 change: 1 addition & 0 deletions src/DcsBios.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "internal/ExportStreamListener.h"
#include "internal/PollingInput.h"
#include "internal/Protocol.h"
#include "internal/Protocol.cpp.inc" // Needs to be a .cpp.inc to allow DCSBIOS_INCOMING_DATA_BUFFER_SIZE
#include "internal/Addresses.h"


Expand Down
15 changes: 14 additions & 1 deletion src/internal/DcsBiosNgRS485Slave.cpp.inc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ namespace DcsBios {
case RX_WAIT_DATA:
rxtx_len--;
if (rx_datatype == RXDATA_DCSBIOS_EXPORT) {
parser.processCharISR(c);
if (rxtx_len <= parser.incomingDataBuffer.availableForWrite()) {
parser.processCharISR(c);
} else {
last_rx_time = micros();
state = SYNC;
}
}
if (rxtx_len == 0) {
state = RX_WAIT_CHECKSUM;
Expand Down Expand Up @@ -240,6 +245,14 @@ namespace DcsBios {
void loop() {
PollingInput::pollInputs();
ExportStreamListener::loopAll();

// Process incoming data outside of ISR
#ifdef DCSBIOS_DEFER_RS485_PROCESSING
if (!parser.incomingDataBuffer.isEmpty()) {
unsigned char nextByte = parser.incomingDataBuffer.get();
parser.processChar(nextByte);
}
#endif
}

void resetAllStates() {
Expand Down
7 changes: 4 additions & 3 deletions src/internal/Protocol.cpp → src/internal/Protocol.cpp.inc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ namespace DcsBios {
*/
void ProtocolParser::processCharISR(unsigned char c) {
incomingDataBuffer.put(c);

// For some reason RS485 slaves cannot process data here, while it works over USB. Perhaps due to the additonal overhead of the RS485 state machine? If DCSBIOS_RS485_SLAVE is defined, the processing is deferred to loop().
#ifndef DCSBIOS_DEFER_RS485_PROCESSING
if (processingData) return;

processingData = true;
Expand All @@ -31,10 +34,8 @@ namespace DcsBios {
unsigned char nextByte = incomingDataBuffer.get();
interrupts();
processChar(nextByte);
#ifdef DCSBIOS_RS485_SLAVE
noInterrupts();
#endif
}
#endif
}

void ProtocolParser::processChar(unsigned char c) {
Expand Down
7 changes: 6 additions & 1 deletion src/internal/Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#define DCSBIOS_STATE_DATA_LOW 5
#define DCSBIOS_STATE_DATA_HIGH 6

#ifndef DCSBIOS_INCOMING_DATA_BUFFER_SIZE
#define DCSBIOS_INCOMING_DATA_BUFFER_SIZE 64
#endif

#include "ExportStreamListener.h"
#include "RingBuffer.h"

Expand All @@ -23,9 +27,10 @@ namespace DcsBios {
volatile unsigned char sync_byte_count;

ExportStreamListener* startESL;
RingBuffer<64> incomingDataBuffer;
volatile bool processingData;
public:
RingBuffer<DCSBIOS_INCOMING_DATA_BUFFER_SIZE> incomingDataBuffer;

void processChar(unsigned char c);
void processCharISR(unsigned char c);
ProtocolParser();
Expand Down
1 change: 1 addition & 0 deletions src/internal/RingBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace DcsBios {
__attribute__((always_inline)) uint8_t get() { uint8_t ret = buffer[readpos]; readpos = ++readpos % SIZE; return ret; }
__attribute__((always_inline)) uint8_t getLength() { return (uint8_t)(writepos - readpos) % SIZE; }
__attribute__((always_inline)) void clear() { readpos = 0; writepos = 0; }
__attribute__((always_inline)) uint8_t availableForWrite() { return SIZE - getLength() - 1; }
};
}

Expand Down