/* * Copyright (C) 2009,2010,2013,2014 by Jonathan Naylor, G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ /* * CExternalController wraps an IHardwareController (serial port, Arduino, * GPIO board, etc.) and drives it from a dedicated background thread. * * The repeater thread calls the set* methods to express the desired output * state (PTT, heartbeat LED, active indicator, auxiliary outputs). The * internal thread polls the hardware at half the D-Star frame rate (every * 10 ms) and applies those values to the physical I/O pins. Input pins * (the "disable" line) are read on the same schedule and stored atomically * so the repeater thread can check them without blocking. * * PTT inversion * ------------- * Some hardware asserts PTT by pulling a line low rather than high. When * pttInvert is true the radioTX sense is flipped before being written to the * hardware, and the idle state is initialised to the inverted (asserted) value * so the line is de-asserted once the thread starts. * * Shutdown sequence * ----------------- * close() sets m_kill and joins the thread. The thread then de-asserts PTT, * waits three frame periods (60 ms) to let the transmitter drop, asserts the * final idle state once more, then calls m_controller->close(). */ #ifndef ExternalController_H #define ExternalController_H #include "HardwareController.h" #include "StdCompat.h" #include #include class CExternalController { public: CExternalController(IHardwareController* controller, bool pttInvert); virtual ~CExternalController(); // Open the hardware device and start the polling thread. virtual bool open(); // True when the hardware disable input is asserted (repeater should not TX). virtual bool getDisable() const; // Set the desired PTT state; inverted before applying if pttInvert is set. virtual void setRadioTransmit(bool value); // Toggle the heartbeat output each call (caller drives the toggle rate). virtual void setHeartbeat(); // Assert or de-assert the "active" status output. virtual void setActive(bool value); virtual void setOutput1(bool value); virtual void setOutput2(bool value); virtual void setOutput3(bool value); virtual void setOutput4(bool value); // Signal the polling thread to stop, then close the hardware device. virtual void close(); private: void entry(); // Polling thread body IHardwareController* m_controller; // Concrete hardware driver (owned) bool m_pttInvert; // True if PTT sense is active-low // Desired output states written by the repeater thread and read by entry(). // All are atomic so no mutex is needed for the shared flag pattern. std::atomic m_disable; // Latched from the hardware disable input std::atomic m_heartbeat; // Heartbeat/LED toggle std::atomic m_active; // Repeater-active indicator std::atomic m_radioTX; // PTT output (post-inversion) std::atomic m_out1; // Auxiliary outputs 1–4 std::atomic m_out2; std::atomic m_out3; std::atomic m_out4; std::atomic m_kill; // Set by close() to stop the poll loop std::thread m_thread; }; #endif