Initial code

This commit is contained in:
2023-12-21 16:43:41 +11:00
parent b69b784056
commit c84c2dfbdc
8 changed files with 390 additions and 0 deletions

34
src/PacketCRC.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include "PacketCRC.h"
PacketCRC::PacketCRC() : crc(CRC16(0x755B, 0xF48B, 0x0000, false, false)) {
// Constructor implementation (if needed)
}
PacketCRC::~PacketCRC() {
// Destructor implementation (if needed)
}
bool PacketCRC::check(const uint8_t* packet) {
uint8_t length = packet[1];
if (length <= 0 or length > 28) {
return false;
}
uint16_t result = calculate(packet);
uint8_t checksum1 = (uint8_t)((result & 0xFF00) >> 8);
uint8_t checksum2 = (uint8_t)(result & 0x00FF);
if (packet[length + 2] == checksum1 && packet[length + 3] == checksum2) {
return true;
}
return false;
}
uint16_t PacketCRC::calculate(const uint8_t* packet) {
crc.restart();
uint8_t length = packet[1];
crc.add(packet, length + 2);
return crc.calc();
}

82
src/PacketParser.cpp Normal file
View File

@@ -0,0 +1,82 @@
#include "PacketParser.h"
PacketParser::PacketParser()
{
}
PacketParser::~PacketParser()
{
}
bool PacketParser::parsePacket(const uint8_t *buffer, Packet& message)
{
message.source = (uint16_t)(buffer[14] << 8 | buffer[15]);
message.destination = (uint16_t)(buffer[12] << 8 | buffer[13]);
if (buffer[16] == 0x52 && buffer[17] == 0x53) {
message.type = PacketType::STOP;
message.parameters = std::monostate{};
} else if (buffer[16] == 0x52 && buffer[17] == 0x44) {
message.type = PacketType::CLOSE;
message.parameters = std::monostate{};
} else if (buffer[16] == 0x52 && buffer[17] == 0x55) {
message.type = PacketType::OPEN;
message.parameters = std::monostate{};
} else if (buffer[16] == 0x21 && buffer[17] == 0x5A) {
message.type = PacketType::FIELDS;
std::vector<Field> fields;
parseFields(buffer, fields);
message.parameters = FieldsParameters{fields};
} else if (buffer[16] == 0x3F && buffer[17] == 0x5A) {
message.type = PacketType::FIELD_COMMAND;
std::vector<Field> fields;
parseFields(buffer, fields);
message.parameters = FieldsParameters{fields};
} else {
message.type = PacketType::UNKNOWN;
message.parameters = std::monostate{};
return false;
}
return true;
}
bool PacketParser::parseFields(const uint8_t *buffer, std::vector<Field>& fields) {
uint8_t length = buffer[1] + 2;
uint8_t offset = 18;
while (offset < length) {
uint8_t fieldLength = buffer[offset];
if (offset + fieldLength >= length) {
// Not enough space to parse the field
return false;
}
FieldType type;
switch (buffer[offset + 1]) {
case 0x40:
type = FieldType::SET;
break;
case 0x3F:
type = FieldType::FETCH;
break;
case 0x21:
type = FieldType::VALUE;
break;
default:
type = FieldType::UNKNOWN;
break;
}
uint8_t identifier = buffer[offset + 2];
if (fieldLength == 2) {
fields.push_back(Field{identifier, type, false, std::monostate{}});
} else if (fieldLength == 3) {
uint8_t value = buffer[offset + 3];
fields.push_back(Field{identifier, type, true, value});
} else if (fieldLength == 4) {
uint16_t value = (uint16_t)(buffer[offset + 3] | buffer[offset + 4] << 8);
fields.push_back(Field{identifier, type, true, value});
}
offset += fieldLength + 1;
}
return true;
}

122
src/PacketReceiver.cpp Normal file
View File

@@ -0,0 +1,122 @@
#include "PacketReceiver.h"
PacketReceiver::PacketReceiver(RF24 *radio) : radio(radio), packetCallback(nullptr), invalidPacketCallback(nullptr) {
for (int i = 0; i < TOTAL_BUFFER_COUNT; i++) {
if (!freeBuffers.isFull()) {
freeBuffers.push(buffers[i]);
}
}
}
PacketReceiver::~PacketReceiver() {
}
void PacketReceiver::loop() {
noInterrupts();
while (!pendingBuffers.isEmpty()) {
uint8_t *p = pendingBuffers.pop();
bool isSanePacket = this->isSanePacket(p);
bool isValidPacket = this->isValidPacket(p);
bool isNewPacket = this->isNewPacket(p);
// TODO: We don't keep old invalid packets around, so invalid packets will always be new for now
if (isSanePacket && !isValidPacket && isNewPacket) {
if (invalidPacketCallback != nullptr) {
invalidPacketCallback(p);
}
}
if (isValidPacket && isNewPacket) {
if (packetCallback != nullptr) {
this->packetCallback(p);
}
// If there is no space to store this new packet, return the oldest packet
if (receivedBuffers.isFull()) {
freeBuffers.unshift(receivedBuffers.pop());
}
// Keep this packet so we can check if packets received later are duplicates
receivedBuffers.unshift(p);
} else {
// Not a valid packet or is a duplicate packet, so return it immediately
freeBuffers.unshift(p);
}
}
interrupts();
}
//IRQ routine used to fill buffer of max size packets -> needs to be short and fast
void PacketReceiver::read() {
bool tx_ds, tx_df, rx_dr;
radio->whatHappened(tx_ds, tx_df, rx_dr); // resets the IRQ pin to HIGH
uint8_t pipe = 0;
while (radio->available(&pipe)) {
if (!pendingBuffers.isFull() && !freeBuffers.isEmpty()) {
uint8_t* p = freeBuffers.pop();
radio->read(p, BUFFER_SIZE);
pendingBuffers.unshift(p);
} else {
// Not enough buffers to store the packet
radio->flush_rx();
break;
}
}
}
void PacketReceiver::setPacketCallback(void (*callback)(const uint8_t *buffer)) {
this->packetCallback = callback;
}
void PacketReceiver::setInvalidPacketCallback(void (*callback)(const uint8_t *buffer))
{
this->invalidPacketCallback = callback;
}
bool PacketReceiver::isSanePacket(uint8_t *buffer) {
// Sanity check that the buffer isn't just filled with noise
// First byte contains a header
// Second byte contains the packet length which cannot be larger than 28 bytes (32 bytes - 1 header byte - 1 length byte - 2 CRC bytes)
if (buffer[0] == 0xC0 && buffer[1] <= 28) {
return true;
}
return false;
}
bool PacketReceiver::isValidPacket(uint8_t *buffer) {
if (isSanePacket(buffer)) {
if (packetCRC.check(buffer)) {
return true;
}
}
return false;
}
bool PacketReceiver::isNewPacket(uint8_t *buffer) {
for (int i = 0; i < receivedBuffers.size(); i++) {
if (isEquivalentPacket(buffer, receivedBuffers[i])) {
return false;
}
}
return true;
}
bool PacketReceiver::isEquivalentPacket(uint8_t *a, uint8_t *b) {
// Check length byte
if (a[1] != b[1]) {
return false;
}
// TODO: Could we just check the source and destination address and the rolling code?
uint8_t length = a[1] + 4;
for (int i = 0; i < length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}