2025-12-13 20:23:28 +01:00
|
|
|
#include "UartHandler.hpp"
|
|
|
|
|
#include "OperationTimeout.hpp"
|
|
|
|
|
#include "StateMachine.hpp"
|
|
|
|
|
|
|
|
|
|
UartHandler::UartHandler() noexcept
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UartHandler::~UartHandler()
|
|
|
|
|
{
|
|
|
|
|
// In case close was not called, close now
|
|
|
|
|
if (isOpen()) {
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-15 20:22:28 +01:00
|
|
|
UartHandler &UartHandler::getInstance() noexcept
|
2025-12-13 20:23:28 +01:00
|
|
|
{
|
|
|
|
|
static UartHandler instance;
|
|
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UartHandler::init(const uint32_t baudRate)
|
|
|
|
|
{
|
|
|
|
|
// Wait for serial port to connect, consider failed after one second
|
|
|
|
|
Serial.begin(baudRate);
|
|
|
|
|
OperationTimeout ot(1000);
|
|
|
|
|
while (!Serial) {
|
|
|
|
|
if (ot.isTimeout()) {
|
|
|
|
|
StateMachine::getInstance().raiseError("Unable to open serial port");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
yield();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UartHandler::close()
|
|
|
|
|
{
|
|
|
|
|
Serial.end();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UartHandler::isOpen() const noexcept
|
|
|
|
|
{
|
|
|
|
|
return (bool)Serial;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-15 20:22:28 +01:00
|
|
|
void UartHandler::poll() noexcept
|
2025-12-13 20:23:28 +01:00
|
|
|
{
|
2025-12-15 20:22:28 +01:00
|
|
|
if (!isOpen()) {
|
|
|
|
|
StateMachine::getInstance().raiseError("Serial closed!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-14 18:57:28 +01:00
|
|
|
size_t bytesAvail = Serial.available();
|
2025-12-13 20:23:28 +01:00
|
|
|
if (bytesAvail) {
|
2025-12-14 18:57:28 +01:00
|
|
|
// Consume at max one byte at a time to give consumers a chance to consume packets
|
|
|
|
|
// ALso this simplifies recognizing packet ends
|
|
|
|
|
size_t bytesRead = Serial.readBytes(inBuf + inBufPos, 1);
|
|
|
|
|
if (!bytesRead) {
|
|
|
|
|
StateMachine::getInstance().raiseError("Unable to read available byte!");
|
|
|
|
|
return;
|
2025-12-13 20:23:28 +01:00
|
|
|
}
|
2025-12-14 18:57:28 +01:00
|
|
|
inBufPos++;
|
|
|
|
|
|
|
|
|
|
// Is our buffer full? Push it.
|
|
|
|
|
if (inBufPos == PACKET_SIZE) {
|
2025-12-13 20:23:28 +01:00
|
|
|
pushPacket();
|
|
|
|
|
inBufPos = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-15 20:22:28 +01:00
|
|
|
void UartHandler::pushPacket() noexcept
|
2025-12-13 20:23:28 +01:00
|
|
|
{
|
|
|
|
|
memset(packetRingBuf + packetRingBufWritePos * PACKET_SIZE, 0x00, PACKET_SIZE);
|
|
|
|
|
memcpy(packetRingBuf + packetRingBufWritePos * PACKET_SIZE, inBuf, inBufPos);
|
|
|
|
|
packetRingBufWritePos = (packetRingBufWritePos + 1) % PACKET_RINGBUF_SIZE;
|
|
|
|
|
numPacketsAvailable++;
|
|
|
|
|
|
|
|
|
|
if (numPacketsAvailable >= PACKET_RINGBUF_SIZE) {
|
|
|
|
|
// Move machine into error state -> reports errors and failsafes
|
|
|
|
|
StateMachine::getInstance().raiseError("UART packet dropped because it was not read!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-15 20:22:28 +01:00
|
|
|
bool UartHandler::getNextPacket(char* dest) noexcept
|
2025-12-13 20:23:28 +01:00
|
|
|
{
|
|
|
|
|
if (!numPacketsAvailable) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(dest, packetRingBuf + packetRingBufReadPos * PACKET_SIZE, PACKET_SIZE);
|
|
|
|
|
packetRingBufReadPos = (packetRingBufReadPos + 1) % PACKET_RINGBUF_SIZE;
|
|
|
|
|
numPacketsAvailable--;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-15 20:22:28 +01:00
|
|
|
size_t UartHandler::send(const char *buf, size_t nbytes)
|
|
|
|
|
{
|
|
|
|
|
if (!isOpen()) {
|
|
|
|
|
StateMachine::getInstance().raiseError("Serial closed!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-12-13 20:23:28 +01:00
|
|
|
|
2025-12-15 20:22:28 +01:00
|
|
|
return Serial.write(buf, nbytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t UartHandler::send(const String& str)
|
|
|
|
|
{
|
|
|
|
|
if (!isOpen()) {
|
|
|
|
|
StateMachine::getInstance().raiseError("Serial closed!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Serial.write(str.c_str(), str.length());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t UartHandler::getNumAvailablePackets() const noexcept
|
2025-12-13 20:23:28 +01:00
|
|
|
{
|
|
|
|
|
return numPacketsAvailable;
|
|
|
|
|
}
|