Initial public release of SystemK.
This commit is contained in:
parent
387f57cdda
commit
6f51f5b006
129 changed files with 11654 additions and 2 deletions
325
Protocols/Dubuque.c
Normal file
325
Protocols/Dubuque.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* This program source code file is part of SystemK, a library in the KTag project.
|
||||
*
|
||||
* 🛡️ <https://ktag.clubk.club> 🃞
|
||||
*
|
||||
* Copyright © 2024-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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "SystemK.h"
|
||||
|
||||
#define DBQ_PURPLE_TEAM 0b00
|
||||
#define DBQ_RED_TEAM 0b01
|
||||
#define DBQ_BLUE_TEAM 0b10
|
||||
#define DBQ_WHITE_TEAM 0b11
|
||||
|
||||
#define DBQ_ZERO_MARK_DURATION_IN_us 400
|
||||
#define DBQ_ZERO_SPACE_DURATION_IN_us 800
|
||||
#define DBQ_ONE_MARK_DURATION_IN_us 800
|
||||
#define DBQ_ONE_SPACE_DURATION_IN_us 400
|
||||
#define DBQ_TOLERANCE_IN_us 199
|
||||
|
||||
#define DBQ_PURPLE_TX_GAP_IN_us 2600
|
||||
#define DBQ_RED_TX_GAP_IN_us 5000
|
||||
#define DBQ_BLUE_TX_GAP_IN_us 7400
|
||||
#define DBQ_WHITE_TX_GAP_IN_us 9800
|
||||
|
||||
#define MIN_ZERO_MARK_IN_us (DBQ_ZERO_MARK_DURATION_IN_us - DBQ_TOLERANCE_IN_us)
|
||||
#define MAX_ZERO_MARK_IN_us (DBQ_ZERO_MARK_DURATION_IN_us + DBQ_TOLERANCE_IN_us)
|
||||
#define MIN_ZERO_SPACE_IN_us (DBQ_ZERO_SPACE_DURATION_IN_us - DBQ_TOLERANCE_IN_us)
|
||||
#define MAX_ZERO_SPACE_IN_us (DBQ_ZERO_SPACE_DURATION_IN_us + DBQ_TOLERANCE_IN_us)
|
||||
#define MIN_ONE_MARK_IN_us (DBQ_ONE_MARK_DURATION_IN_us - DBQ_TOLERANCE_IN_us)
|
||||
#define MAX_ONE_MARK_IN_us (DBQ_ONE_MARK_DURATION_IN_us + DBQ_TOLERANCE_IN_us)
|
||||
#define MIN_ONE_SPACE_IN_us (DBQ_ONE_SPACE_DURATION_IN_us - DBQ_TOLERANCE_IN_us)
|
||||
#define MAX_ONE_SPACE_IN_us (DBQ_ONE_SPACE_DURATION_IN_us + DBQ_TOLERANCE_IN_us)
|
||||
|
||||
static const TimedBit_T DBQ_ZERO_MARK = {.symbol = MARK, .duration = DBQ_ZERO_MARK_DURATION_IN_us};
|
||||
static const TimedBit_T DBQ_ONE_MARK = {.symbol = MARK, .duration = DBQ_ONE_MARK_DURATION_IN_us};
|
||||
static const TimedBit_T DBQ_ZERO_SPACE = {.symbol = SPACE, .duration = DBQ_ZERO_SPACE_DURATION_IN_us};
|
||||
static const TimedBit_T DBQ_ONE_SPACE = {.symbol = SPACE, .duration = DBQ_ONE_SPACE_DURATION_IN_us};
|
||||
static const TimedBit_T DBQ_PURPLE_GAP = {.symbol = SPACE, .duration = DBQ_ZERO_SPACE_DURATION_IN_us + DBQ_PURPLE_TX_GAP_IN_us};
|
||||
static const TimedBit_T DBQ_RED_GAP = {.symbol = SPACE, .duration = DBQ_ONE_SPACE_DURATION_IN_us + DBQ_RED_TX_GAP_IN_us};
|
||||
static const TimedBit_T DBQ_BLUE_GAP = {.symbol = SPACE, .duration = DBQ_ZERO_SPACE_DURATION_IN_us + DBQ_BLUE_TX_GAP_IN_us};
|
||||
static const TimedBit_T DBQ_WHITE_GAP = {.symbol = SPACE, .duration = DBQ_ONE_SPACE_DURATION_IN_us + DBQ_WHITE_TX_GAP_IN_us};
|
||||
static const TimedBit_T DBQ_END = {.symbol = SPACE, .duration = LAST_PULSE};
|
||||
|
||||
static TimedPulseTrain_T Tag_Send_Buffer;
|
||||
static DecodedPacket_T DBQ_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 uint_fast16_t Team_To_Ignore = DBQ_WHITE_TEAM;
|
||||
|
||||
static inline DecodedPacket_T *Get_Tag_Packet_Buffer(void)
|
||||
{
|
||||
if (DBQ_Tag_Received_Buffers[0].Tag.type == DECODED_PACKET_TYPE_BUFFER_FREE)
|
||||
{
|
||||
return &DBQ_Tag_Received_Buffers[0];
|
||||
}
|
||||
else if (DBQ_Tag_Received_Buffers[1].Tag.type == DECODED_PACKET_TYPE_BUFFER_FREE)
|
||||
{
|
||||
return &DBQ_Tag_Received_Buffers[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just use it.
|
||||
return &DBQ_Tag_Received_Buffers[2];
|
||||
}
|
||||
}
|
||||
|
||||
TimedPulseTrain_T *DBQ_EncodePacket(TagPacket_T *packet)
|
||||
{
|
||||
if (packet->team_ID == DBQ_PURPLE_TEAM)
|
||||
{
|
||||
Tag_Send_Buffer.bitstream[0] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[1] = DBQ_ZERO_SPACE;
|
||||
Tag_Send_Buffer.bitstream[2] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[3] = DBQ_PURPLE_GAP;
|
||||
Tag_Send_Buffer.bitstream[4] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[5] = DBQ_ZERO_SPACE;
|
||||
Tag_Send_Buffer.bitstream[6] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[7] = DBQ_ZERO_SPACE;
|
||||
Tag_Send_Buffer.bitstream[8] = DBQ_END;
|
||||
}
|
||||
else if (packet->team_ID == DBQ_RED_TEAM)
|
||||
{
|
||||
Team_To_Ignore = DBQ_RED_TEAM;
|
||||
|
||||
Tag_Send_Buffer.bitstream[0] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[1] = DBQ_ZERO_SPACE;
|
||||
Tag_Send_Buffer.bitstream[2] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[3] = DBQ_RED_GAP;
|
||||
Tag_Send_Buffer.bitstream[4] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[5] = DBQ_ZERO_SPACE;
|
||||
Tag_Send_Buffer.bitstream[6] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[7] = DBQ_ONE_SPACE;
|
||||
Tag_Send_Buffer.bitstream[8] = DBQ_END;
|
||||
}
|
||||
else if (packet->team_ID == DBQ_BLUE_TEAM)
|
||||
{
|
||||
Team_To_Ignore = DBQ_BLUE_TEAM;
|
||||
|
||||
Tag_Send_Buffer.bitstream[0] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[1] = DBQ_ONE_SPACE;
|
||||
Tag_Send_Buffer.bitstream[2] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[3] = DBQ_BLUE_GAP;
|
||||
Tag_Send_Buffer.bitstream[4] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[5] = DBQ_ONE_SPACE;
|
||||
Tag_Send_Buffer.bitstream[6] = DBQ_ZERO_MARK;
|
||||
Tag_Send_Buffer.bitstream[7] = DBQ_ZERO_SPACE;
|
||||
Tag_Send_Buffer.bitstream[8] = DBQ_END;
|
||||
}
|
||||
else // if (packet->team_ID == DBQ_WHITE_TEAM)
|
||||
{
|
||||
Tag_Send_Buffer.bitstream[0] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[1] = DBQ_ONE_SPACE;
|
||||
Tag_Send_Buffer.bitstream[2] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[3] = DBQ_WHITE_GAP;
|
||||
Tag_Send_Buffer.bitstream[4] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[5] = DBQ_ONE_SPACE;
|
||||
Tag_Send_Buffer.bitstream[6] = DBQ_ONE_MARK;
|
||||
Tag_Send_Buffer.bitstream[7] = DBQ_ONE_SPACE;
|
||||
Tag_Send_Buffer.bitstream[8] = DBQ_END;
|
||||
}
|
||||
|
||||
Tag_Send_Buffer.count = 8;
|
||||
|
||||
return &Tag_Send_Buffer;
|
||||
}
|
||||
|
||||
DecodedPacket_T *DBQ_MaybeDecodePacket(TimedPulseTrain_T *packet)
|
||||
{
|
||||
uint_fast8_t decoded_data = UINT_FAST8_MAX;
|
||||
uint_fast8_t consecutive_bits = 0;
|
||||
uint_fast8_t ignored_data = UINT_FAST8_MAX;
|
||||
|
||||
// Special handling for the purple team.
|
||||
uint_fast16_t collisions = 0;
|
||||
uint_fast16_t purple_completions = 0;
|
||||
|
||||
// Loop through all the pulses, looking for a match.
|
||||
for (uint8_t n = 0; n < packet->count; n += 2)
|
||||
{
|
||||
// Even pulses are marks; odd pulses are spaces.
|
||||
if (consecutive_bits == 0)
|
||||
{
|
||||
// Perform full checking on the first bit.
|
||||
if ((packet->bitstream[n].duration > MIN_ONE_MARK_IN_us) && (packet->bitstream[n].duration < MAX_ONE_MARK_IN_us) &&
|
||||
(packet->bitstream[n + 1].duration > MIN_ONE_SPACE_IN_us) && (packet->bitstream[n + 1].duration < MAX_ONE_SPACE_IN_us))
|
||||
{
|
||||
// This is a "one".
|
||||
decoded_data = 2;
|
||||
consecutive_bits = 1;
|
||||
}
|
||||
else if ((packet->bitstream[n].duration > MIN_ZERO_MARK_IN_us) && (packet->bitstream[n].duration < MAX_ZERO_MARK_IN_us) &&
|
||||
(packet->bitstream[n + 1].duration > MIN_ZERO_SPACE_IN_us) && (packet->bitstream[n + 1].duration < MAX_ZERO_SPACE_IN_us))
|
||||
{
|
||||
// This is a "zero".
|
||||
decoded_data = 0;
|
||||
consecutive_bits = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This mark/space combination is neither a zero or a one; continue.
|
||||
collisions++;
|
||||
}
|
||||
}
|
||||
else // consecutive_bits > 0
|
||||
{
|
||||
// One the second bit, full check the mark, and make sure the space is long enough.
|
||||
if ((packet->bitstream[n].duration > MIN_ONE_MARK_IN_us) && (packet->bitstream[n].duration < MAX_ONE_MARK_IN_us) &&
|
||||
((packet->bitstream[n + 1].duration > MIN_ONE_SPACE_IN_us) || (packet->bitstream[n + 1].duration == LAST_PULSE)))
|
||||
{
|
||||
// This is a "one".
|
||||
decoded_data += 1;
|
||||
|
||||
if (decoded_data == Team_To_Ignore)
|
||||
{
|
||||
// We received a packet we should ignore. Remember this, and keep looking.
|
||||
ignored_data = decoded_data;
|
||||
decoded_data = UINT_FAST8_MAX;
|
||||
consecutive_bits = 0;
|
||||
}
|
||||
else if (decoded_data == DBQ_PURPLE_TEAM)
|
||||
{
|
||||
// We received a purple packet. Remember this, and keep looking.
|
||||
purple_completions++;
|
||||
decoded_data = UINT_FAST8_MAX;
|
||||
consecutive_bits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((packet->bitstream[n].duration > MIN_ZERO_MARK_IN_us) && (packet->bitstream[n].duration < MAX_ZERO_MARK_IN_us) &&
|
||||
((packet->bitstream[n + 1].duration > MIN_ZERO_SPACE_IN_us) || (packet->bitstream[n + 1].duration == LAST_PULSE)))
|
||||
{
|
||||
// This is a "zero".
|
||||
decoded_data += 0;
|
||||
|
||||
if (decoded_data == Team_To_Ignore)
|
||||
{
|
||||
// We received a packet we should ignore. Remember this, and keep looking.
|
||||
ignored_data = decoded_data;
|
||||
decoded_data = UINT_FAST8_MAX;
|
||||
consecutive_bits = 0;
|
||||
}
|
||||
else if (decoded_data == DBQ_PURPLE_TEAM)
|
||||
{
|
||||
// We received a purple packet. Remember this, and keep looking.
|
||||
purple_completions++;
|
||||
decoded_data = UINT_FAST8_MAX;
|
||||
consecutive_bits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This mark/space combination is neither a zero or a one; reset.
|
||||
collisions++;
|
||||
decoded_data = UINT_FAST8_MAX;
|
||||
consecutive_bits = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we ignored the only data we received, restore it here.
|
||||
if ((ignored_data != UINT_FAST8_MAX) && (decoded_data == UINT_FAST8_MAX))
|
||||
{
|
||||
decoded_data = ignored_data;
|
||||
}
|
||||
|
||||
if (purple_completions > 0)
|
||||
{
|
||||
DecodedPacket_T *Tag_Rx_Buffer = Get_Tag_Packet_Buffer();
|
||||
Tag_Rx_Buffer->Tag.type = DECODED_PACKET_TYPE_TAG_RECEIVED;
|
||||
Tag_Rx_Buffer->Tag.protocol = DUBUQUE_PROTOCOL;
|
||||
Tag_Rx_Buffer->Tag.player_ID = 0;
|
||||
Tag_Rx_Buffer->Tag.team_ID = DBQ_PURPLE_TEAM;
|
||||
Tag_Rx_Buffer->Tag.damage = 10 * (purple_completions + collisions);
|
||||
Tag_Rx_Buffer->Tag.color = COLOR_PURPLE;
|
||||
return Tag_Rx_Buffer;
|
||||
}
|
||||
else if (decoded_data == DBQ_RED_TEAM)
|
||||
{
|
||||
DecodedPacket_T *Tag_Rx_Buffer = Get_Tag_Packet_Buffer();
|
||||
Tag_Rx_Buffer->Tag.type = DECODED_PACKET_TYPE_TAG_RECEIVED;
|
||||
Tag_Rx_Buffer->Tag.protocol = DUBUQUE_PROTOCOL;
|
||||
Tag_Rx_Buffer->Tag.player_ID = 0;
|
||||
Tag_Rx_Buffer->Tag.team_ID = DBQ_RED_TEAM;
|
||||
Tag_Rx_Buffer->Tag.damage = 10;
|
||||
Tag_Rx_Buffer->Tag.color = COLOR_RED;
|
||||
return Tag_Rx_Buffer;
|
||||
}
|
||||
else if (decoded_data == DBQ_BLUE_TEAM)
|
||||
{
|
||||
DecodedPacket_T *Tag_Rx_Buffer = Get_Tag_Packet_Buffer();
|
||||
Tag_Rx_Buffer->Tag.type = DECODED_PACKET_TYPE_TAG_RECEIVED;
|
||||
Tag_Rx_Buffer->Tag.protocol = DUBUQUE_PROTOCOL;
|
||||
Tag_Rx_Buffer->Tag.player_ID = 0;
|
||||
Tag_Rx_Buffer->Tag.team_ID = DBQ_BLUE_TEAM;
|
||||
Tag_Rx_Buffer->Tag.damage = 10;
|
||||
Tag_Rx_Buffer->Tag.color = COLOR_BLUE;
|
||||
return Tag_Rx_Buffer;
|
||||
}
|
||||
else if (decoded_data == DBQ_WHITE_TEAM)
|
||||
{
|
||||
DecodedPacket_T *Tag_Rx_Buffer = Get_Tag_Packet_Buffer();
|
||||
Tag_Rx_Buffer->Tag.type = DECODED_PACKET_TYPE_TAG_RECEIVED;
|
||||
Tag_Rx_Buffer->Tag.protocol = DUBUQUE_PROTOCOL;
|
||||
Tag_Rx_Buffer->Tag.player_ID = 0;
|
||||
Tag_Rx_Buffer->Tag.team_ID = DBQ_WHITE_TEAM;
|
||||
Tag_Rx_Buffer->Tag.damage = 10;
|
||||
Tag_Rx_Buffer->Tag.color = COLOR_WHITE;
|
||||
return Tag_Rx_Buffer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
color_t DBQ_GetTeamColor(uint8_t team_ID)
|
||||
{
|
||||
color_t result = COLOR_PURPLE;
|
||||
|
||||
if (team_ID == DBQ_RED_TEAM)
|
||||
{
|
||||
result = COLOR_RED;
|
||||
}
|
||||
else if (team_ID == DBQ_BLUE_TEAM)
|
||||
{
|
||||
result = COLOR_BLUE;
|
||||
}
|
||||
else if (team_ID == DBQ_WHITE_TEAM)
|
||||
{
|
||||
result = COLOR_WHITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue