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 <joe@clubk.club>
Reviewed-on: #2
This commit is contained in:
Joe Kearney 2025-06-08 21:52:29 +00:00
parent 4fe072f2d3
commit bfcdf4c354
26 changed files with 917 additions and 128 deletions

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;