#include "CRC16.h" volatile uint8_t control_flags = 0xC9; volatile uint32_t timer_end = 0x00000000; volatile uint32_t length = 0x00000000; volatile uint32_t last_timer_sent = 0x00000000; CRC16 crc = CRC16(0x1021, 0xFFFF, 0x0000, false, false); int read_line = 22; int rx2 = 16; int tx2 = 17; uint32_t htonl(uint32_t val) { return ((val & 0x000000FF) << 24) | ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8) | ((val & 0xFF000000) >> 24); } uint16_t htons(uint16_t val) { return ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8); } typedef struct __attribute__((packed)) { uint8_t type; uint8_t controller_version; uint8_t unknown[12]; uint16_t crc; } pkt_discovery_t; typedef struct __attribute__((packed)) { uint8_t type; uint8_t unknown_1[7]; uint32_t serial; uint8_t unknown_2[2]; uint16_t crc; } pkt_discovery_resp_t; typedef struct __attribute__((packed)) { uint8_t type; uint8_t unknown[13]; uint16_t crc; } pkt_init_t; typedef struct __attribute__((packed)) { uint8_t type; uint8_t ack_type; uint8_t unknown_1; uint8_t unknown_2[7]; uint8_t unknown_3; uint8_t unknown_4[3]; uint16_t crc; } pkt_ack_t; typedef struct __attribute__((packed)) { uint8_t type; uint8_t unknown[29]; uint16_t crc; } pkt_set_poll_rate_t; typedef struct __attribute__((packed)) { uint8_t type; uint8_t unknown_1; uint16_t system_status; uint8_t unknown_2[2]; uint8_t field_status; uint8_t unknown_3[11]; uint8_t name[10]; uint8_t version[2]; uint16_t crc; } pkt_poll_t; void parse_discovery(uint8_t* pkt, size_t len) { pkt_discovery_t parsed; parsed.controller_version = pkt[1]; memcpy(parsed.unknown, &pkt[2], 12); parsed.crc = (pkt[14] << 8) + (pkt[15] << 0); crc.restart(); crc.add(pkt, 14); uint16_t calc_crc = crc.calc(); if (calc_crc != parsed.crc) { Serial.printf("Got dicovery packet with bad crc(%04x != %04x)\n", calc_crc, parsed.crc); } else { Serial.printf("Got dicovery packet with matching crc(%04x)\n", calc_crc); } pkt_discovery_resp_t response; response.type = 0x03; response.unknown_1[0] = 0x01; response.unknown_1[1] = 0x64; response.unknown_1[2] = 0x00; response.unknown_1[3] = 0x00; response.unknown_1[4] = 0x00; response.unknown_1[5] = 0x00; response.unknown_1[6] = 0xBA; response.serial = htonl(0x881C7C00); response.unknown_2[0] = 0x00; response.unknown_2[1] = 0x00; crc.restart(); crc.add((uint8_t*)&response, 14); response.crc = htons(crc.calc()); digitalWrite(read_line, HIGH); Serial2.write((uint8_t*)&response, 16); delayMicroseconds(100); digitalWrite(read_line, LOW); } void parse_init(uint8_t* pkt, size_t len) { pkt_init_t parsed; memcpy(parsed.unknown, &pkt[1], 13); parsed.crc = (pkt[14] << 8) + (pkt[15] << 0); crc.restart(); crc.add(pkt, 14); uint16_t calc_crc = crc.calc(); if (calc_crc != parsed.crc) { Serial.printf("Got init packet with bad crc(%04x != %04x)\n", calc_crc, parsed.crc); } else { Serial.printf("Got init packet with matching crc(%04x)\n", calc_crc); } pkt_ack_t response; response.type = 0x02; response.ack_type = pkt[0]; response.unknown_1 = 0x01; memset(response.unknown_2, 0, 7); response.unknown_3 = 0x01; memset(response.unknown_4, 0, 3); crc.restart(); crc.add((uint8_t*)&response, 14); response.crc = htons(crc.calc()); digitalWrite(read_line, HIGH); Serial2.write((uint8_t*)&response, 16); delayMicroseconds(100); digitalWrite(read_line, LOW); } void parse_get_poll_rate(uint8_t* pkt, size_t len, uint8_t poll_ms) { crc.restart(); crc.add(pkt, 30); uint16_t parsed_crc = (pkt[30] << 8) + (pkt[31] << 0); uint16_t calc_crc = crc.calc(); if (parsed_crc != calc_crc) { Serial.printf("Got get_poll_rate packet with bad crc(%04x != %04x\n", calc_crc, parsed_crc); } else { Serial.printf("Got get_poll_rate packet with matching crc(%04x)\n", calc_crc); } pkt_set_poll_rate_t response; response.type = 0x04; memset(response.unknown, 0, 29); response.unknown[1] = 0x14; crc.restart(); crc.add((uint8_t*)&response, 30); response.crc = htons(crc.calc()); digitalWrite(read_line, HIGH); Serial2.write((uint8_t*)&response, 32); delayMicroseconds(200); digitalWrite(read_line, LOW); } void send_ack(uint8_t ack_type, uint8_t unknown) { uint8_t response[32]; memset(response, 0, 32); response[0] = 0x02; response[1] = ack_type; response[2] = unknown; response[10] = unknown; crc.restart(); crc.add(response, 30); uint16_t ack_crc = crc.calc(); response[30] = (ack_crc >> 8 & 0xFF); response[31] = (ack_crc >> 0 & 0xFF); digitalWrite(read_line, HIGH); Serial2.write((uint8_t*)&response, 32); delayMicroseconds(200); digitalWrite(read_line, LOW); } void send_state(uint8_t control_flags, uint32_t timer) { uint8_t response[32]; memset(response, 0, 32); response[0] = 0x53; response[1] = control_flags; response[2] = 0x00; response[3] = 0x00; response[4] = ((timer >> 0) & 0xFF); response[5] = ((timer >> 8) & 0xFF); response[6] = ((timer >> 16) & 0xFF); response[7] = ((timer >> 24) & 0xFF); response[8] = 0x03; crc.restart(); crc.add(response, 30); uint16_t ack_crc = crc.calc(); response[30] = (ack_crc >> 8 & 0xFF); response[31] = (ack_crc >> 0 & 0xFF); digitalWrite(read_line, HIGH); Serial2.write((uint8_t*)&response, 32); delayMicroseconds(200); digitalWrite(read_line, LOW); } void parse_poll(uint8_t* pkt, size_t len) { pkt_poll_t* parsed = (pkt_poll_t*)pkt; crc.restart(); crc.add(pkt, 30); uint16_t crc_calc = crc.calc(); if (htons(parsed->crc) != crc_calc) { Serial.printf("parsed poll with invalid CRC 0x%04x, calculated to be 0x%04x\n", htons(parsed->crc), crc_calc); } else { //Serial.printf("parsed poll with valid CRC 0x%04x, system status 0x%04x, field status 0x%02x, team name %s\n", htons(parsed->crc), htons(parsed->system_status), parsed->field_status, parsed->name); } uint32_t now = millis(); uint32_t current_timer = 0; if (now < timer_end) { current_timer = (timer_end - millis()) & 0xFFFFFF00; } else { current_timer = length; control_flags = 0xC9; } if ((parsed->field_status == control_flags) && (current_timer == last_timer_sent)) { send_ack(0xA7, 0x01); } else if (control_flags == 0xC9) { send_state(0xC9, length); } else { last_timer_sent = current_timer; send_state(control_flags, current_timer); } } void on_rx(void) { uint8_t pkt[12]; int n = Serial.available(); if (n != 12) { Serial.printf("Wrong number of bytes on serial port %d/12\n", n); for (int i = 0; i < n; i++) { Serial.read(); } return; } int read = Serial.readBytes(pkt, n); sscanf((const char*)pkt, "0x%2hhx%8x", &control_flags, &length); timer_end = millis() + length; Serial.printf("Parsed new control flags: 0x%02x, length 0x%08x\n", control_flags, length); } void on_rx_2(void) { uint8_t pkt[32]; int n = Serial2.available(); if (n < 16) { return; } int read = Serial2.readBytes(pkt, n); switch (pkt[0]) { case 0xA7: parse_poll(pkt, read); break; case 0x0A: parse_discovery(pkt, read); break; case 0x13: parse_init(pkt, read); break; case 0x11: parse_get_poll_rate(pkt, read, 20); break; case 0x02: switch (pkt[1]){ case 0x04: send_ack(0x02, 0x00); break; default: Serial.printf("Unknown ack 0x%x\n", pkt[1]); } break; default: Serial.printf("Unknown command 0x%x\n", pkt[0]); break; } } void setup() { Serial.begin(115200); Serial2.begin(1562500, SERIAL_8N1, rx2, tx2); pinMode(read_line, OUTPUT); digitalWrite(read_line, LOW); Serial2.onReceive(on_rx_2); Serial.onReceive(on_rx); Serial.println("Started"); } void loop() { }