From bfcdf4c354ae6c96165e11e2fd6d52d0c8ab91eb Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sun, 8 Jun 2025 21:52:29 +0000 Subject: [PATCH] Reworked BLE according to v0.11 of the KTag Beacon Specification (#2) This was done to support the new KTag Konfigurator app, which Jack created for his Senior Design project. Co-authored-by: Joe Kearney Reviewed-on: https://git.ktag.clubk.club/Software/SystemK/pulls/2 --- BLE/BLE_HW_Interface.h | 1 + BLE/BLE_Packet_Tracker.c | 5 +- BLE/BLE_Packets.c | 202 ++++++++++++++-- BLE/BLE_Packets.h | 163 +++++++++++-- BLE/BLE_Utils.c | 54 +++++ BLE/BLE_Utils.h | 24 ++ CMakeLists.txt | 1 + Events/KEvents.h | 2 + Game/Game.c | 3 +- Game/Game.h | 66 +++++- Game/Weapons.c | 2 +- Protocols/NEC.c | 4 +- Settings/Settings_Interface.h | 11 +- States/Playing/State_Playing.c | 38 +-- States/Playing/State_Playing__Interacting.c | 26 ++- States/Playing/State_Playing__Tagged_Out.c | 37 ++- .../State_Starting_Game__Counting_Down.c | 15 +- .../State_Starting_Game__Instigating.c | 4 + .../State_Starting_Game__Responding.c | 1 + States/State_Configuring.c | 219 +++++++++++++++++- States/State_Initializing.c | 13 +- States/State_Machine.c | 80 ++++++- States/State_Machine.h | 24 +- States/State_Ready.c | 8 +- States/State_Wrapping_Up.c | 37 ++- SystemK.h | 5 + 26 files changed, 917 insertions(+), 128 deletions(-) create mode 100644 BLE/BLE_Utils.c create mode 100644 BLE/BLE_Utils.h diff --git a/BLE/BLE_HW_Interface.h b/BLE/BLE_HW_Interface.h index 6b3f31c..7a9759e 100644 --- a/BLE/BLE_HW_Interface.h +++ b/BLE/BLE_HW_Interface.h @@ -25,5 +25,6 @@ SystemKResult_T BLE_GetMyAddress(uint8_t * BD_ADDR); SystemKResult_T BLE_ScanAndAdvertise(void); SystemKResult_T BLE_SetAdvertisingData(BLE_AdvertisingData_T * data); +SystemKResult_T BLE_StopAdvertising(void); #endif // BLE_HW_INTERFACE_H diff --git a/BLE/BLE_Packet_Tracker.c b/BLE/BLE_Packet_Tracker.c index 7f1ff2d..11f698a 100644 --- a/BLE/BLE_Packet_Tracker.c +++ b/BLE/BLE_Packet_Tracker.c @@ -49,11 +49,14 @@ static PacketTracker_T Tracker = .head = 0, }; -// A packet is _new_ if the combination of BLE adress, type, and event number have not been seen recently. +// A packet is _new_ if the combination of BLE address, type, and event number have not been seen recently. bool BLE_IsPacketNew(const uint8_t *sender_BD_ADDR, BLE_PacketType_T packet_type, uint8_t event_number) { + //esp_log_level_set("BLE", ESP_LOG_DEBUG); + //KLOG_DEBUG("BLE", "Packet from %s", BLE_ADDR_To_Str(sender_BD_ADDR)); + // Check if the packet already exists in the tracker. for (int i = 0; i < Tracker.count; i++) { diff --git a/BLE/BLE_Packets.c b/BLE/BLE_Packets.c index c2cc0a9..b150e6f 100644 --- a/BLE/BLE_Packets.c +++ b/BLE/BLE_Packets.c @@ -147,17 +147,19 @@ void BLE_UpdateInstigationPacket(uint32_t Game_Length_in_ms, uint32_t Time_Remai } } -void BLE_UpdateStatusPacket() +void BLE_UpdateStatusPacket(uint8_t current_state) { static uint8_t EventNumber = 0; uint8_t team_ID; uint8_t player_ID; uint8_t weapon_ID; + uint32_t secondary_color; Protocol_T protocol; (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_TEAMID, &team_ID); (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_PLAYERID, &player_ID); (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_WEAPONID, &weapon_ID); + (void) SETTINGS_get_uint32_t(SYSTEMK_SETTING_SECONDARY_COLOR, &secondary_color); protocol = GetWeaponFromID(weapon_ID).Protocol; uint32_t Team_Color = (uint32_t)PROTOCOLS_GetColor(protocol, team_ID, player_ID); @@ -180,17 +182,17 @@ void BLE_UpdateStatusPacket() Advertising_Data.data[13] = player_ID; Advertising_Data.data[14] = Get_Health(); Advertising_Data.data[15] = 0x00; - Advertising_Data.data[16] = MAX_HEALTH; + Advertising_Data.data[16] = Get_Max_Health(); Advertising_Data.data[17] = 0x00; Advertising_Data.data[18] = (Team_Color >> 0) & 0xFF; Advertising_Data.data[19] = (Team_Color >> 8) & 0xFF; Advertising_Data.data[20] = (Team_Color >> 16) & 0xFF; Advertising_Data.data[21] = (Team_Color >> 24) & 0xFF; - Advertising_Data.data[22] = (Team_Color >> 0) & 0xFF; // Secondary Color - Advertising_Data.data[23] = (Team_Color >> 8) & 0xFF; // Secondary Color - Advertising_Data.data[24] = (Team_Color >> 16) & 0xFF; // Secondary Color - Advertising_Data.data[25] = (Team_Color >> 24) & 0xFF; // Secondary Color - Advertising_Data.data[26] = 0xFF; + Advertising_Data.data[22] = (secondary_color >> 0) & 0xFF; + Advertising_Data.data[23] = (secondary_color >> 8) & 0xFF; + Advertising_Data.data[24] = (secondary_color >> 16) & 0xFF; + Advertising_Data.data[25] = (secondary_color >> 24) & 0xFF; + Advertising_Data.data[26] = current_state; Advertising_Data.data[27] = 0xFF; Advertising_Data.data[28] = 0xFF; Advertising_Data.data[29] = 0xFF; @@ -237,12 +239,12 @@ void BLE_UpdateTagPacket(int16_t damage, color_t color, uint8_t target_BD_ADDR[B Advertising_Data.data[17] = (color >> 8) & 0xFF; Advertising_Data.data[18] = (color >> 16) & 0xFF; Advertising_Data.data[19] = (color >> 24) & 0xFF; - Advertising_Data.data[20] = target_BD_ADDR[0], - Advertising_Data.data[21] = target_BD_ADDR[1], - Advertising_Data.data[22] = target_BD_ADDR[2], - Advertising_Data.data[23] = target_BD_ADDR[3], - Advertising_Data.data[24] = target_BD_ADDR[4], - Advertising_Data.data[25] = target_BD_ADDR[5], + Advertising_Data.data[20] = target_BD_ADDR[0]; + Advertising_Data.data[21] = target_BD_ADDR[1]; + Advertising_Data.data[22] = target_BD_ADDR[2]; + Advertising_Data.data[23] = target_BD_ADDR[3]; + Advertising_Data.data[24] = target_BD_ADDR[4]; + Advertising_Data.data[25] = target_BD_ADDR[5]; Advertising_Data.data[26] = 0xFF; Advertising_Data.data[27] = 0xFF; Advertising_Data.data[28] = 0xFF; @@ -257,6 +259,168 @@ void BLE_UpdateTagPacket(int16_t damage, color_t color, uint8_t target_BD_ADDR[B } } +//! Event number used for all BLE_PACKET_TYPE_PARAMETERS packets. +static uint8_t ParametersEventNumber = 0; + +void BLE_RespondToConfigurationPacket(const BLE_ParametersPacket_T *const packet, BLE_ConfigurationSubtype_T response) +{ + Advertising_Data.length = BLE_KTAG_PACKET_TOTAL_SIZE; + + // Manufacturer Specific Data + Advertising_Data.data[0] = 0x1E; + Advertising_Data.data[1] = 0xFF; + Advertising_Data.data[2] = 0xFF; + Advertising_Data.data[3] = 0xFF; + Advertising_Data.data[4] = 'K'; + Advertising_Data.data[5] = 'T'; + Advertising_Data.data[6] = 'a'; + Advertising_Data.data[7] = 'g'; + Advertising_Data.data[8] = BLE_PACKET_TYPE_PARAMETERS; + Advertising_Data.data[9] = ParametersEventNumber++; + Advertising_Data.data[10] = packet->BD_ADDR[0]; + Advertising_Data.data[11] = packet->BD_ADDR[1]; + Advertising_Data.data[12] = packet->BD_ADDR[2]; + Advertising_Data.data[13] = packet->BD_ADDR[3]; + Advertising_Data.data[14] = packet->BD_ADDR[4]; + Advertising_Data.data[15] = packet->BD_ADDR[5]; + Advertising_Data.data[16] = (uint8_t)response; + Advertising_Data.data[17] = (uint8_t)((packet->key_one >> 0) & 0xFF); + Advertising_Data.data[18] = (uint8_t)((packet->key_one >> 8) & 0xFF); + Advertising_Data.data[19] = (uint8_t)((packet->value_one >> 0) & 0xFF); + Advertising_Data.data[20] = (uint8_t)((packet->value_one >> 8) & 0xFF); + Advertising_Data.data[21] = (uint8_t)((packet->value_one >> 16) & 0xFF); + Advertising_Data.data[22] = (uint8_t)((packet->value_one >> 24) & 0xFF); + Advertising_Data.data[23] = (uint8_t)((packet->key_two >> 0) & 0xFF); + Advertising_Data.data[24] = (uint8_t)((packet->key_two >> 8) & 0xFF); + Advertising_Data.data[25] = (uint8_t)((packet->value_two >> 0) & 0xFF); + Advertising_Data.data[26] = (uint8_t)((packet->value_two >> 8) & 0xFF); + Advertising_Data.data[27] = (uint8_t)((packet->value_two >> 16) & 0xFF); + Advertising_Data.data[28] = (uint8_t)((packet->value_two >> 24) & 0xFF); + Advertising_Data.data[29] = 0xFF; + Advertising_Data.data[30] = 0xFF; + + SystemKResult_T result = BLE_SetAdvertisingData(&Advertising_Data); + + if (result != SYSTEMK_RESULT_SUCCESS) + { + KLOG_ERROR(KLOG_TAG, "Error responding to configuration packet!"); + } + + if (BLE_ScanAndAdvertise() != SYSTEMK_RESULT_SUCCESS) + { + KLOG_ERROR(KLOG_TAG, "Couldn't scan and advertise!"); + } +} + +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) +{ + Advertising_Data.length = BLE_KTAG_PACKET_TOTAL_SIZE; + + // Manufacturer Specific Data + Advertising_Data.data[0] = 0x1E; + Advertising_Data.data[1] = 0xFF; + Advertising_Data.data[2] = 0xFF; + Advertising_Data.data[3] = 0xFF; + Advertising_Data.data[4] = 'K'; + Advertising_Data.data[5] = 'T'; + Advertising_Data.data[6] = 'a'; + Advertising_Data.data[7] = 'g'; + Advertising_Data.data[8] = BLE_PACKET_TYPE_PARAMETERS; + Advertising_Data.data[9] = ParametersEventNumber++; + Advertising_Data.data[10] = BLE_BROADCAST_ADDRESS[0]; + Advertising_Data.data[11] = BLE_BROADCAST_ADDRESS[1]; + Advertising_Data.data[12] = BLE_BROADCAST_ADDRESS[2]; + Advertising_Data.data[13] = BLE_BROADCAST_ADDRESS[3]; + Advertising_Data.data[14] = BLE_BROADCAST_ADDRESS[4]; + Advertising_Data.data[15] = BLE_BROADCAST_ADDRESS[5]; + Advertising_Data.data[16] = BLE_CURRENT_PARAMETER_INFORMATION; + Advertising_Data.data[17] = (uint8_t)((key_one >> 0) & 0xFF); + Advertising_Data.data[18] = (uint8_t)((key_one >> 8) & 0xFF); + Advertising_Data.data[19] = (uint8_t)((value_one >> 0) & 0xFF); + Advertising_Data.data[20] = (uint8_t)((value_one >> 8) & 0xFF); + Advertising_Data.data[21] = (uint8_t)((value_one >> 16) & 0xFF); + Advertising_Data.data[22] = (uint8_t)((value_one >> 24) & 0xFF); + Advertising_Data.data[23] = (uint8_t)((key_two >> 0) & 0xFF); + Advertising_Data.data[24] = (uint8_t)((key_two >> 8) & 0xFF); + Advertising_Data.data[25] = (uint8_t)((value_two >> 0) & 0xFF); + Advertising_Data.data[26] = (uint8_t)((value_two >> 8) & 0xFF); + Advertising_Data.data[27] = (uint8_t)((value_two >> 16) & 0xFF); + Advertising_Data.data[28] = (uint8_t)((value_two >> 24) & 0xFF); + Advertising_Data.data[29] = 0xFF; + Advertising_Data.data[30] = 0xFF; + + SystemKResult_T result = BLE_SetAdvertisingData(&Advertising_Data); + + if (result != SYSTEMK_RESULT_SUCCESS) + { + KLOG_ERROR(KLOG_TAG, "Error responding to configuration packet!"); + } +} + +void BLE_UpdateHelloPacket() +{ + static uint8_t EventNumber = 0; + + uint32_t device_type32; + uint16_t device_type = BLE_DEVICE_TYPE_UNKNOWN; + if (SETTINGS_get_uint32_t(SYSTEMK_SETTING_DEVICE_TYPE, &device_type32) == SYSTEMK_RESULT_SUCCESS) + { + device_type = (uint16_t)device_type32; + } + + uint8_t team_ID; + (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_TEAMID, &team_ID); + + char device_name[SYSTEMK_MAX_CHARS_IN_DEVICE_NAME + 1]; + SystemKResult_T result = SETTINGS_get_device_name(&device_name[0]); + if (result != SYSTEMK_RESULT_SUCCESS) + { + strcpy(device_name, "Anonymous"); + } + + Advertising_Data.length = BLE_KTAG_PACKET_TOTAL_SIZE; + + // Manufacturer Specific Data + Advertising_Data.data[0] = 0x1E; + Advertising_Data.data[1] = 0xFF; + Advertising_Data.data[2] = 0xFF; + Advertising_Data.data[3] = 0xFF; + Advertising_Data.data[4] = 'K'; + Advertising_Data.data[5] = 'T'; + Advertising_Data.data[6] = 'a'; + Advertising_Data.data[7] = 'g'; + Advertising_Data.data[8] = BLE_PACKET_TYPE_HELLO; + Advertising_Data.data[9] = EventNumber++; + Advertising_Data.data[10] = SYSTEMK_MAJOR_VERSION; + Advertising_Data.data[11] = SYSTEMK_MINOR_VERSION; + Advertising_Data.data[12] = (device_type >> 0) & 0xFF; + Advertising_Data.data[13] = (device_type >> 8) & 0xFF; + Advertising_Data.data[14] = team_ID; + Advertising_Data.data[15] = device_name[0]; + Advertising_Data.data[16] = device_name[1]; + Advertising_Data.data[17] = device_name[2]; + Advertising_Data.data[18] = device_name[3]; + Advertising_Data.data[19] = device_name[4]; + Advertising_Data.data[20] = device_name[5]; + Advertising_Data.data[21] = device_name[6]; + Advertising_Data.data[22] = device_name[7]; + Advertising_Data.data[23] = device_name[8]; + Advertising_Data.data[24] = device_name[9]; + Advertising_Data.data[25] = device_name[10]; + Advertising_Data.data[26] = device_name[11]; + Advertising_Data.data[27] = device_name[12]; + Advertising_Data.data[28] = device_name[13]; + Advertising_Data.data[29] = device_name[14]; + Advertising_Data.data[30] = device_name[15]; + + result = BLE_SetAdvertisingData(&Advertising_Data); + + if (result != SYSTEMK_RESULT_SUCCESS) + { + KLOG_ERROR(KLOG_TAG, "Error updating hello packet!"); + } +} + bool BLE_IsBLEPacketForMe(const uint8_t BD_ADDR[6]) { bool for_me = false; @@ -286,12 +450,12 @@ bool BLE_IsBLEPacketForMe(const uint8_t BD_ADDR[6]) } // Is this the broadcast address? - if ((BD_ADDR[0] == 0xFF) && - (BD_ADDR[1] == 0xFF) && - (BD_ADDR[2] == 0xFF) && - (BD_ADDR[3] == 0xFF) && - (BD_ADDR[4] == 0xFF) && - (BD_ADDR[5] == 0xFF)) + if ((BD_ADDR[0] == BLE_BROADCAST_ADDRESS[0]) && + (BD_ADDR[1] == BLE_BROADCAST_ADDRESS[1]) && + (BD_ADDR[2] == BLE_BROADCAST_ADDRESS[2]) && + (BD_ADDR[3] == BLE_BROADCAST_ADDRESS[3]) && + (BD_ADDR[4] == BLE_BROADCAST_ADDRESS[4]) && + (BD_ADDR[5] == BLE_BROADCAST_ADDRESS[5])) { for_me = true; } diff --git a/BLE/BLE_Packets.h b/BLE/BLE_Packets.h index d1f0a03..48a68ae 100644 --- a/BLE/BLE_Packets.h +++ b/BLE/BLE_Packets.h @@ -29,7 +29,8 @@ #define BLE_PACKETS_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* Preprocessor and Type Definitions */ @@ -59,11 +60,13 @@ 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_JOIN_NOW = 2, + BLE_PACKET_TYPE_EVENT = 2, BLE_PACKET_TYPE_TAG = 3, BLE_PACKET_TYPE_CONSOLE = 4, BLE_PACKET_TYPE_STATUS = 5, - BLE_LAST_VALID_PACKET_TYPE = BLE_PACKET_TYPE_STATUS, + 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; @@ -73,7 +76,7 @@ typedef struct 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; @@ -84,25 +87,35 @@ typedef struct 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 random_time_after_countdown_in_ms_x100; - uint8_t unused[12]; + uint8_t unused[13]; } __attribute__((packed, aligned(1))) BLE_InstigationPacket_T; -//! Contents of the BLE packet #BLE_PACKET_TYPE_JOIN_NOW. +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_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; - - uint32_t game_length_in_ms; - uint32_t time_remaining_in_game_in_ms; - uint8_t unused[13]; -} __attribute__((packed, aligned(1))) BLE_JoinNowPacket_T; + + 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 @@ -120,7 +133,7 @@ typedef struct color_t color; uint8_t target_BD_ADDR[BD_ADDR_SIZE]; uint8_t unused[5]; -} __attribute__((packed, aligned(1)))BLE_TagPacket_T; +} __attribute__((packed, aligned(1))) BLE_TagPacket_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_CONSOLE. typedef struct @@ -129,9 +142,9 @@ typedef struct 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; +} __attribute__((packed, aligned(1))) BLE_ConsolePacket_T; //! Contents of the BLE packet #BLE_PACKET_TYPE_STATUS. typedef struct @@ -140,7 +153,7 @@ typedef struct 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; @@ -149,17 +162,116 @@ typedef struct uint16_t maximum_health; color_t primary_color; color_t secondary_color; - uint8_t unused[5]; -} __attribute__((packed, aligned(1)))BLE_StatusPacket_T; + 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_JoinNowPacket_T JoinNow; + 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 */ @@ -168,20 +280,23 @@ typedef union /* Public Functions */ -inline void BLE_FreePacketBuffer(void * buffer) +inline void BLE_FreePacketBuffer(BLE_GenericPacketType_T *buffer) { if (buffer != NULL) { - ((BLE_GenericPacketType_T *)buffer)->type = BLE_PACKET_TYPE_BUFFER_FREE; + 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); +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(); +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 diff --git a/BLE/BLE_Utils.c b/BLE/BLE_Utils.c new file mode 100644 index 0000000..a0030f4 --- /dev/null +++ b/BLE/BLE_Utils.c @@ -0,0 +1,54 @@ +/* + * This program source code file is part of SystemK, a library in the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 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 + +const uint8_t BLE_BROADCAST_ADDRESS[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + //! Converts a 6-byte Bluetooth Low Energy address to a human-readable string (for logging). + /*! + * \param bd_addr The Bluetooth address as a 6-byte array + * \return Pointer to a static string containing the formatted address + * + * Output format: "XX:XX:XX:XX:XX:XX" where XX are uppercase hexadecimal values + * \note This function is not reentrant as it uses a static buffer! + */ +const char *BLE_ADDR_To_Str(const uint8_t bd_addr[6]) +{ + static char str_addr[18]; // 17 characters + null terminator + + // Convert each byte and add separating colons. + for (int i = 0; i < 6; i++) + { + snprintf(&str_addr[i * 3], sizeof(str_addr) - (i * 3), "%02X", bd_addr[5-i]); + + // Add colon separator except after the last byte. + if (i < 5) + { + str_addr[(i * 3) + 2] = ':'; + } + } + + str_addr[17] = '\0'; // Ensure null termination. + return str_addr; +} \ No newline at end of file diff --git a/BLE/BLE_Utils.h b/BLE/BLE_Utils.h new file mode 100644 index 0000000..84837df --- /dev/null +++ b/BLE/BLE_Utils.h @@ -0,0 +1,24 @@ +/* + * This program source code file is part of SystemK, a library in the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 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 . + */ + + extern const uint8_t BLE_BROADCAST_ADDRESS[6]; + + const char* BLE_ADDR_To_Str(const uint8_t bd_addr[6]); \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index c04f98e..c9e2bb9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ idf_component_register( SRCS "BLE/BLE_Packets.c" "BLE/BLE_Packet_Tracker.c" + "BLE/BLE_Utils.c" "Events/KEvents.c" "Game/Game.c" "Game/Weapons.c" diff --git a/Events/KEvents.h b/Events/KEvents.h index a992606..027a733 100755 --- a/Events/KEvents.h +++ b/Events/KEvents.h @@ -79,6 +79,8 @@ typedef enum KEVENT_AUDIO_COMPLETED = 36, KEVENT_GAME_OVER = 37, KEVENT_PLAY_PRESSED_ON_REMOTE = 38, + //! For #KEVENT_BLE_EVENT_RECEIVED, #KEvent_T::Data contains the BLE_EventID_T of the received event. + KEVENT_BLE_EVENT_RECEIVED = 39, // KEVENT_IS_OUT_OF_RANGE is one more than the last valid event. KEVENT_IS_OUT_OF_RANGE } KEvent_ID_T; diff --git a/Game/Game.c b/Game/Game.c index 8fa8744..3ba634f 100644 --- a/Game/Game.c +++ b/Game/Game.c @@ -23,7 +23,8 @@ KTag_Game_Data_T KTAG_Game_Data = { - .My_Health = MAX_HEALTH, + .My_Health = 0, + .Max_Health = 0, .My_Weapon = TEST_PATTERN_ID, .My_Shield_Strength = 100, .Time_Remaining_in_Game_in_ms = UINT32_MAX, diff --git a/Game/Game.h b/Game/Game.h index a9ca257..fabef8d 100644 --- a/Game/Game.h +++ b/Game/Game.h @@ -24,8 +24,6 @@ #include "Weapons.h" -#define MAX_HEALTH 10 - //! Implemented according to the 2024-07-20 "KTag Teams Compatibility Matrix". typedef enum { @@ -44,6 +42,18 @@ typedef enum MAXIMUM_TEAM_ID = 7 } TeamID_t; +inline bool Is_Valid_Team_ID(uint8_t team_ID) +{ + bool result = false; + + if (team_ID <= MAXIMUM_TEAM_ID) + { + result = true; + } + + return result; +} + __attribute__((always_inline)) static inline SystemKResult_T Set_Team_With_Audio_Feedback(uint8_t team_ID) { static uint8_t Team_ID = 0; // This is static because AUDIO_PRONOUNCE_NUMBER_0_TO_100 needs a *pointer*. @@ -77,6 +87,27 @@ __attribute__((always_inline)) inline TeamID_t Resolve_Common_Team_ID(uint8_t te return (team_ID & COMMON_TEAM_ID_MASK); } +__attribute__((always_inline)) static inline SystemKResult_T Set_Player_With_Audio_Feedback(uint8_t player_ID) +{ + static uint8_t Player_ID = 0; // This is static because AUDIO_PRONOUNCE_NUMBER_0_TO_100 needs a *pointer*. + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + + Player_ID = player_ID; + + result = SETTINGS_set_uint8_t(SYSTEMK_SETTING_PLAYERID, Player_ID); + + if (result == SYSTEMK_RESULT_SUCCESS) + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_PLAYER_ID_PROMPT, .Play_To_Completion = true, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + + AudioAction_T volume_action = {.ID = AUDIO_PRONOUNCE_NUMBER_0_TO_100, .Play_To_Completion = true, .Data = (void *)&Player_ID}; + Perform_Audio_Action(&volume_action); + } + + return result; +} + __attribute__((always_inline)) inline bool Team_Can_Tag_Me(uint8_t tagging_team_ID) { bool can_tag = false; @@ -104,6 +135,7 @@ typedef struct uint8_t My_Health; WeaponID_t My_Weapon; uint8_t My_Shield_Strength; + uint8_t Max_Health; uint32_t Time_Remaining_in_Game_in_ms; uint32_t Time_Remaining_Until_Countdown_in_ms; uint16_t Shots_Fired; @@ -130,6 +162,36 @@ __attribute__((always_inline)) inline void Set_Health(uint8_t health) } } +__attribute__((always_inline)) inline uint8_t Get_Max_Health() +{ + if (KTAG_Game_Data.Max_Health == 0) + { + // Initialize from settings. + uint8_t max_health; + if (SETTINGS_get_uint8_t(SYSTEMK_SETTING_MAX_HEALTH, &max_health) == SYSTEMK_RESULT_SUCCESS) + { + KTAG_Game_Data.Max_Health = max_health; + } + else + { + KTAG_Game_Data.Max_Health = 100; + } + } + + return KTAG_Game_Data.Max_Health; +} + +__attribute__((always_inline)) inline void Set_Max_Health(uint8_t health) +{ + KTAG_Game_Data.Max_Health = health; + + // Limit current health to max health. + if (KTAG_Game_Data.My_Health > health) + { + KTAG_Game_Data.My_Health = health; + } +} + __attribute__((always_inline)) inline void Reduce_Health(uint8_t reduction) { if (reduction < KTAG_Game_Data.My_Health) diff --git a/Game/Weapons.c b/Game/Weapons.c index f90f523..52da364 100644 --- a/Game/Weapons.c +++ b/Game/Weapons.c @@ -158,7 +158,7 @@ Weapon_t WeaponsByID[NUMBER_OF_WEAPONS] = // The Dubuque Protocol { - .ID = LASER_X_ID, + .ID = DUBUQUE_PROTOCOL_ID, .Type = ENERGY, .Protocol = DUBUQUE_PROTOCOL, .Damage_Per_Shot = 1, diff --git a/Protocols/NEC.c b/Protocols/NEC.c index 263fa7e..4e10e30 100755 --- a/Protocols/NEC.c +++ b/Protocols/NEC.c @@ -109,9 +109,9 @@ static inline void PackPulseTrain(TimedPulseTrain_T *pulsetrain, uint32_t data) TimedPulseTrain_T *NEC_EncodePacket(CommandPacket_T *packet) { - uint32_t packed_data = 0x00000000; + uint32_t data = packet->data; - PackPulseTrain(&Command_Send_Buffer, packed_data); + PackPulseTrain(&Command_Send_Buffer, data); return &Command_Send_Buffer; } diff --git a/Settings/Settings_Interface.h b/Settings/Settings_Interface.h index 4f80805..e5fa376 100644 --- a/Settings/Settings_Interface.h +++ b/Settings/Settings_Interface.h @@ -21,21 +21,30 @@ #ifndef SETTINGS_INTERFACE_H #define SETTINGS_INTERFACE_H + +#define SYSTEMK_MAX_CHARS_IN_DEVICE_NAME 16 typedef enum { + SYSTEMK_SETTING_DEVICE_TYPE, SYSTEMK_SETTING_IS_RIGHT_HANDED, SYSTEMK_SETTING_AUDIO_VOLUME, SYSTEMK_SETTING_TEAMID, SYSTEMK_SETTING_PLAYERID, SYSTEMK_SETTING_WEAPONID, - SYSTEMK_SETTING_T_START_GAME_in_ms + SYSTEMK_SETTING_MAX_HEALTH, + SYSTEMK_SETTING_N_SPECIAL_WEAPONS_ON_REENTRY, + SYSTEMK_SETTING_T_START_GAME_in_ms, + SYSTEMK_SETTING_T_GAME_LENGTH_in_ms, + SYSTEMK_SETTING_SECONDARY_COLOR } SystemKSettingID_T; SystemKResult_T SETTINGS_get_uint8_t(SystemKSettingID_T id, uint8_t * value); SystemKResult_T SETTINGS_set_uint8_t(SystemKSettingID_T id, uint8_t value); SystemKResult_T SETTINGS_get_uint32_t(SystemKSettingID_T id, uint32_t * value); SystemKResult_T SETTINGS_set_uint32_t(SystemKSettingID_T id, uint32_t value); +SystemKResult_T SETTINGS_get_device_name(char* name); +SystemKResult_T SETTINGS_set_device_name(char* name); SystemKResult_T SETTINGS_Save(void); #endif // SETTINGS_INTERFACE_H diff --git a/States/Playing/State_Playing.c b/States/Playing/State_Playing.c index 832d2c1..b65b99f 100644 --- a/States/Playing/State_Playing.c +++ b/States/Playing/State_Playing.c @@ -37,7 +37,8 @@ static const int_fast8_t TAG_RSSI_THRESHOLD = -75; static void BLEStatusTimerCallback(TimerHandle_t xTimer) { - BLE_UpdateStatusPacket(); + StateMachineContext_T* context = GetContext(); + BLE_UpdateStatusPacket(context->States.Current_State); } static void GameDurationTimerCallback(TimerHandle_t xTimer) @@ -60,7 +61,7 @@ void Playing_Entry(StateMachineContext_T *context) BLE_RXd_data.neighbors[slot].TimeToLive_in_ms = 0; } - BLE_UpdateStatusPacket(); + BLE_UpdateStatusPacket(context->States.Current_State); if (BLE_ScanAndAdvertise() != SYSTEMK_RESULT_SUCCESS) { KLOG_ERROR(KLOG_TAG, "Couldn't start BLE!"); @@ -92,7 +93,8 @@ void Playing_Entry(StateMachineContext_T *context) } // The timer is only needed for timed games. - if (Get_Time_Remaining_in_Game_in_ms() != UINT32_MAX) + if ((Get_Time_Remaining_in_Game_in_ms() != UINT32_MAX) && + (Get_Time_Remaining_in_Game_in_ms() != 0)) { if (GameDurationTimer == NULL) { @@ -129,7 +131,7 @@ void Playing_Exit(StateMachineContext_T *context) { LOG("Exiting the Playing state."); xTimerStop(BLEStatusTimer, portMAX_DELAY); - BLE_UpdateStatusPacket(); + BLE_UpdateStatusPacket(context->States.Next_State); } void HandleBLEStatusPacket(const BLE_StatusPacket_T *const packet) @@ -179,6 +181,8 @@ void HandleBLEStatusPacket(const BLE_StatusPacket_T *const packet) // NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_BLE_NEARBY, .Data = (void *)&BLE_RXd_data, .Prominence = NEOPIXELS_BACKGROUND}; // xQueueSend(xQueueNeoPixels, &neopixels_action, 0); + + BLE_FreePacketBuffer((BLE_GenericPacketType_T *)packet); } void HandleBLETagPacket(const BLE_TagPacket_T *const packet) @@ -202,29 +206,31 @@ void HandleBLETagPacket(const BLE_TagPacket_T *const packet) { if (BLE_IsPacketNew(packet->BD_ADDR, BLE_PACKET_TYPE_TAG, packet->event_number)) { + Health_In_Percent = (int16_t)Get_Health(); + if (packet->damage > 0) { - Reduce_Health(packet->damage); + if (Health_In_Percent > 0) + { + Reduce_Health(packet->damage); - ReceivedTagColor = packet->color; + ReceivedTagColor = packet->color; - AudioAction_T audio_action = {.ID = AUDIO_PLAY_TAG_RECEIVED, .Data = (void *)0x00}; - Perform_Audio_Action(&audio_action); + AudioAction_T audio_action = {.ID = AUDIO_PLAY_TAG_RECEIVED, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); - NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_TAG_RECEIVED, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)&ReceivedTagColor}; - xQueueSend(xQueueNeoPixels, &neopixels_action, 0); + NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_TAG_RECEIVED, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)&ReceivedTagColor}; + xQueueSend(xQueueNeoPixels, &neopixels_action, 0); + } } else if (packet->damage < 0) { - Health_In_Percent = (uint8_t)Get_Health(); Health_In_Percent -= packet->damage; - if (Health_In_Percent > MAX_HEALTH) + if (Health_In_Percent > Get_Max_Health()) { - Health_In_Percent = MAX_HEALTH; + Health_In_Percent = Get_Max_Health(); } - Health_In_Percent = MAX_HEALTH; - Set_Health(Health_In_Percent); AudioAction_T audio_action = {.ID = AUDIO_PRONOUNCE_NUMBER_0_TO_100, .Play_To_Completion = true, .Data = (void *)&Health_In_Percent}; Perform_Audio_Action(&audio_action); @@ -236,4 +242,6 @@ void HandleBLETagPacket(const BLE_TagPacket_T *const packet) } } } + + BLE_FreePacketBuffer((BLE_GenericPacketType_T *)packet); } diff --git a/States/Playing/State_Playing__Interacting.c b/States/Playing/State_Playing__Interacting.c index f8d968f..ddb9f44 100644 --- a/States/Playing/State_Playing__Interacting.c +++ b/States/Playing/State_Playing__Interacting.c @@ -60,6 +60,7 @@ static void Playing__Interacting_Entry(StateMachineContext_T * context) Playing_Entry(context); srand(xTaskGetTickCount()); } + BLE_UpdateStatusPacket(STATE_PLAYING__INTERACTING); LOG("Entering the Interacting substate of the Playing state."); } @@ -305,6 +306,10 @@ static void Playing__Interacting_Do(StateMachineContext_T * context) xQueueSend(xQueueNeoPixels, &neopixels_action, 0); Increment_Tags_Received(); + +#ifdef LOG_INTERACTING_SUBSTATE + KLOG_INFO(KLOG_TAG, "%u of %u health remaining", KTAG_Game_Data.My_Health, KTAG_Game_Data.Max_Health); +#endif // LOG_INTERACTING_SUBSTATE } } else if (player_ID != my_player_ID) @@ -344,14 +349,7 @@ static void Playing__Interacting_Do(StateMachineContext_T * context) case KEVENT_BLE_PACKET_RECEIVED: #ifdef LOG_INTERACTING_SUBSTATE - //KLOG_INFO(KLOG_TAG, "KEVENT_BLE_PACKET_RECEIVED from %02X:%02X:%02X:%02X:%02X:%02X", - // ((BLE_Packet_T *)Event.Data)->Generic.BD_ADDR[5], - // ((BLE_Packet_T *)Event.Data)->Generic.BD_ADDR[4], - // ((BLE_Packet_T *)Event.Data)->Generic.BD_ADDR[3], - // ((BLE_Packet_T *)Event.Data)->Generic.BD_ADDR[2], - // ((BLE_Packet_T *)Event.Data)->Generic.BD_ADDR[1], - // ((BLE_Packet_T *)Event.Data)->Generic.BD_ADDR[0] - //); + //KLOG_INFO(KLOG_TAG, "KEVENT_BLE_PACKET_RECEIVED from %s", BLE_ADDR_To_Str(((BLE_Packet_T *)Event.Data)->Generic.BD_ADDR)); #endif // LOG_INTERACTING_SUBSTATE if (((BLE_Packet_T *)Event.Data)->Generic.type == BLE_PACKET_TYPE_STATUS) { @@ -361,8 +359,14 @@ static void Playing__Interacting_Do(StateMachineContext_T * context) { HandleBLETagPacket((BLE_TagPacket_T *)Event.Data); } - - BLE_FreePacketBuffer(Event.Data); + else if (((BLE_Packet_T *)Event.Data)->Generic.type == BLE_PACKET_TYPE_EVENT) + { + HandleBLEEventPacket((BLE_EventPacket_T *)Event.Data, context); + } + else + { + BLE_FreePacketBuffer(Event.Data); + } break; case KEVENT_ACCESSORY_SWITCH_PRESSED: @@ -398,7 +402,7 @@ static void Playing__Interacting_Do(StateMachineContext_T * context) case KEVENT_GAME_OVER: { - AudioAction_T audio_action = {.ID = AUDIO_PLAY_GAME_OVER, .Data = (void *)0x00}; + AudioAction_T audio_action = {.ID = AUDIO_PLAY_GAME_OVER, .Play_To_Completion = true}; Perform_Audio_Action(&audio_action); Transition_For_Event(context, STATE_WRAPPING_UP, &Event); } diff --git a/States/Playing/State_Playing__Tagged_Out.c b/States/Playing/State_Playing__Tagged_Out.c index 87e445a..7ab9cd6 100644 --- a/States/Playing/State_Playing__Tagged_Out.c +++ b/States/Playing/State_Playing__Tagged_Out.c @@ -22,6 +22,22 @@ /* Include Files */ #include "SystemK.h" +static const char *KLOG_TAG = "STATE_PLAYING__TAGGED_OUT"; + +static void Reset_Bombs() +{ + uint8_t n_bombs; + if (SETTINGS_get_uint8_t(SYSTEMK_SETTING_N_SPECIAL_WEAPONS_ON_REENTRY, &n_bombs) == SYSTEMK_RESULT_SUCCESS) + { + Set_Available_Bombs(n_bombs); + } + else + { + Set_Available_Bombs(0); + KLOG_ERROR(KLOG_TAG, "Error getting available bombs!"); + } +} + static void Playing__Tagged_Out_Entry(StateMachineContext_T * context); static void Playing__Tagged_Out_Do(StateMachineContext_T * context); static void Playing__Tagged_Out_Exit(StateMachineContext_T * context); @@ -51,7 +67,7 @@ static void Playing__Tagged_Out_Entry(StateMachineContext_T * context) NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_TAGGED_OUT, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); - BLE_UpdateStatusPacket(); + BLE_UpdateStatusPacket(STATE_PLAYING__TAGGED_OUT); Increment_Times_Tagged_Out(); } @@ -78,11 +94,14 @@ static void Playing__Tagged_Out_Do(StateMachineContext_T * context) if (Back_In() == true) { - // TODO: Get this from settings. - Set_Available_Bombs(1); + Reset_Bombs(); Transition_For_Event(context, STATE_PLAYING__INTERACTING, &Event); } } + else if (((BLE_Packet_T *)Event.Data)->Generic.type == BLE_PACKET_TYPE_EVENT) + { + HandleBLEEventPacket((BLE_EventPacket_T *)Event.Data, context); + } else { BLE_FreePacketBuffer(Event.Data); @@ -97,9 +116,8 @@ static void Playing__Tagged_Out_Do(StateMachineContext_T * context) // Was it a "long" press? if (duration_of_press_in_ms > 5000) { - Set_Health(MAX_HEALTH); - // TODO: Get this from settings. - Set_Available_Bombs(1); + Set_Health(Get_Max_Health()); + Reset_Bombs(); Transition_For_Event(context, STATE_PLAYING__INTERACTING, &Event); } } @@ -107,16 +125,15 @@ static void Playing__Tagged_Out_Do(StateMachineContext_T * context) case KEVENT_GAME_OVER: { - AudioAction_T audio_action = {.ID = AUDIO_PLAY_GAME_OVER, .Data = (void *)0x00}; + AudioAction_T audio_action = {.ID = AUDIO_PLAY_GAME_OVER, .Play_To_Completion = true}; Perform_Audio_Action(&audio_action); Transition_For_Event(context, STATE_WRAPPING_UP, &Event); } break; case KEVENT_PLAY_PRESSED_ON_REMOTE: - Set_Health(MAX_HEALTH); - // TODO: Get this from settings. - Set_Available_Bombs(1); + Set_Health(Get_Max_Health()); + Reset_Bombs(); Transition_For_Event(context, STATE_PLAYING__INTERACTING, &Event); break; diff --git a/States/Starting_Game/State_Starting_Game__Counting_Down.c b/States/Starting_Game/State_Starting_Game__Counting_Down.c index da80484..e5b4164 100644 --- a/States/Starting_Game/State_Starting_Game__Counting_Down.c +++ b/States/Starting_Game/State_Starting_Game__Counting_Down.c @@ -22,6 +22,8 @@ /* Include Files */ #include "SystemK.h" +static const char *KLOG_TAG = "STARTING_GAME__COUNTING_DOWN"; + static void Starting_Game__Counting_Down_Entry(StateMachineContext_T * context); static void Starting_Game__Counting_Down_Do(StateMachineContext_T * context); static void Starting_Game__Counting_Down_Exit(StateMachineContext_T * context); @@ -48,8 +50,17 @@ static void Starting_Game__Counting_Down_Entry(StateMachineContext_T * context) Reset_Shots_Fired(); Reset_Tags_Received(); Reset_Times_Tagged_Out(); - // TODO: Get this from settings. - Set_Available_Bombs(1); + + uint8_t n_bombs; + if (SETTINGS_get_uint8_t(SYSTEMK_SETTING_N_SPECIAL_WEAPONS_ON_REENTRY, &n_bombs) == SYSTEMK_RESULT_SUCCESS) + { + Set_Available_Bombs(n_bombs); + } + else + { + Set_Available_Bombs(0); + KLOG_ERROR(KLOG_TAG, "Error getting available bombs!"); + } N_Lights_Lit = 0; AudioAction_T audio_action = {.ID = AUDIO_SILENCE, .Data = (void *)0x00}; diff --git a/States/Starting_Game/State_Starting_Game__Instigating.c b/States/Starting_Game/State_Starting_Game__Instigating.c index e4664b3..d835f61 100644 --- a/States/Starting_Game/State_Starting_Game__Instigating.c +++ b/States/Starting_Game/State_Starting_Game__Instigating.c @@ -49,6 +49,10 @@ static void Starting_Game__Instigating_Entry(StateMachineContext_T * context) Starting_Game_Entry(context); LOG("Entering the Instigating substate of the Starting Game state."); + + uint32_t game_length_in_ms; + (void) SETTINGS_get_uint32_t(SYSTEMK_SETTING_T_GAME_LENGTH_in_ms, &game_length_in_ms); + Set_Time_Remaining_Until_Countdown(game_length_in_ms); Set_Time_Remaining_in_Game(UINT32_MAX); uint32_t start_game_time_in_ms; diff --git a/States/Starting_Game/State_Starting_Game__Responding.c b/States/Starting_Game/State_Starting_Game__Responding.c index 7651254..9f17784 100644 --- a/States/Starting_Game/State_Starting_Game__Responding.c +++ b/States/Starting_Game/State_Starting_Game__Responding.c @@ -56,6 +56,7 @@ static void Starting_Game__Responding_Entry(StateMachineContext_T * context) { uint32_t game_length_in_ms = ((BLE_Packet_T *)context->Cause_Of_Transition->Data)->Instigation.game_length_in_ms; Set_Time_Remaining_in_Game(game_length_in_ms); + (void) SETTINGS_set_uint32_t(SYSTEMK_SETTING_T_GAME_LENGTH_in_ms, game_length_in_ms); uint32_t time_remaining_until_countdown_in_ms = ((BLE_Packet_T *)context->Cause_Of_Transition->Data)->Instigation.time_remaining_until_countdown_in_ms; Set_Time_Remaining_Until_Countdown(time_remaining_until_countdown_in_ms); diff --git a/States/State_Configuring.c b/States/State_Configuring.c index 6c79699..f11203e 100644 --- a/States/State_Configuring.c +++ b/States/State_Configuring.c @@ -26,6 +26,18 @@ static void Configuring_Entry(StateMachineContext_T *context); static void Configuring_Do(StateMachineContext_T *context); static void Configuring_Exit(StateMachineContext_T *context); +static void HandleBLEConfigurationPacket(const BLE_ParametersPacket_T *const packet); + +static TimerHandle_t BLEConfigurationResponseTimer = NULL; +static StaticTimer_t xBLEConfigurationResponseTimerBuffer; +static TickType_t xBLEConfigurationResponseTimerPeriod = 3000 / portTICK_PERIOD_MS; + +static void BLEConfigurationResponseTimerCallback(TimerHandle_t xTimer) +{ + // Don't send HELLO packets once configuration has started. + BLE_StopAdvertising(); +} + #define MAX_MENU_DEPTH 10 static MenuItem_T const *CurrentMenuItem; static uint8_t MenuItemHistoryIndex = 0; @@ -37,10 +49,11 @@ static const char *KLOG_TAG = "STATE_CONFIGURING"; //! Activities for the **Configuring** state. const StateActivity_T STATE_CONFIGURING_Activities = - { - .Entry = Configuring_Entry, - .Do = Configuring_Do, - .Exit = Configuring_Exit}; +{ + .Entry = Configuring_Entry, + .Do = Configuring_Do, + .Exit = Configuring_Exit +}; //! Sets up the Configuring state. /*! @@ -52,12 +65,35 @@ static void Configuring_Entry(StateMachineContext_T *context) NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_MENU, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); - BLE_UpdateStatusPacket(); + if (context->Cause_Of_Transition->ID == KEVENT_BLE_EVENT_RECEIVED) + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BEEP, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + } + + BLE_UpdateHelloPacket(); + if (BLE_ScanAndAdvertise() != SYSTEMK_RESULT_SUCCESS) { KLOG_ERROR(KLOG_TAG, "Couldn't start BLE!"); } + if (BLEConfigurationResponseTimer == NULL) + { + BLEConfigurationResponseTimer = xTimerCreateStatic( + "BLEConfigResponse", + xBLEConfigurationResponseTimerPeriod, + pdFALSE, + (void *)0, + BLEConfigurationResponseTimerCallback, + &xBLEConfigurationResponseTimerBuffer); + } + + if (BLEConfigurationResponseTimer == NULL) + { + KLOG_ERROR(KLOG_TAG, "Couldn't create the BLEConfigurationResponseTimer!"); + } + // Reset the menu. CurrentMenuItem = RootMenu; MenuItemHistory[MenuItemHistoryIndex] = CurrentMenuItem; @@ -71,6 +107,13 @@ static void Configuring_Do(StateMachineContext_T *context) { portBASE_TYPE xStatus; static KEvent_T Event; + + // For the first hundred milliseconds, keep updating the Hello packet, since on some platforms (PSoC6), one call is not enough. + // TODO: Fix the Hello packet hack on PSoC6. + if ((xTaskGetTickCount() - context->Time_At_State_Entry_In_Ticks) < (100 / portTICK_PERIOD_MS)) + { + BLE_UpdateHelloPacket(); + } xStatus = Receive_KEvent(&Event); @@ -150,6 +193,7 @@ static void Configuring_Do(StateMachineContext_T *context) CurrentMenuItem->OnFocus(true); } } + BLE_UpdateHelloPacket(); break; case KEVENT_TRIGGER_SWITCH_RELEASED: @@ -180,6 +224,8 @@ static void Configuring_Do(StateMachineContext_T *context) { KLOG_WARN(KLOG_TAG, "Failed to increment team!"); } + + BLE_UpdateHelloPacket(); } break; @@ -191,6 +237,21 @@ static void Configuring_Do(StateMachineContext_T *context) Transition_For_Event(context, STATE_REPROGRAMMING, &Event); break; + case KEVENT_BLE_PACKET_RECEIVED: + if (((BLE_Packet_T *)Event.Data)->Generic.type == BLE_PACKET_TYPE_PARAMETERS) + { + HandleBLEConfigurationPacket((BLE_ParametersPacket_T *)Event.Data); + } + else if (((BLE_Packet_T *)Event.Data)->Generic.type == BLE_PACKET_TYPE_EVENT) + { + HandleBLEEventPacket((BLE_EventPacket_T *)Event.Data, context); + } + else + { + BLE_FreePacketBuffer(Event.Data); + } + break; + default: // All other events are ignored in this state. ProcessUnhandledEvent(&Event); @@ -214,3 +275,151 @@ static void Configuring_Exit(StateMachineContext_T *context) NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_ALL_OFF, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); } + +static SystemKResult_T HandleParameterChangeRequest(BLE_ParameterKey_T key, uint32_t value) +{ + SystemKResult_T result = SYSTEMK_RESULT_UNSPECIFIED_FAILURE; + + if (key == BLE_PARAMETER_KEY_TEAM_ID) + { + uint8_t team_ID = (uint8_t)value; + if (Is_Valid_Team_ID(team_ID)) + { + result = Set_Team_With_Audio_Feedback(team_ID); + } + if (result == SYSTEMK_RESULT_SUCCESS) + { + KLOG_INFO(KLOG_TAG, "Team set to %u over BLE.", team_ID); + } + } + else if (key == BLE_PARAMETER_KEY_PLAYER_ID) + { + uint8_t player_ID = (uint8_t)value; + result = Set_Player_With_Audio_Feedback(player_ID); + if (result == SYSTEMK_RESULT_SUCCESS) + { + KLOG_INFO(KLOG_TAG, "Player set to %u over BLE.", player_ID); + } + } + else if (key == BLE_PARAMETER_KEY_GAME_LENGTH) + { + result = SETTINGS_set_uint32_t(SYSTEMK_SETTING_T_GAME_LENGTH_in_ms, value); + + if (result == SYSTEMK_RESULT_SUCCESS) + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BEEP, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + KLOG_INFO(KLOG_TAG, "Game length set to %lu ms over BLE.", value); + } + else + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BONK, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + } + } + else if (key == BLE_PARAMETER_KEY_MAX_HEALTH) + { + uint8_t max_health = (uint8_t)value; + Set_Max_Health(max_health); + result = SETTINGS_set_uint8_t(SYSTEMK_SETTING_MAX_HEALTH, max_health); + + if (result == SYSTEMK_RESULT_SUCCESS) + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BEEP, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + KLOG_INFO(KLOG_TAG, "Max health set to %u over BLE.", max_health); + } + else + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BONK, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + } + } + else if (key == BLE_PARAMETER_KEY_SECONDARY_COLOR) + { + result = SETTINGS_set_uint32_t(SYSTEMK_SETTING_SECONDARY_COLOR, value); + + if (result == SYSTEMK_RESULT_SUCCESS) + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BEEP, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + KLOG_INFO(KLOG_TAG, "Secondary color set to %lu over BLE.", value); + } + else + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BONK, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + } + } + else if (key == BLE_PARAMETER_KEY_SPECIAL_WEAPONS_ON_REENTRY) + { + uint8_t n_weapons_on_reentry = (uint8_t)value; + Set_Available_Bombs(n_weapons_on_reentry); + result = SETTINGS_set_uint8_t(SYSTEMK_SETTING_N_SPECIAL_WEAPONS_ON_REENTRY, n_weapons_on_reentry); + + if (result == SYSTEMK_RESULT_SUCCESS) + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BEEP, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + KLOG_INFO(KLOG_TAG, "Number of special weapons granted on reentry set to %u over BLE.", n_weapons_on_reentry); + } + else + { + AudioAction_T audio_action = {.ID = AUDIO_PLAY_BONK, .Data = (void *)0x00}; + Perform_Audio_Action(&audio_action); + } + } + + return result; +} + +void HandleBLEConfigurationPacket(const BLE_ParametersPacket_T *const packet) +{ + if (BLE_IsBLEPacketForMe(packet->target_BD_ADDR)) + { + if (BLE_IsPacketNew(packet->BD_ADDR, BLE_PACKET_TYPE_PARAMETERS, packet->event_number)) + { + if (packet->subtype == BLE_REQUEST_PARAMETER_CHANGE) + { + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + + BLE_ParameterKey_T key_one = BLE_GetValidConfigKey(packet->key_one); + if (key_one != BLE_PARAMETER_KEY_NONE) + { + result = HandleParameterChangeRequest(key_one, packet->value_one); + } + + if (result == SYSTEMK_RESULT_SUCCESS) + { + BLE_ParameterKey_T key_two = BLE_GetValidConfigKey(packet->key_two); + if (key_two != BLE_PARAMETER_KEY_NONE) + { + result = HandleParameterChangeRequest(key_two, packet->value_two); + } + } + + if (result == SYSTEMK_RESULT_SUCCESS) + { + BLE_RespondToConfigurationPacket(packet, BLE_ACKNOWLEDGE_PARAMETER_CHANGE); + } + else + { + KLOG_ERROR(KLOG_TAG, "Error changing parameter(s)!"); + BLE_RespondToConfigurationPacket(packet, BLE_ERROR_CHANGING_PARAMETERS); + } + + if (xTimerStart(BLEConfigurationResponseTimer, 0) != pdPASS) + { + KLOG_ERROR(KLOG_TAG, "Couldn't start the BLEConfigurationResponseTimer!"); + } + } + } + } + else + { + // Once configuration has begun, stop advertising the HELLO packet to free up bandwidth. + BLE_StopAdvertising(); + } + + BLE_FreePacketBuffer((BLE_GenericPacketType_T *)packet); +} diff --git a/States/State_Initializing.c b/States/State_Initializing.c index 2f52060..0b490d8 100644 --- a/States/State_Initializing.c +++ b/States/State_Initializing.c @@ -44,7 +44,8 @@ const StateActivity_T STATE_INITIALIZING_Activities = */ static void Initializing_Entry(StateMachineContext_T * context) { - LOG("Entering the Initializing state."); + KLOG_INFO("SystemK", "Using SystemK version %s.", SYSTEMK_VERSION_STRING); + NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_TEST_PATTERN, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); AudioAction_T audio_action = {.ID = AUDIO_PLAY_STARTUP_SOUND, .Play_To_Completion = true, .Data = (void *)0x00}; @@ -113,14 +114,4 @@ static void Initializing_Exit(StateMachineContext_T * context) uint8_t weapon_ID = NERF_LASER_STRIKE_BLASTER_ID; (void) SETTINGS_set_uint8_t(SYSTEMK_SETTING_WEAPONID, weapon_ID); (void) SETTINGS_Save(); - - //! \todo TEAM_PURPLE is always one-hit kill. - uint8_t team_ID; - (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_TEAMID, &team_ID); - TeamID_t my_common_team_ID = Resolve_Common_Team_ID(team_ID); - - if (my_common_team_ID == TEAM_PURPLE) - { - Set_Health(10); - } } diff --git a/States/State_Machine.c b/States/State_Machine.c index f3e702b..7bb4151 100644 --- a/States/State_Machine.c +++ b/States/State_Machine.c @@ -22,13 +22,6 @@ /* Include Files */ #include "SystemK.h" -const StateActivity_T STATE_DEFAULT_Activities = -{ - .Entry = NULL, - .Do = NULL, - .Exit = NULL -}; - //! Activities for the top-level state machine. /*! * This array is indexed by #StateID_T (except there is no entry for @@ -37,7 +30,6 @@ const StateActivity_T STATE_DEFAULT_Activities = */ static const StateActivity_T * Activities[] = { - &STATE_DEFAULT_Activities, &STATE_INITIALIZING_Activities, &STATE_REPROGRAMMING_Activities, &STATE_CONFIGURING_Activities, @@ -62,6 +54,11 @@ static StateMachineContext_T Context = .Time_At_State_Entry_In_Ticks = 0, }; +StateMachineContext_T* GetContext() +{ + return &Context; +} + TaskHandle_t State_Machine_Task_Handle; void State_Machine_Task(void * pvParameters) @@ -131,3 +128,70 @@ void ProcessUnhandledEvent(KEvent_T * Event) break; } } + +void HandleBLEEventPacket(const BLE_EventPacket_T *const packet, StateMachineContext_T *context) +{ + if (BLE_IsBLEPacketForMe(packet->target_BD_ADDR)) + { + if (BLE_IsPacketNew(packet->BD_ADDR, BLE_PACKET_TYPE_EVENT, packet->event_number)) + { + if (packet->event_ID == BLE_EVENT_CONFIGURED) + { + if (context->States.Current_State == STATE_CONFIGURING) + { + static KEvent_T Event = + { + .ID = KEVENT_BLE_EVENT_RECEIVED, + .Data = (void *)BLE_EVENT_CONFIGURED + }; + Transition_For_Event(context, STATE_READY, &Event); + } + } + else if (packet->event_ID == BLE_EVENT_CONFIGURE) + { + if (context->States.Current_State == STATE_READY) + { + static KEvent_T Event = + { + .ID = KEVENT_BLE_EVENT_RECEIVED, + .Data = (void *)BLE_EVENT_CONFIGURE + }; + Transition_For_Event(context, STATE_CONFIGURING, &Event); + } + } + else if (packet->event_ID == BLE_EVENT_WRAPUP_COMPLETE) + { + if (context->States.Current_State == STATE_WRAPPING_UP) + { + StateID_T next_state = (StateID_T)packet->event_data; + + if (next_state < STATE_IS_OUT_OF_RANGE) + { + static KEvent_T Event = + { + .ID = KEVENT_BLE_EVENT_RECEIVED, + .Data = (void *)BLE_EVENT_WRAPUP_COMPLETE + }; + Transition_For_Event(context, next_state, &Event); + } + else + { + KLOG_WARN("STATE", "Received a BLE Wrapup Complete event with an invalid Next State!"); + } + } + } + else if (packet->event_ID == BLE_EVENT_GAME_OVER) + { + if ((context->States.Current_State == STATE_PLAYING__INTERACTING) || + (context->States.Current_State == STATE_PLAYING__TAGGED_OUT)) + { + KEvent_T game_over_event = { .ID = KEVENT_GAME_OVER, .Data = (void *)0x00 }; + Post_KEvent(&game_over_event); + } + } + } + } + + BLE_FreePacketBuffer((BLE_GenericPacketType_T *)packet); +} + diff --git a/States/State_Machine.h b/States/State_Machine.h index 31d375a..981986e 100644 --- a/States/State_Machine.h +++ b/States/State_Machine.h @@ -36,22 +36,21 @@ */ typedef enum { - STATE_DEFAULT = 0, - STATE_INITIALIZING = 1, - STATE_REPROGRAMMING = 2, - STATE_CONFIGURING = 3, - STATE_READY = 4, + STATE_INITIALIZING = 0, + STATE_REPROGRAMMING = 1, + STATE_CONFIGURING = 2, + STATE_READY = 3, // Substates of STATE_STARTING_GAME - STATE_STARTING_GAME__INSTIGATING = 5, - STATE_STARTING_GAME__RESPONDING = 6, - STATE_STARTING_GAME__COUNTING_DOWN = 7, + STATE_STARTING_GAME__INSTIGATING = 4, + STATE_STARTING_GAME__RESPONDING = 5, + STATE_STARTING_GAME__COUNTING_DOWN = 6, // Substates of STATE_PLAYING - STATE_PLAYING__INTERACTING = 8, - STATE_PLAYING__TAGGED_OUT = 9, + STATE_PLAYING__INTERACTING = 7, + STATE_PLAYING__TAGGED_OUT = 8, - STATE_WRAPPING_UP = 10, + STATE_WRAPPING_UP = 9, // STATE_IS_OUT_OF_RANGE is one more than the last valid state. STATE_IS_OUT_OF_RANGE, @@ -107,6 +106,7 @@ extern TaskHandle_t State_Machine_Task_Handle; void State_Machine_Task(void * pvParameters); void ProcessUnhandledEvent(KEvent_T * Event); +void HandleBLEEventPacket(const BLE_EventPacket_T *const packet, StateMachineContext_T *context); inline void Transition_For_Event(StateMachineContext_T* context, StateID_T next_state, KEvent_T* event) { @@ -120,6 +120,8 @@ inline uint32_t GetTimeInState_in_ms(StateMachineContext_T * context) return result; } +StateMachineContext_T* GetContext(); + #include "State_Configuring.h" #include "State_Ready.h" #include "State_Initializing.h" diff --git a/States/State_Ready.c b/States/State_Ready.c index 21b4af4..777e37c 100644 --- a/States/State_Ready.c +++ b/States/State_Ready.c @@ -47,13 +47,15 @@ static void Ready_Entry(StateMachineContext_T * context) LOG("Entering the Ready state."); NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_IDLE, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); - BLE_UpdateStatusPacket(); + BLE_UpdateStatusPacket(STATE_READY); if (BLE_ScanAndAdvertise() != SYSTEMK_RESULT_SUCCESS) { KLOG_ERROR(KLOG_TAG, "Couldn't start BLE!"); } AudioAction_T audio_action = {.ID = AUDIO_PLAY_GAME_ON, .Data = (void *)0x00}; Perform_Audio_Action(&audio_action); + + Set_Health(Get_Max_Health()); } //! Executes the Ready state. @@ -90,6 +92,10 @@ static void Ready_Do(StateMachineContext_T * context) { Transition_For_Event(context, STATE_STARTING_GAME__RESPONDING, &Event); } + else if (((BLE_Packet_T *)Event.Data)->Generic.type == BLE_PACKET_TYPE_EVENT) + { + HandleBLEEventPacket((BLE_EventPacket_T *)Event.Data, context); + } else { BLE_FreePacketBuffer(Event.Data); diff --git a/States/State_Wrapping_Up.c b/States/State_Wrapping_Up.c index 1361f93..fc915b3 100644 --- a/States/State_Wrapping_Up.c +++ b/States/State_Wrapping_Up.c @@ -30,6 +30,15 @@ static void Wrapping_Up_Entry(StateMachineContext_T * context); static void Wrapping_Up_Do(StateMachineContext_T * context); static void Wrapping_Up_Exit(StateMachineContext_T * context); +static TimerHandle_t BLEInfoRequestResponseTimer = NULL; +static StaticTimer_t xBLEInfoRequestResponseTimerBuffer; +static TickType_t xBLEInfoRequestResponseTimerPeriod = 3000 / portTICK_PERIOD_MS; + +static void BLEInfoRequestResponseTimerCallback(TimerHandle_t xTimer) +{ + BLE_UpdateStatusPacket(STATE_WRAPPING_UP); +} + //! Activities for the **Wrapping Up** state. const StateActivity_T STATE_WRAPPING_UP_Activities = { @@ -47,11 +56,27 @@ static void Wrapping_Up_Entry(StateMachineContext_T * context) LOG("Entering the Wrapping Up state."); NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_IDLE, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); - BLE_UpdateStatusPacket(); + BLE_UpdateStatusPacket(STATE_WRAPPING_UP); if (BLE_ScanAndAdvertise() != SYSTEMK_RESULT_SUCCESS) { KLOG_ERROR(KLOG_TAG, "Couldn't start BLE!"); } + + if (BLEInfoRequestResponseTimer == NULL) + { + BLEInfoRequestResponseTimer = xTimerCreateStatic( + "BLEInfoRequestResponse", + xBLEInfoRequestResponseTimerPeriod, + pdFALSE, + (void *)0, + BLEInfoRequestResponseTimerCallback, + &xBLEInfoRequestResponseTimerBuffer); + } + + if (BLEInfoRequestResponseTimer == NULL) + { + KLOG_ERROR(KLOG_TAG, "Couldn't create the BLEInfoRequestResponseTimer!"); + } } //! Executes the Wrapping Up state. @@ -84,8 +109,14 @@ static void Wrapping_Up_Do(StateMachineContext_T * context) break; case KEVENT_BLE_PACKET_RECEIVED: - // TODO - BLE_FreePacketBuffer(Event.Data); + if (((BLE_Packet_T *)Event.Data)->Generic.type == BLE_PACKET_TYPE_EVENT) + { + HandleBLEEventPacket((BLE_EventPacket_T *)Event.Data, context); + } + else + { + BLE_FreePacketBuffer(Event.Data); + } break; default: diff --git a/SystemK.h b/SystemK.h index 289cfb1..2ff8590 100755 --- a/SystemK.h +++ b/SystemK.h @@ -70,6 +70,10 @@ #ifndef SYSTEMK_H #define SYSTEMK_H +#define SYSTEMK_MAJOR_VERSION 0 +#define SYSTEMK_MINOR_VERSION 99 +#define SYSTEMK_VERSION_STRING "00.99" + #ifdef ESP_PLATFORM #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -99,6 +103,7 @@ #include "BLE/BLE_Packets.h" #include "BLE/BLE_Packet_Tracker.h" #include "BLE/BLE_HW_Interface.h" +#include "BLE/BLE_Utils.h" #include "IR/IR_HW_Interface.h" #include "States/State_Machine.h" #include "Menu/Menu.h"