/* * 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 . */ /** \file * \brief This file defines the Bluetooth Low Energy advertising packets used by KTag. * */ #ifndef BLE_PACKETS_H #define BLE_PACKETS_H #ifdef __cplusplus extern "C" { #endif /* Preprocessor and Type Definitions */ #include #define BLE_MAX_ADVERTISING_BYTES 31 #define BLE_MAX_SCAN_RESPONSE_BYTES 31 #define BD_ADDR_SIZE 6 #define BLE_KTAG_PACKET_TOTAL_SIZE 31 #define BLE_KTAG_PACKET_DATA_SIZE 21 typedef struct { uint8_t data[BLE_MAX_ADVERTISING_BYTES]; uint8_t length; } BLE_AdvertisingData_T; typedef struct { uint8_t data[BLE_MAX_SCAN_RESPONSE_BYTES]; uint8_t length; } BLE_ScanResponseData_T; typedef enum { BLE_PACKET_TYPE_BUFFER_FREE = 0, BLE_PACKET_TYPE_INSTIGATE_GAME = 1, BLE_FIRST_VALID_PACKET_TYPE = BLE_PACKET_TYPE_INSTIGATE_GAME, BLE_PACKET_TYPE_EVENT = 2, BLE_PACKET_TYPE_TAG = 3, BLE_PACKET_TYPE_CONSOLE = 4, BLE_PACKET_TYPE_STATUS = 5, BLE_PACKET_TYPE_PARAMETERS = 6, BLE_PACKET_TYPE_HELLO = 7, BLE_LAST_VALID_PACKET_TYPE = BLE_PACKET_TYPE_HELLO, BLE_PACKET_TYPE_UNKNOWN } BLE_PacketType_T; typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; uint8_t data[BLE_KTAG_PACKET_DATA_SIZE]; } __attribute__((packed, aligned(1))) BLE_GenericPacketType_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_INSTIGATE_GAME. typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; uint32_t game_length_in_ms; uint32_t time_remaining_until_countdown_in_ms; uint8_t unused[13]; } __attribute__((packed, aligned(1))) BLE_InstigationPacket_T; typedef enum { BLE_EVENT_NO_EVENT = 0, BLE_EVENT_CONFIGURE = 1, BLE_EVENT_CONFIGURED = 2, BLE_EVENT_WRAPUP_COMPLETE = 3, BLE_EVENT_GAME_OVER = 4, BLE_EVENT_QUIET = 5, BLE_EVENT_UNQUIET = 6, BLE_EVENT_FORCE_STATE = 7, BLE_EVENT_UNUSED = 0xFFFFFFFF } BLE_EventID_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_EVENT. typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; uint8_t target_BD_ADDR[BD_ADDR_SIZE]; uint32_t event_ID; uint32_t event_data; uint8_t unused[7]; } __attribute__((packed, aligned(1))) BLE_EventPacket_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_TAG. typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; uint8_t tx_power_level; uint8_t protocol; uint8_t team_ID; uint8_t player_ID; int16_t damage; color_t color; uint8_t target_BD_ADDR[BD_ADDR_SIZE]; uint8_t unused[5]; } __attribute__((packed, aligned(1))) BLE_TagPacket_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_CONSOLE. typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; uint8_t console_data[BLE_KTAG_PACKET_DATA_SIZE]; } __attribute__((packed, aligned(1))) BLE_ConsolePacket_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_STATUS. typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; int8_t tx_power_level; uint8_t protocol; uint8_t team_ID; uint8_t player_ID; uint16_t health; uint16_t maximum_health; color_t primary_color; color_t secondary_color; uint8_t SystemK_top_level_state; // StateID_T uint8_t unused[4]; } __attribute__((packed, aligned(1))) BLE_StatusPacket_T; typedef enum { BLE_REQUEST_CURRENT_PARAMETER_INFORMATION = 0x00, BLE_CURRENT_PARAMETER_INFORMATION = 0x01, BLE_REQUEST_PARAMETER_CHANGE = 0x02, BLE_ACKNOWLEDGE_PARAMETER_CHANGE = 0x03, BLE_ERROR_CHANGING_PARAMETERS = 0x04, BLE_ERROR_RESPONDING_TO_REQUEST = 0xFF } BLE_ConfigurationSubtype_T; typedef enum { BLE_PARAMETER_KEY_NONE = 0, BLE_PARAMETER_KEY_TEAM_ID = 1, BLE_PARAMETER_KEY_PLAYER_ID = 2, BLE_PARAMETER_KEY_GAME_LENGTH = 3, BLE_PARAMETER_KEY_MAX_HEALTH = 4, BLE_PARAMETER_KEY_SECONDARY_COLOR = 5, BLE_PARAMETER_KEY_SPECIAL_WEAPONS_ON_REENTRY = 6, BLE_FIRST_VALID_CONFIGURATION_KEY = BLE_PARAMETER_KEY_TEAM_ID, BLE_LAST_VALID_CONFIGURATION_KEY = BLE_PARAMETER_KEY_SPECIAL_WEAPONS_ON_REENTRY, BLE_PARAMETER_KEY_SHOTS_FIRED_THIS_GAME = 10001, BLE_PARAMETER_KEY_TAGS_RECEIVED_THIS_GAME = 10002, BLE_PARAMETER_KEY_TIMES_TAGGED_OUT_THIS_GAME = 10003, BLE_FIRST_VALID_GAME_RESULT_KEY = BLE_PARAMETER_KEY_SHOTS_FIRED_THIS_GAME, BLE_LAST_VALID_GAME_RESULT_KEY = BLE_PARAMETER_KEY_TIMES_TAGGED_OUT_THIS_GAME, BLE_PARAMETER_KEY_UNUSED = 65535 } BLE_ParameterKey_T; inline BLE_ParameterKey_T BLE_GetValidConfigKey(uint16_t key) { BLE_ParameterKey_T result = BLE_PARAMETER_KEY_NONE; if ((key >= BLE_FIRST_VALID_CONFIGURATION_KEY) && (key <= BLE_LAST_VALID_CONFIGURATION_KEY)) { result = (BLE_ParameterKey_T)key; } return result; } inline BLE_ParameterKey_T BLE_GetValidGameResultKey(uint16_t key) { BLE_ParameterKey_T result = BLE_PARAMETER_KEY_NONE; if ((key >= BLE_FIRST_VALID_GAME_RESULT_KEY) && (key <= BLE_LAST_VALID_GAME_RESULT_KEY)) { result = (BLE_ParameterKey_T)key; } return result; } //! Contents of the BLE packet #BLE_PACKET_TYPE_PARAMETERS. typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; uint8_t target_BD_ADDR[BD_ADDR_SIZE]; uint8_t subtype; uint16_t key_one; uint32_t value_one; uint16_t key_two; uint32_t value_two; uint8_t unused[2]; } __attribute__((packed, aligned(1))) BLE_ParametersPacket_T; typedef enum { BLE_DEVICE_TYPE_LITTLE_BOY_BLUE = 0x0000, BLE_DEVICE_TYPE_2020TPC = 0x0001, BLE_DEVICE_TYPE_MOBILE_APP = 0x0002, BLE_DEVICE_TYPE_32ESPECIAL = 0x0003, BLE_DEVICE_TYPE_UNKNOWN = 0xFFFF } BLE_DeviceType_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_HELLO. typedef struct { BLE_PacketType_T type; uint8_t BD_ADDR[BD_ADDR_SIZE]; int8_t RSSI; uint8_t event_number; uint8_t SystemK_major_version; uint8_t SystemK_minor_version; uint16_t device_type; uint8_t team_ID; uint8_t device_name[SYSTEMK_MAX_CHARS_IN_DEVICE_NAME]; } __attribute__((packed, aligned(1))) BLE_HelloPacket_T; typedef union { BLE_GenericPacketType_T Generic; BLE_InstigationPacket_T Instigation; BLE_EventPacket_T Event; BLE_TagPacket_T Tag; BLE_ConsolePacket_T Console; BLE_StatusPacket_T Status; BLE_ParametersPacket_T Configuration; BLE_HelloPacket_T Hello; } BLE_Packet_T; /* Include Files */ /* Public Variables */ /* Public Functions */ inline void BLE_FreePacketBuffer(BLE_GenericPacketType_T *buffer) { if (buffer != NULL) { buffer->type = BLE_PACKET_TYPE_BUFFER_FREE; } } void BLE_InitPacketBuffers(void); BLE_Packet_T *BLE_DecodeKTagPacket(const uint8_t *received_data, uint8_t received_data_length, uint8_t peer_BD_ADDR[BD_ADDR_SIZE], int8_t rssi_in_dBm); void BLE_UpdateInstigationPacket(uint32_t Game_Length_in_ms, uint32_t Time_Remaining_Until_Countdown_in_ms); void BLE_UpdateStatusPacket(uint8_t current_state); void BLE_UpdateTagPacket(int16_t damage, color_t color, uint8_t target_BD_ADDR[BD_ADDR_SIZE]); void BLE_RespondToConfigurationPacket(const BLE_ParametersPacket_T *const packet, BLE_ConfigurationSubtype_T response); void BLE_BroadcastCurrentParameterInfoPacket(const BLE_ParameterKey_T key_one, const uint32_t value_one, const BLE_ParameterKey_T key_two, const uint32_t value_two); void BLE_UpdateHelloPacket(); bool BLE_IsBLEPacketForMe(const uint8_t BD_ADDR[BD_ADDR_SIZE]); #ifdef __cplusplus } #endif #endif // BLE_PACKETS_H