From e23ab6c98e6fcd073369c8d64c412da465da11aa Mon Sep 17 00:00:00 2001 From: Maciej Swic Date: Mon, 9 Oct 2023 14:50:13 +0300 Subject: [PATCH 01/10] RS485 Fix WIP --- src/internal/DcsBiosNgRS485Slave.cpp.inc | 12 +++++++++++- src/internal/Protocol.cpp | 8 ++++++-- src/internal/Protocol.h | 3 ++- src/internal/RingBuffer.h | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/internal/DcsBiosNgRS485Slave.cpp.inc b/src/internal/DcsBiosNgRS485Slave.cpp.inc index 97a5b2e..8cef182 100644 --- a/src/internal/DcsBiosNgRS485Slave.cpp.inc +++ b/src/internal/DcsBiosNgRS485Slave.cpp.inc @@ -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.availableBufferSpace()) { + // Toggle D13 LED to indicate buffer overflow + PORTB ^= (1<<7); + } else { + parser.processCharISR(c); + } } if (rxtx_len == 0) { state = RX_WAIT_CHECKSUM; @@ -240,6 +245,11 @@ namespace DcsBios { void loop() { PollingInput::pollInputs(); ExportStreamListener::loopAll(); + + if (!parser.incomingDataBuffer.isEmpty()) { + unsigned char nextByte = parser.incomingDataBuffer.get(); + parser.processChar(nextByte); + } } } #endif diff --git a/src/internal/Protocol.cpp b/src/internal/Protocol.cpp index 91fd86c..3be9b88 100644 --- a/src/internal/Protocol.cpp +++ b/src/internal/Protocol.cpp @@ -13,6 +13,10 @@ namespace DcsBios { sync_byte_count = 0; } + uint8_t ProtocolParser::availableBufferSpace() { + return incomingDataBuffer.availableForWrite(); + } + /* to be called from ISR stores the character in a buffer, re-enables interrupts and processes the complete @@ -20,7 +24,7 @@ namespace DcsBios { */ void ProtocolParser::processCharISR(unsigned char c) { incomingDataBuffer.put(c); - if (processingData) return; + /*if (processingData) return; processingData = true; while (1) { @@ -34,7 +38,7 @@ namespace DcsBios { #ifdef DCSBIOS_RS485_SLAVE noInterrupts(); #endif - } + }*/ } void ProtocolParser::processChar(unsigned char c) { diff --git a/src/internal/Protocol.h b/src/internal/Protocol.h index f5ebc7e..fae7372 100644 --- a/src/internal/Protocol.h +++ b/src/internal/Protocol.h @@ -23,11 +23,12 @@ namespace DcsBios { volatile unsigned char sync_byte_count; ExportStreamListener* startESL; - RingBuffer<64> incomingDataBuffer; volatile bool processingData; public: + RingBuffer<64> incomingDataBuffer; void processChar(unsigned char c); void processCharISR(unsigned char c); + uint8_t availableBufferSpace(); ProtocolParser(); }; } diff --git a/src/internal/RingBuffer.h b/src/internal/RingBuffer.h index 2058eee..816cfac 100644 --- a/src/internal/RingBuffer.h +++ b/src/internal/RingBuffer.h @@ -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; } }; } From 2a52128c08b51f1bdefd2f0e67006d9cc38c6bbc Mon Sep 17 00:00:00 2001 From: Maciej Swic Date: Mon, 9 Oct 2023 15:00:59 +0300 Subject: [PATCH 02/10] Refactoring --- src/DcsBios.h | 1 + src/internal/DcsBiosNgRS485Slave.cpp.inc | 6 ++---- src/internal/{Protocol.cpp => Protocol.cpp.inc} | 11 ++++++----- 3 files changed, 9 insertions(+), 9 deletions(-) rename src/internal/{Protocol.cpp => Protocol.cpp.inc} (92%) diff --git a/src/DcsBios.h b/src/DcsBios.h index da48e5f..487a71a 100644 --- a/src/DcsBios.h +++ b/src/DcsBios.h @@ -14,6 +14,7 @@ #include "internal/ExportStreamListener.h" #include "internal/PollingInput.h" #include "internal/Protocol.h" +#include "internal/Protocol.cpp.inc" #include "internal/Addresses.h" diff --git a/src/internal/DcsBiosNgRS485Slave.cpp.inc b/src/internal/DcsBiosNgRS485Slave.cpp.inc index 8cef182..faa61b5 100644 --- a/src/internal/DcsBiosNgRS485Slave.cpp.inc +++ b/src/internal/DcsBiosNgRS485Slave.cpp.inc @@ -107,10 +107,7 @@ namespace DcsBios { case RX_WAIT_DATA: rxtx_len--; if (rx_datatype == RXDATA_DCSBIOS_EXPORT) { - if (rxtx_len > parser.availableBufferSpace()) { - // Toggle D13 LED to indicate buffer overflow - PORTB ^= (1<<7); - } else { + if (rxtx_len <= parser.availableBufferSpace()) { parser.processCharISR(c); } } @@ -246,6 +243,7 @@ namespace DcsBios { PollingInput::pollInputs(); ExportStreamListener::loopAll(); + // Process incoming data outside of ISR if (!parser.incomingDataBuffer.isEmpty()) { unsigned char nextByte = parser.incomingDataBuffer.get(); parser.processChar(nextByte); diff --git a/src/internal/Protocol.cpp b/src/internal/Protocol.cpp.inc similarity index 92% rename from src/internal/Protocol.cpp rename to src/internal/Protocol.cpp.inc index 3be9b88..5847389 100644 --- a/src/internal/Protocol.cpp +++ b/src/internal/Protocol.cpp.inc @@ -24,7 +24,10 @@ namespace DcsBios { */ void ProtocolParser::processCharISR(unsigned char c) { incomingDataBuffer.put(c); - /*if (processingData) return; + + // For some reason RS485 slaves cannot process data here, while it works over USB. If DCSBIOS_RS485_SLAVE is defined, the processing is deferred to loop(). + #ifndef DCSBIOS_RS485_SLAVE + if (processingData) return; processingData = true; while (1) { @@ -35,10 +38,8 @@ namespace DcsBios { unsigned char nextByte = incomingDataBuffer.get(); interrupts(); processChar(nextByte); -#ifdef DCSBIOS_RS485_SLAVE - noInterrupts(); -#endif - }*/ + } + #endif } void ProtocolParser::processChar(unsigned char c) { From 92007bd7072a1cc6f6b6da7e892b958e75ec46b4 Mon Sep 17 00:00:00 2001 From: Maciej Swic Date: Tue, 10 Oct 2023 00:01:11 +0300 Subject: [PATCH 03/10] Make new behaviour togglable with two #defines #define DCSBIOS_INCOMING_DATA_BUFFER_SIZE 512 #define DCSBIOS_ALTERNATIVE_RS485_PROCESSING --- src/internal/DcsBiosNgRS485Slave.cpp.inc | 2 ++ src/internal/Protocol.cpp.inc | 2 +- src/internal/Protocol.h | 6 +++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/internal/DcsBiosNgRS485Slave.cpp.inc b/src/internal/DcsBiosNgRS485Slave.cpp.inc index faa61b5..fc89e69 100644 --- a/src/internal/DcsBiosNgRS485Slave.cpp.inc +++ b/src/internal/DcsBiosNgRS485Slave.cpp.inc @@ -243,11 +243,13 @@ namespace DcsBios { PollingInput::pollInputs(); ExportStreamListener::loopAll(); + #ifdef DCSBIOS_ALTERNATIVE_RS485_PROCESSING // Process incoming data outside of ISR if (!parser.incomingDataBuffer.isEmpty()) { unsigned char nextByte = parser.incomingDataBuffer.get(); parser.processChar(nextByte); } + #endif } } #endif diff --git a/src/internal/Protocol.cpp.inc b/src/internal/Protocol.cpp.inc index 5847389..4d9b168 100644 --- a/src/internal/Protocol.cpp.inc +++ b/src/internal/Protocol.cpp.inc @@ -26,7 +26,7 @@ namespace DcsBios { incomingDataBuffer.put(c); // For some reason RS485 slaves cannot process data here, while it works over USB. If DCSBIOS_RS485_SLAVE is defined, the processing is deferred to loop(). - #ifndef DCSBIOS_RS485_SLAVE + #ifndef DCSBIOS_ALTERNATIVE_RS485_PROCESSING if (processingData) return; processingData = true; diff --git a/src/internal/Protocol.h b/src/internal/Protocol.h index fae7372..198d180 100644 --- a/src/internal/Protocol.h +++ b/src/internal/Protocol.h @@ -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" @@ -25,7 +29,7 @@ namespace DcsBios { ExportStreamListener* startESL; volatile bool processingData; public: - RingBuffer<64> incomingDataBuffer; + RingBuffer incomingDataBuffer; void processChar(unsigned char c); void processCharISR(unsigned char c); uint8_t availableBufferSpace(); From 68f4c83f4019751cd28407fd90edced81dd68935 Mon Sep 17 00:00:00 2001 From: Maciej Swic Date: Tue, 10 Oct 2023 00:30:55 +0300 Subject: [PATCH 04/10] Added a comment --- src/DcsBios.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DcsBios.h b/src/DcsBios.h index 487a71a..d713e3b 100644 --- a/src/DcsBios.h +++ b/src/DcsBios.h @@ -14,7 +14,7 @@ #include "internal/ExportStreamListener.h" #include "internal/PollingInput.h" #include "internal/Protocol.h" -#include "internal/Protocol.cpp.inc" +#include "internal/Protocol.cpp.inc" // Needs to be a .cpp.inc to allow DCSBIOS_INCOMING_DATA_BUFFER_SIZE #include "internal/Addresses.h" From 7e4639dd4ad0aef375b752ddefbcc26d0e906bdb Mon Sep 17 00:00:00 2001 From: Maciej Swic Date: Tue, 10 Oct 2023 00:32:09 +0300 Subject: [PATCH 05/10] Put back some code i removed by accident --- src/internal/Protocol.cpp.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/internal/Protocol.cpp.inc b/src/internal/Protocol.cpp.inc index 4d9b168..12248fa 100644 --- a/src/internal/Protocol.cpp.inc +++ b/src/internal/Protocol.cpp.inc @@ -38,6 +38,9 @@ namespace DcsBios { unsigned char nextByte = incomingDataBuffer.get(); interrupts(); processChar(nextByte); +#ifdef DCSBIOS_RS485_SLAVE + noInterrupts(); +#endif } #endif } From bb9f9ea7bd37eb8f73cfcb3edff047372f8afe11 Mon Sep 17 00:00:00 2001 From: Maciej Swic <442007+maciekish@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:22:55 +0300 Subject: [PATCH 06/10] Cleanup and comment --- src/internal/DcsBiosNgRS485Slave.cpp.inc | 2 -- src/internal/Protocol.cpp.inc | 7 ++----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/internal/DcsBiosNgRS485Slave.cpp.inc b/src/internal/DcsBiosNgRS485Slave.cpp.inc index fc89e69..faa61b5 100644 --- a/src/internal/DcsBiosNgRS485Slave.cpp.inc +++ b/src/internal/DcsBiosNgRS485Slave.cpp.inc @@ -243,13 +243,11 @@ namespace DcsBios { PollingInput::pollInputs(); ExportStreamListener::loopAll(); - #ifdef DCSBIOS_ALTERNATIVE_RS485_PROCESSING // Process incoming data outside of ISR if (!parser.incomingDataBuffer.isEmpty()) { unsigned char nextByte = parser.incomingDataBuffer.get(); parser.processChar(nextByte); } - #endif } } #endif diff --git a/src/internal/Protocol.cpp.inc b/src/internal/Protocol.cpp.inc index 12248fa..d10d998 100644 --- a/src/internal/Protocol.cpp.inc +++ b/src/internal/Protocol.cpp.inc @@ -25,8 +25,8 @@ 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. If DCSBIOS_RS485_SLAVE is defined, the processing is deferred to loop(). - #ifndef DCSBIOS_ALTERNATIVE_RS485_PROCESSING + // 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_RS485_SLAVE if (processingData) return; processingData = true; @@ -38,9 +38,6 @@ namespace DcsBios { unsigned char nextByte = incomingDataBuffer.get(); interrupts(); processChar(nextByte); -#ifdef DCSBIOS_RS485_SLAVE - noInterrupts(); -#endif } #endif } From c3923a640ba179e8e73dc4cd8695ff09bb8b1029 Mon Sep 17 00:00:00 2001 From: Maciej Swic <442007+maciekish@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:24:21 +0300 Subject: [PATCH 07/10] Cleanup --- src/internal/DcsBiosNgRS485Slave.cpp.inc | 2 +- src/internal/Protocol.cpp.inc | 4 ---- src/internal/Protocol.h | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/internal/DcsBiosNgRS485Slave.cpp.inc b/src/internal/DcsBiosNgRS485Slave.cpp.inc index faa61b5..6b392f7 100644 --- a/src/internal/DcsBiosNgRS485Slave.cpp.inc +++ b/src/internal/DcsBiosNgRS485Slave.cpp.inc @@ -107,7 +107,7 @@ namespace DcsBios { case RX_WAIT_DATA: rxtx_len--; if (rx_datatype == RXDATA_DCSBIOS_EXPORT) { - if (rxtx_len <= parser.availableBufferSpace()) { + if (rxtx_len <= parser.incomingDataBuffer.availableForWrite()) { parser.processCharISR(c); } } diff --git a/src/internal/Protocol.cpp.inc b/src/internal/Protocol.cpp.inc index d10d998..2bd589b 100644 --- a/src/internal/Protocol.cpp.inc +++ b/src/internal/Protocol.cpp.inc @@ -13,10 +13,6 @@ namespace DcsBios { sync_byte_count = 0; } - uint8_t ProtocolParser::availableBufferSpace() { - return incomingDataBuffer.availableForWrite(); - } - /* to be called from ISR stores the character in a buffer, re-enables interrupts and processes the complete diff --git a/src/internal/Protocol.h b/src/internal/Protocol.h index 198d180..aa0da52 100644 --- a/src/internal/Protocol.h +++ b/src/internal/Protocol.h @@ -30,9 +30,9 @@ namespace DcsBios { volatile bool processingData; public: RingBuffer incomingDataBuffer; + void processChar(unsigned char c); void processCharISR(unsigned char c); - uint8_t availableBufferSpace(); ProtocolParser(); }; } From 39d4534acbb3c29b4ee3bdbad05540a62d51dd3f Mon Sep 17 00:00:00 2001 From: Maciej Swic <442007+maciekish@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:45:11 +0300 Subject: [PATCH 08/10] Reset RS485 state to SYNC if buffer is full, otherwise if loop() picks up another character, the tail end of a partial new message may end up in the incomingDataBuffer. --- src/internal/DcsBiosNgRS485Slave.cpp.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/internal/DcsBiosNgRS485Slave.cpp.inc b/src/internal/DcsBiosNgRS485Slave.cpp.inc index 6b392f7..ad0dea4 100644 --- a/src/internal/DcsBiosNgRS485Slave.cpp.inc +++ b/src/internal/DcsBiosNgRS485Slave.cpp.inc @@ -109,6 +109,9 @@ namespace DcsBios { if (rx_datatype == RXDATA_DCSBIOS_EXPORT) { if (rxtx_len <= parser.incomingDataBuffer.availableForWrite()) { parser.processCharISR(c); + } else { + last_rx_time = micros(); + state = SYNC; } } if (rxtx_len == 0) { From 88e00bd3d1aa74d5b80d287de3767f53b0f07d4d Mon Sep 17 00:00:00 2001 From: Maciej Swic <442007+maciekish@users.noreply.github.com> Date: Thu, 12 Oct 2023 20:57:55 +0300 Subject: [PATCH 09/10] Added #define DCSBIOS_DEFER_RS485_PROCESSING --- src/internal/DcsBiosNgRS485Slave.cpp.inc | 2 ++ src/internal/Protocol.cpp.inc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/internal/DcsBiosNgRS485Slave.cpp.inc b/src/internal/DcsBiosNgRS485Slave.cpp.inc index ad0dea4..0ac80fb 100644 --- a/src/internal/DcsBiosNgRS485Slave.cpp.inc +++ b/src/internal/DcsBiosNgRS485Slave.cpp.inc @@ -247,10 +247,12 @@ namespace DcsBios { 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 } } #endif diff --git a/src/internal/Protocol.cpp.inc b/src/internal/Protocol.cpp.inc index 2bd589b..48ce3d4 100644 --- a/src/internal/Protocol.cpp.inc +++ b/src/internal/Protocol.cpp.inc @@ -22,7 +22,7 @@ namespace DcsBios { 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_RS485_SLAVE + #ifndef DCSBIOS_DEFER_RS485_PROCESSING if (processingData) return; processingData = true; From 537125f0376ab9707d1c80584e7863e6aa47cd75 Mon Sep 17 00:00:00 2001 From: Maciej Swic Date: Sat, 22 Jun 2024 04:55:36 +0300 Subject: [PATCH 10/10] DCSBIOS_DEFER_RS485_PROCESSING example --- examples/RS485Deferred/RS485Deferred.ino | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 examples/RS485Deferred/RS485Deferred.ino diff --git a/examples/RS485Deferred/RS485Deferred.ino b/examples/RS485Deferred/RS485Deferred.ino new file mode 100644 index 0000000..7fc621c --- /dev/null +++ b/examples/RS485Deferred/RS485Deferred.ino @@ -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(); +} \ No newline at end of file