/* * This program source code file is part of SystemK, a library in the KTag project. * * 🛡️ 🃞 * * Copyright © 2016-2025 Joseph P. Kearney and the KTag developers. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * 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 Affero General Public License for more * details. * * There should be a copy of the GNU Affero General Public License in the LICENSE * file in the root of this repository. If not, see . */ #include #include #include "SystemK.h" static const char *KLOG_TAG = "Test Protocol"; #define TEST_PULSE_SUBTRAHEND_IN_us 300 //! The shortest test packet is a two marks, the first of duration (3 * TEST_PULSE_SUBTRAHEND_IN_us), and the second of duration TEST_PULSE_SUBTRAHEND_IN_us. #define TEST_MINIMUM_LONGEST_PULSE_DURATION_IN_us (3 * TEST_PULSE_SUBTRAHEND_IN_us) #define TEST_TOLERANCE_IN_us ((TEST_PULSE_SUBTRAHEND_IN_us / 2) - 1) static TimedPulseTrain_T Tag_Send_Buffer; static DecodedPacket_T Test_Tag_Received_Buffers[3] = { {.Tag.type = DECODED_PACKET_TYPE_BUFFER_FREE}, {.Tag.type = DECODED_PACKET_TYPE_BUFFER_FREE}, {.Tag.type = DECODED_PACKET_TYPE_BUFFER_FREE}}; static inline DecodedPacket_T *Get_Tag_Packet_Buffer(void) { if (Test_Tag_Received_Buffers[0].Tag.type == DECODED_PACKET_TYPE_BUFFER_FREE) { return &Test_Tag_Received_Buffers[0]; } else if (Test_Tag_Received_Buffers[1].Tag.type == DECODED_PACKET_TYPE_BUFFER_FREE) { return &Test_Tag_Received_Buffers[1]; } else { // Just use it. return &Test_Tag_Received_Buffers[2]; } } static inline void PackPulseTrain(TimedPulseTrain_T *pulsetrain, uint32_t longest_pulse_duration_in_us) { uint_fast8_t index = 0; uint32_t next_pulse_duration_in_us = longest_pulse_duration_in_us; TimedBit_T next_bit; if (next_pulse_duration_in_us < TEST_MINIMUM_LONGEST_PULSE_DURATION_IN_us) { next_pulse_duration_in_us = TEST_MINIMUM_LONGEST_PULSE_DURATION_IN_us; } while ((next_pulse_duration_in_us >= TEST_PULSE_SUBTRAHEND_IN_us) && (index < MAX_PULSES)) { // Even indicies are marks. if ((index % 2) == 0) { next_bit.symbol = MARK; } // Odd indicies are spaces. else { next_bit.symbol = SPACE; } next_bit.duration = next_pulse_duration_in_us; pulsetrain->bitstream[index] = next_bit; next_pulse_duration_in_us = next_pulse_duration_in_us - TEST_PULSE_SUBTRAHEND_IN_us; index++; } // Mark the end of the train. next_bit.symbol = SPACE; next_bit.duration = LAST_PULSE; pulsetrain->bitstream[index] = next_bit; pulsetrain->count = index; } TimedPulseTrain_T *TEST_EncodePacket(TagPacket_T *packet) { uint32_t packed_data = 2100; PackPulseTrain(&Tag_Send_Buffer, packed_data); return &Tag_Send_Buffer; } DecodedPacket_T *TEST_MaybeDecodePacket(TimedPulseTrain_T *packet) { // packet->bitstream[0] is the longest pulse--assume it was received correctly. uint32_t longest_pulse_duration_in_us = packet->bitstream[0].duration; if ((longest_pulse_duration_in_us - TEST_TOLERANCE_IN_us) < TEST_MINIMUM_LONGEST_PULSE_DURATION_IN_us) { // The first pulse is too short! return NULL; } for (uint_fast8_t index = 1; index < packet->count; index++) { uint32_t expected_pulse_duration_in_us = longest_pulse_duration_in_us - (index * TEST_PULSE_SUBTRAHEND_IN_us); if (packet->bitstream[index].duration < (expected_pulse_duration_in_us - TEST_TOLERANCE_IN_us)) { KLOG_WARN(KLOG_TAG, "Pulse %u is too short! Expected %lu; received %u.", index, expected_pulse_duration_in_us, packet->bitstream[index].duration); return NULL; } if (packet->bitstream[index].duration > (expected_pulse_duration_in_us + TEST_TOLERANCE_IN_us)) { KLOG_WARN(KLOG_TAG, "Pulse %u is too long! Expected %lu; received %u.", index, expected_pulse_duration_in_us, packet->bitstream[index].duration); return NULL; } } DecodedPacket_T *Command_Rx_Buffer = Get_Tag_Packet_Buffer(); Command_Rx_Buffer->Command.type = DECODED_PACKET_TYPE_COMMAND_RECEIVED; Command_Rx_Buffer->Command.protocol = TEST_PROTOCOL; Command_Rx_Buffer->Command.data = longest_pulse_duration_in_us; return Command_Rx_Buffer; } color_t TEST_GetTeamColor(__attribute__((unused)) uint8_t team_ID) { color_t result = COLOR_WHITE; return result; }