summaryrefslogtreecommitdiff
path: root/protocol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocol.cpp')
-rw-r--r--protocol.cpp124
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