diff options
Diffstat (limited to 'protocol.cpp')
| -rw-r--r-- | protocol.cpp | 124 |
1 files changed, 0 insertions, 124 deletions
diff --git a/protocol.cpp b/protocol.cpp deleted file mode 100644 index 5ad0975..0000000 --- a/protocol.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "protocol.hpp" -#include "system.hpp" - -#include <Arduino.h> -#include <TimerOne.h> -#include <SPI.h> - -// ============================================================================ -// The throttle qudrant requires a specific protocol for communication: -// 1. At time 0: the "data ready" line will be pulled low. -// 2. At 0.7ms: the line will is release. -// 3. At 1.9ms: the data is ready to be read. -// -// The data can be read out at about 20 kHz. It is presented LSB first and comprises 5 -// bytes. -// ============================================================================ - -namespace tq::protocol { - -namespace state { - -//! Whether or not an SPI transfer is pending. -auto volatile spi_transfer_pending = false; - -//! Whether we are currently in a protocol loop. -auto volatile protocol_loop_running = false; - -} - -namespace settings { - -//! The SPI bus configuration for data transfers from the throttle quadrant. -auto const spi_configuration = SPISettings{ 20000, LSBFIRST, SPI_MODE3 }; - -} - -//! Start a transfer of the throttle quadrant data. -//! -//! This function schedules the next step in the protocol. -auto begin_transfer_cycle() -> void { - // Disable the "data ready" interrupt, since we need to reuse it for the next step. - detachInterrupt(digitalPinToInterrupt(system::data_ready_signal_pin)); - - // Attach an inverted "data ready" interrupt, so we know when to start the timer. - attachInterrupt(digitalPinToInterrupt(system::data_ready_signal_pin), - on_start_delay, - RISING); -} - -auto init() -> void { - // Ensure we are not starting spurious transfers. - state::spi_transfer_pending = false; - state::protocol_loop_running = false; - - // Prepare the protocol timer. - Timer1.initialize(); - - // Prepare the "data ready" signal pin. - pinMode(system::data_ready_signal_pin, INPUT_PULLUP); -} - -auto on_data_ready() -> void { - // Read out the current state of the "data ready" signal pin. - auto pin_state = digitalRead(system::data_ready_signal_pin); - - // Check if we actually are at the start of a transfer. - if (pin_state == LOW) { - begin_transfer_cycle(); - } -} - -auto on_start_delay() -> void { - // Disable the interrupt so we are not interrupted during a transfer. - detachInterrupt(digitalPinToInterrupt(system::data_ready_signal_pin)); - - // Wait 1.2ms until we start the actual SPI transfer. - Timer1.attachInterrupt(on_start_delay_passed, 1200); - Timer1.start(); -} - -auto on_start_delay_passed() -> void { - Timer1.detachInterrupt(); - state::spi_transfer_pending = true; -} - -auto perform_transfer() -> optional<message> { - byte buffer[sizeof(message)] = {}; - - if (!state::spi_transfer_pending) { - return {}; - } - - // Record that we are done with one loop. - state::spi_transfer_pending = false; - state::protocol_loop_running = false; - - SPI.beginTransaction(settings::spi_configuration); - SPI.transfer(buffer, sizeof(buffer)); - SPI.endTransaction(); - - auto parsed = message{}; - memcpy(&parsed, buffer, sizeof(message)); - - return optional<message>{ parsed }; -} - -auto start() -> bool { - // If we are already in a loop, don't start a new one. - if (state::protocol_loop_running) { - return false; - } - - // Record that a loop has started - state::protocol_loop_running = true; - - // Attach the protocol handling subsystem entry point to the correct input line. - attachInterrupt(digitalPinToInterrupt(system::data_ready_signal_pin), - tq::protocol::on_data_ready, - FALLING); - - return true; -} - -}
\ No newline at end of file |
