Initial public release of SystemK.
This commit is contained in:
parent
387f57cdda
commit
6f51f5b006
129 changed files with 11654 additions and 2 deletions
239
States/Playing/State_Playing.c
Normal file
239
States/Playing/State_Playing.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* This program source code file is part of SystemK, a library in the KTag project.
|
||||
*
|
||||
* 🛡️ <https://ktag.clubk.club> 🃞
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "SystemK.h"
|
||||
|
||||
static TimerHandle_t BLEStatusTimer = NULL;
|
||||
static StaticTimer_t xBLEStatusTimerBuffer;
|
||||
static TickType_t xBLEStatusTimerPeriod = 3000 / portTICK_PERIOD_MS;
|
||||
|
||||
static TimerHandle_t GameDurationTimer = NULL;
|
||||
static StaticTimer_t xGameDurationTimerBuffer;
|
||||
|
||||
static BLENearby_T BLE_RXd_data;
|
||||
static const uint_fast16_t MAX_TIME_TO_LIVE_in_ms = 1000;
|
||||
static const int_fast8_t STATUS_RSSI_THRESHOLD = -80;
|
||||
|
||||
static const int_fast8_t TAG_RSSI_THRESHOLD = -75;
|
||||
|
||||
static void BLEStatusTimerCallback(TimerHandle_t xTimer)
|
||||
{
|
||||
BLE_UpdateStatusPacket();
|
||||
}
|
||||
|
||||
static void GameDurationTimerCallback(TimerHandle_t xTimer)
|
||||
{
|
||||
KEvent_T game_over_event = { .ID = KEVENT_GAME_OVER, .Data = (void *)0x00 };
|
||||
Post_KEvent(&game_over_event);
|
||||
}
|
||||
|
||||
//! Sets up the Playing state.
|
||||
/*!
|
||||
* \param context Context in which this state is being run.
|
||||
*/
|
||||
void Playing_Entry(StateMachineContext_T *context)
|
||||
{
|
||||
LOG("Entering the Playing state.");
|
||||
static const char *KLOG_TAG = "STATE_PLAYING Entry";
|
||||
|
||||
for (uint_fast8_t slot = 0; slot < CONFIG_KTAG_MAX_NEOPIXELS_PER_CHANNEL; slot++)
|
||||
{
|
||||
BLE_RXd_data.neighbors[slot].TimeToLive_in_ms = 0;
|
||||
}
|
||||
|
||||
BLE_UpdateStatusPacket();
|
||||
if (BLE_ScanAndAdvertise() != SYSTEMK_RESULT_SUCCESS)
|
||||
{
|
||||
KLOG_ERROR(KLOG_TAG, "Couldn't start BLE!");
|
||||
}
|
||||
|
||||
NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_TEAM_COLORS, .Data = (void *)DISPLAY_STYLE_HEARTBEAT, .Prominence = NEOPIXELS_BACKGROUND};
|
||||
xQueueSend(xQueueNeoPixels, &neopixels_action, 0);
|
||||
|
||||
if (BLEStatusTimer == NULL)
|
||||
{
|
||||
BLEStatusTimer = xTimerCreateStatic(
|
||||
"BLEStatus",
|
||||
xBLEStatusTimerPeriod,
|
||||
pdTRUE,
|
||||
(void *)0,
|
||||
BLEStatusTimerCallback,
|
||||
&xBLEStatusTimerBuffer);
|
||||
}
|
||||
if (BLEStatusTimer != NULL)
|
||||
{
|
||||
if (xTimerStart(BLEStatusTimer, 0) != pdPASS)
|
||||
{
|
||||
KLOG_ERROR(KLOG_TAG, "Couldn't start the BLEStatusTimer!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KLOG_ERROR(KLOG_TAG, "Couldn't create the BLEStatusTimer!");
|
||||
}
|
||||
|
||||
// The timer is only needed for timed games.
|
||||
if (Get_Time_Remaining_in_Game_in_ms() != UINT32_MAX)
|
||||
{
|
||||
if (GameDurationTimer == NULL)
|
||||
{
|
||||
static TickType_t xGameDurationTimerPeriod;
|
||||
xGameDurationTimerPeriod = Get_Time_Remaining_in_Game_in_ms() / portTICK_PERIOD_MS;
|
||||
|
||||
GameDurationTimer = xTimerCreateStatic(
|
||||
"GameDuration",
|
||||
xGameDurationTimerPeriod,
|
||||
pdFALSE,
|
||||
(void *)0,
|
||||
GameDurationTimerCallback,
|
||||
&xGameDurationTimerBuffer);
|
||||
}
|
||||
if (GameDurationTimer != NULL)
|
||||
{
|
||||
if (xTimerStart(GameDurationTimer, 0) != pdPASS)
|
||||
{
|
||||
KLOG_ERROR(KLOG_TAG, "Couldn't start the GameDurationTimer!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KLOG_ERROR(KLOG_TAG, "Couldn't create the GameDurationTimer!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Cleans up the Playing state.
|
||||
/*!
|
||||
* \param context Context in which this state is being run.
|
||||
*/
|
||||
void Playing_Exit(StateMachineContext_T *context)
|
||||
{
|
||||
LOG("Exiting the Playing state.");
|
||||
xTimerStop(BLEStatusTimer, portMAX_DELAY);
|
||||
BLE_UpdateStatusPacket();
|
||||
}
|
||||
|
||||
void HandleBLEStatusPacket(const BLE_StatusPacket_T *const packet)
|
||||
{
|
||||
bool found = false;
|
||||
uint8_t first_empty_slot = 0xFF;
|
||||
|
||||
// Look through the neighbors, and see if this is one we already know about.
|
||||
for (uint_fast8_t slot = 0; slot < CONFIG_KTAG_MAX_NEOPIXELS_PER_CHANNEL; slot++)
|
||||
{
|
||||
if (BLE_RXd_data.neighbors[slot].TimeToLive_in_ms > 0)
|
||||
{
|
||||
if (memcmp(packet->BD_ADDR, BLE_RXd_data.neighbors[slot].BD_ADDR, 6) == 0)
|
||||
{
|
||||
if ((packet->health > 0) && (packet->RSSI > STATUS_RSSI_THRESHOLD))
|
||||
{
|
||||
BLE_RXd_data.neighbors[slot].RSSI = packet->RSSI;
|
||||
BLE_RXd_data.neighbors[slot].Color = packet->primary_color;
|
||||
BLE_RXd_data.neighbors[slot].TimeToLive_in_ms = MAX_TIME_TO_LIVE_in_ms;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear the slot.
|
||||
BLE_RXd_data.neighbors[slot].TimeToLive_in_ms = 0;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (first_empty_slot == 0xFF)
|
||||
{
|
||||
first_empty_slot = slot;
|
||||
}
|
||||
}
|
||||
|
||||
if ((found == false) &&
|
||||
(first_empty_slot < CONFIG_KTAG_MAX_NEOPIXELS_PER_CHANNEL) &&
|
||||
(packet->health > 0) &&
|
||||
(packet->RSSI > STATUS_RSSI_THRESHOLD))
|
||||
{
|
||||
// Welcome the new neighbor.
|
||||
memcpy(BLE_RXd_data.neighbors[first_empty_slot].BD_ADDR, packet->BD_ADDR, 6);
|
||||
BLE_RXd_data.neighbors[first_empty_slot].RSSI = packet->RSSI;
|
||||
BLE_RXd_data.neighbors[first_empty_slot].Color = packet->primary_color;
|
||||
BLE_RXd_data.neighbors[first_empty_slot].TimeToLive_in_ms = MAX_TIME_TO_LIVE_in_ms;
|
||||
}
|
||||
|
||||
// NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_BLE_NEARBY, .Data = (void *)&BLE_RXd_data, .Prominence = NEOPIXELS_BACKGROUND};
|
||||
// xQueueSend(xQueueNeoPixels, &neopixels_action, 0);
|
||||
}
|
||||
|
||||
void HandleBLETagPacket(const BLE_TagPacket_T *const packet)
|
||||
{
|
||||
static int16_t Health_In_Percent;
|
||||
static color_t ReceivedTagColor;
|
||||
|
||||
// Use this code for tuning RSSI.
|
||||
//{
|
||||
// static uint8_t normalized_rssi = 0;
|
||||
// normalized_rssi = (uint8_t)abs(packet->RSSI);
|
||||
//
|
||||
// AudioAction_T rssi_action = {.ID = AUDIO_PRONOUNCE_NUMBER_0_TO_100, .Play_To_Completion = true, .Data = (void *)&normalized_rssi};
|
||||
// Perform_Audio_Action(&rssi_action);
|
||||
//}
|
||||
|
||||
// Throw away quiet packets without processing them.
|
||||
if (packet->RSSI > TAG_RSSI_THRESHOLD)
|
||||
{
|
||||
if (BLE_IsBLEPacketForMe(packet->target_BD_ADDR))
|
||||
{
|
||||
if (BLE_IsPacketNew(packet->BD_ADDR, BLE_PACKET_TYPE_TAG, packet->event_number))
|
||||
{
|
||||
if (packet->damage > 0)
|
||||
{
|
||||
Reduce_Health(packet->damage);
|
||||
|
||||
ReceivedTagColor = packet->color;
|
||||
|
||||
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);
|
||||
}
|
||||
else if (packet->damage < 0)
|
||||
{
|
||||
Health_In_Percent = (uint8_t)Get_Health();
|
||||
Health_In_Percent -= packet->damage;
|
||||
if (Health_In_Percent > MAX_HEALTH)
|
||||
{
|
||||
Health_In_Percent = 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);
|
||||
AudioAction_T audio_action_two = {.ID = AUDIO_PLAY_HEALTH_REMAINING, .Data = (void *)0x00};
|
||||
Perform_Audio_Action(&audio_action_two);
|
||||
NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_HEALTH_REPORT, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)&Health_In_Percent};
|
||||
xQueueSend(xQueueNeoPixels, &neopixels_action, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue