SystemK v2.00: Interface Improvements #15
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "interface_improvements"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Overview
Several improvements were made to the SystemK Hardware Abstraction Layer (HAL) and
related interfaces. They are ordered from least to most invasive:
BLE_Init()to the BLE HALSETTINGS_Load()to the Settings HALBLE_Quiet/BLE_UnquietsemanticsHW_Execute_Console_Commandparameter typeBLE_GetMyAddresspointer parametermax_lenparameter toSETTINGS_get_device_nameHW_NeoPixels_Get_My_Color()from the HALHW_NeoPixels_Set_RGBwithHW_NeoPixels_Set_Colorvoid *DatainAudioAction_Twith a typed unionPrepare_Tag/Send_Tagaccept explicit argumentsPhase 1 — Pure Additions
1.1
BLE_Init()added toBLE/BLE_HW_Interface.hBLE initialization previously happened implicitly inside each platform
implementation with no explicit contract. Platform porters had to reverse-engineer
where and whether initialization was expected.
SystemK.cnow callsBLE_Init()fromInitialize_SystemK(), before the statemachine task is created.
1.2
SETTINGS_Load()added toSettings/Settings_Interface.hSettings loading also happened implicitly.
SETTINGS_Save()existed in theinterface but its counterpart did not.
SystemK.cnow callsSETTINGS_Load()fromInitialize_SystemK(), beforeBLE_Init()and the state machine task.1.3
BLE_Quiet/BLE_Unquietsemantics documentedA comment block was added to both declarations in
BLE/BLE_HW_Interface.hdescribing the full contract: timer behavior, idempotency guarantees, interaction
between timed and indefinite quiet, and the
SYSTEMK_RESULT_NOT_READYreturncondition. No code changes.
Phase 2 — Mechanical Type Fixes
2.1
HW_Execute_Console_Commandparameter type correctedThe command is a text string but was typed as
const uint8_t *const. Callersworked around this with explicit casts.
2.2
BLE_GetMyAddresspointer parameter tightenedThe raw
uint8_t *parameter gave no indication of the required buffer size.No change is required at call sites; the array type is compatible.
2.3
SETTINGS_get_device_namegains amax_lenparameterCallers had to know the correct buffer size out-of-band.
Phase 3 — NeoPixel Refactor
3.1
HW_NeoPixels_Get_My_Color()removed from the HALTeam color is a game/settings concept, not a hardware concept. The HAL should not
need to know about team assignments.
The seven call sites in
NeoPixels/Animations/now use theGAME_Get_My_Color()inline helper in
Game/Game.h, which reads team, player, and weapon from settingsand derives the color via
PROTOCOLS_GetColor().3.2
HW_NeoPixels_Set_RGBreplaced byHW_NeoPixels_Set_ColorThe old signature required callers to decompose
color_tinto separate R, G, Bcomponents and apply gamma correction themselves. Some call sites also swapped
channels to compensate for GRB-order hardware — hardware-specific behavior that
belongs in the HAL.
The platform implementation is now responsible for gamma correction and any
color-channel reordering required by its hardware.
Phase 4 — Structural Changes
4.1
AudioAction_T.Datachanged fromvoid *to a typed unionvoid *Datawas an untyped payload with no documented contract per action ID.In practice only two action IDs used non-null data, both passing a pointer to a
uint8_t. This change makes the type explicit and eliminates pointer indirection.Call sites that previously passed
(void *)0x00now omitDataentirely (C99zero-initializes unspecified members). Call sites that previously passed
(void *)&variablenow pass{ .number = variable }by value.The struct shrinks from 12 to 8 bytes. FreeRTOS queues created with
xQueueCreate(n, sizeof(AudioAction_T))pick up the new size automatically atruntime.
4.2
Prepare_Tag/Send_Tagaccept explicit argumentsThe original interface communicated through hidden global state:
Prepare_Tag()encoded a packet from settings into a module-level variable;
Send_Tag()consumedit. The contract was invisible to callers and to platform implementers.
The new interface uses a handle:
PreparedTag_Tis defined inGame/Game.h(SystemK code) and contains aTimedPulseTrain_T *pulse_trainmember.SystemK builds the
TagPacket_Tfrom current settings viaGAME_Build_My_Tag_Packet()inGame/Game.hand stores the returnedPreparedTag_T *inGAME_Prepared_Tag(defined inGame/Game.c,declared
externinGame/Game.h) so it is accessible from both the countdownstate (which calls
Prepare_Tag) and the interacting substate (which callsSend_Tag).The platform is responsible for encoding the pulse train in
Prepare_Tagandtransmitting it in
Send_Tag.PROTOCOLS_EncodePacket()is called exactly once,in
Prepare_Tag.4.3 Generic settings accessors replaced with per-setting typed functions
SETTINGS_get_uint8_t(id, ptr)andSETTINGS_get_uint32_t(id, ptr)baked thestorage type of each setting into every call site via the function name. If a
setting's range ever grows (e.g.,
Max_Healthexceeding 255), all call sitessilently truncate with no compile-time warning.
The
SystemKSettingID_Tenum is removed from the public interface entirely. Inits place, each setting has one dedicated typed getter and one typed setter:
The function names are derived from the
Keycolumn inSettings/Settings.csv.Settings/generate_settings_code.pyhas been updated to generate both theinterface declarations and the per-setting implementations. Adding a new setting
now requires only a new row in the CSV; changing a setting's type requires editing
one CSV cell, regenerating, and fixing the compile errors the compiler identifies.
Platform Porting Guide
This section lists every change a platform implementation must make to compile
against the updated SystemK interface.
Settings (
Settings_Interface.h)Add
SETTINGS_Load().Rename your existing initialization function (e.g.,
Initialize_Settings()) toSETTINGS_Load(). It must returnSystemKResult_Tand signal readiness bysetting the
SYS_SETTINGS_READYevent group bit before returning.Replace the four generic accessors with per-setting functions.
Delete
SETTINGS_get_uint8_t,SETTINGS_set_uint8_t,SETTINGS_get_uint32_t,and
SETTINGS_set_uint32_t. Implement one getter and one setter for eachsetting listed in
Settings/Settings.csv, using the naming conventionSETTINGS_get_<Key>/SETTINGS_set_<Key>. RunSettings/generate_settings_code.pyto generate a starting implementation.Add
SETTINGS_get_Device_Type(uint32_t *value).This is a read-only function that returns your platform's BLE device type
constant. It is not generated from
Settings.csv.Update
SETTINGS_get_device_name.Add a
size_t max_lenparameter and use it to limit the copy into the caller'sbuffer, ensuring null-termination within
max_lenbytes.BLE (
BLE/BLE_HW_Interface.h)Add
BLE_Init().Implement
SystemKResult_T BLE_Init(void). Move any BLE host/controllerinitialization that previously happened at startup into this function. Return
SYSTEMK_RESULT_SUCCESSon success orSYSTEMK_RESULT_UNSPECIFIED_FAILUREifthe BLE stack fails to initialize.
Update
BLE_GetMyAddress.Change the parameter from
uint8_t *BD_ADDRtouint8_t BD_ADDR[BD_ADDR_SIZE].The function body requires no change; only the signature needs updating.
Console (
Console_HW_Interface.h)HW_Execute_Console_Command.Change the parameter from
const uint8_t *const commandtoconst char *const command. Remove any(const char *)casts at call siteswithin your platform code.
NeoPixels (
NeoPixels/NeoPixel_HW_Interface.h)Delete
HW_NeoPixels_Get_My_Color().Remove the implementation entirely. Team color is now resolved in SystemK.
Replace
HW_NeoPixels_Set_RGBwithHW_NeoPixels_Set_Color.Your implementation must now decompose
colorusingRed(),Green(),Blue()and apply gamma correction. If your hardware uses GRB channel ordering,swap the red and green components here. Example for RGB-order hardware with
gamma correction:
Audio (
Audio/Audio_HW_Interface.h)Update
AudioAction_Tdata access.action.Datais no longer avoid *. Where your implementation previouslydereferenced the pointer — e.g.,
*((uint8_t *)action.Data)— use the unionmember directly:
IR (
IR/IR_HW_Interface.h)Implement the new
Prepare_Tag/Send_Tagsignatures.PreparedTag_Tis defined inGame/Game.hand contains a single member,TimedPulseTrain_T *pulse_train. You do not need to define the struct yourself.Prepare_Tagreceives a fully populatedTagPacket_Tfrom SystemK. Itmust encode the packet via
PROTOCOLS_EncodePacket(), store the result in astatic
PreparedTag_T, prepare the hardware for transmission, and return apointer to that static. Do not call
PROTOCOLS_EncodePacket()inSend_Tag— encoding must happen in
Prepare_Tagto minimize transmit latency.Send_Tagreceives the pointer returned byPrepare_Tagand transmits thepre-encoded pulse train via
tag->pulse_train. It must not re-encode anything.Your platform no longer needs to read settings (team ID, player ID, weapon ID)
in either function; SystemK provides a fully populated
TagPacket_T.Example:
SystemK Interface Improvementsto SystemK v2.00: Interface Improvements@ -59,3 +59,3 @@#define NEC_COMMAND_ROKU_02_OK 3576350698#define NEC_COMMAND_ROKU_02_COUNTERCLOCKWISE 2272839658#define NEC_COMMAND_ROKU_02_ASTERIX 2272839658#define NEC_COMMAND_ROKU_02_ASTERIX 2657208298I don't know how this was wrong, but it was.
@ -75,1 +73,3 @@#define SYSTEMK_VERSION_STRING "01.01"#define SYSTEMK_MAJOR_VERSION 2#define SYSTEMK_MINOR_VERSION 0#define SYSTEMK_VERSION_STRING "02.00"We changed the interface, so we're changing the major version.