11#include "state_sync.h"
22#include "bt_conn.h"
3+ #include "link_protocol.h"
34#include "connections.h"
45#include "device.h"
56#include "device_state.h"
@@ -160,8 +161,27 @@ static state_sync_prop_t stateSyncProps[StateSyncPropertyId_Count] = {
160161 CUSTOM (KeyStatesDummy , SyncDirection_LeftToRight , DirtyState_Clean ),
161162 CUSTOM (DongleProtocolVersion , SyncDirection_DongleToRight , DirtyState_Clean ),
162163 SIMPLE (BatteryStationaryMode , SyncDirection_RightToLeft , DirtyState_Clean , & Cfg .BatteryStationaryMode ),
164+ // Emitted alongside ModuleState*; never independently dirtied.
165+ CUSTOM (ModuleGitRepo , SyncDirection_LeftToRight , DirtyState_Clean ),
166+ CUSTOM (ModuleGitTag , SyncDirection_LeftToRight , DirtyState_Clean ),
163167};
164168
169+ // Bytes a state-sync message occupies on top of its payload struct: the 3-byte
170+ // link header (src, dst, watermark - MessageOffset_Payload) plus the two message
171+ // id bytes (MessageId_StateSync and the property id).
172+ #define STATE_SYNC_MESSAGE_HEADER_LENGTH (MessageOffset_Payload + 2)
173+ // Largest payload struct that still fits in a single link packet.
174+ #define STATE_SYNC_MAX_PAYLOAD_LENGTH (MAX_LINK_PACKET_LENGTH - STATE_SYNC_MESSAGE_HEADER_LENGTH)
175+
176+ _Static_assert (sizeof (sync_command_layer_t ) <= STATE_SYNC_MAX_PAYLOAD_LENGTH ,
177+ "sync_command_layer_t does not fit in a link packet; reduce KEY_COUNT_PER_UPDATE" );
178+ _Static_assert (sizeof (sync_command_module_state_t ) <= STATE_SYNC_MAX_PAYLOAD_LENGTH ,
179+ "sync_command_module_state_t does not fit in a link packet" );
180+ _Static_assert (sizeof (sync_command_module_git_repo_t ) <= STATE_SYNC_MAX_PAYLOAD_LENGTH ,
181+ "sync_command_module_git_repo_t does not fit in a link packet" );
182+ _Static_assert (sizeof (sync_command_module_git_tag_t ) <= STATE_SYNC_MAX_PAYLOAD_LENGTH ,
183+ "sync_command_module_git_tag_t does not fit in a link packet" );
184+
165185static void invalidateProperty (state_sync_prop_id_t propId ) {
166186 STATE_SYNC_LOG ("<<< Invalidating property %s\n" , stateSyncProps [propId ].name );
167187 if (StateSyncPropertyId_LayerActionFirst <= propId &&
@@ -339,8 +359,6 @@ static void receiveModuleStateData(sync_command_module_state_t *buffer) {
339359 moduleState -> firmwareVersion = buffer -> firmwareVersion ;
340360 moduleState -> keyCount = buffer -> keyCount ;
341361 moduleState -> pointerCount = buffer -> pointerCount ;
342- Utils_SafeStrCopy (moduleState -> gitRepo , buffer -> gitRepo , MAX_STRING_PROPERTY_LENGTH );
343- Utils_SafeStrCopy (moduleState -> gitTag , buffer -> gitTag , MAX_STRING_PROPERTY_LENGTH );
344362 memcpy (moduleState -> firmwareChecksum , buffer -> firmwareChecksum , MD5_CHECKSUM_LENGTH );
345363
346364 if (DEVICE_IS_UHK80_RIGHT && leftModuleChanged ) {
@@ -446,6 +464,20 @@ static void receiveProperty(device_id_t src, state_sync_prop_id_t propId, const
446464 receiveModuleStateData ((sync_command_module_state_t * )data );
447465 }
448466 break ;
467+ case StateSyncPropertyId_ModuleGitRepo :
468+ if (!isLocalUpdate ) {
469+ sync_command_module_git_repo_t * buffer = (sync_command_module_git_repo_t * )data ;
470+ uint8_t driverId = UhkModuleSlaveDriver_SlotIdToDriverId (buffer -> slotId );
471+ Utils_SafeStrCopy (UhkModuleStates [driverId ].gitRepo , buffer -> gitRepo , MAX_STRING_PROPERTY_LENGTH );
472+ }
473+ break ;
474+ case StateSyncPropertyId_ModuleGitTag :
475+ if (!isLocalUpdate ) {
476+ sync_command_module_git_tag_t * buffer = (sync_command_module_git_tag_t * )data ;
477+ uint8_t driverId = UhkModuleSlaveDriver_SlotIdToDriverId (buffer -> slotId );
478+ Utils_SafeStrCopy (UhkModuleStates [driverId ].gitTag , buffer -> gitTag , MAX_STRING_PROPERTY_LENGTH );
479+ }
480+ break ;
449481 case StateSyncPropertyId_FunctionalColors :
450482 if (!isLocalUpdate ) {
451483 EventVector_Set (EventVector_LedMapUpdateNeeded );
@@ -565,27 +597,37 @@ static void prepareLayerActions(layer_id_t layerId, uint8_t slotId, uint8_t buff
565597
566598static void prepareAndSubmitLayer (device_id_t dst , state_sync_prop_id_t propId , layer_id_t layerId ) {
567599 sync_command_layer_t buffer ;
600+ buffer .layerId = layerId ;
568601
569- const uint8_t firstPacketLeftHalfActionCount = KEY_COUNT_PER_UPDATE ;
570- const uint8_t secondPacketLeftHalfActionCount = MAX_KEY_COUNT_PER_MODULE - KEY_COUNT_PER_UPDATE ;
571- const uint8_t secondPacketLeftModuleActionCount = MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE ;
602+ // Chunk the half-keyboard actions into KEY_COUNT_PER_UPDATE-sized packets. The
603+ // module actions ride in the last chunk if they fit, else in a trailing packet.
604+ bool moduleActionsSent = false ;
572605
573- buffer .layerId = layerId ;
574- buffer .startOffset = 0 ;
575- buffer .actionCount = firstPacketLeftHalfActionCount ;
576- buffer .moduleActionCount = 0 ;
606+ for (uint8_t halfOffset = 0 ; halfOffset < MAX_KEY_COUNT_PER_MODULE ; halfOffset += KEY_COUNT_PER_UPDATE ) {
607+ uint8_t halfCount = MIN (KEY_COUNT_PER_UPDATE , MAX_KEY_COUNT_PER_MODULE - halfOffset );
608+ bool isLastHalfChunk = halfOffset + halfCount >= MAX_KEY_COUNT_PER_MODULE ;
577609
578- prepareLayerActions (layerId , SlotId_LeftKeyboardHalf , 0 , 0 , firstPacketLeftHalfActionCount , & buffer );
579- submitPreparedData (dst , propId , (const uint8_t * )& buffer , sizeof (buffer ));
610+ buffer .startOffset = halfOffset ;
611+ buffer .actionCount = halfCount ;
612+ buffer .moduleActionCount = 0 ;
613+ prepareLayerActions (layerId , SlotId_LeftKeyboardHalf , 0 , halfOffset , halfCount , & buffer );
580614
581- buffer .layerId = layerId ;
582- buffer .startOffset = firstPacketLeftHalfActionCount ;
583- buffer .actionCount = secondPacketLeftHalfActionCount ;
584- buffer .moduleActionCount = secondPacketLeftModuleActionCount ;
615+ if (isLastHalfChunk && halfCount + MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE <= KEY_COUNT_PER_UPDATE ) {
616+ buffer .moduleActionCount = MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE ;
617+ prepareLayerActions (layerId , SlotId_LeftModule , halfCount , 0 , MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE , & buffer );
618+ moduleActionsSent = true;
619+ }
620+
621+ submitPreparedData (dst , propId , (const uint8_t * )& buffer , sizeof (buffer ));
622+ }
585623
586- prepareLayerActions (layerId , SlotId_LeftKeyboardHalf , 0 , firstPacketLeftHalfActionCount , secondPacketLeftHalfActionCount , & buffer );
587- prepareLayerActions (layerId , SlotId_LeftModule , secondPacketLeftHalfActionCount , 0 , secondPacketLeftModuleActionCount , & buffer );
588- submitPreparedData (dst , propId , (const uint8_t * )& buffer , sizeof (buffer ));
624+ if (!moduleActionsSent ) {
625+ buffer .startOffset = 0 ;
626+ buffer .actionCount = 0 ;
627+ buffer .moduleActionCount = MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE ;
628+ prepareLayerActions (layerId , SlotId_LeftModule , 0 , 0 , MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE , & buffer );
629+ submitPreparedData (dst , propId , (const uint8_t * )& buffer , sizeof (buffer ));
630+ }
589631}
590632
591633static void prepareBacklight (sync_command_backlight_t * buffer ) {
@@ -604,8 +646,6 @@ static void prepareLeftHalfStateData(sync_command_module_state_t *buffer) {
604646 buffer -> firmwareVersion = firmwareVersion ;
605647 buffer -> keyCount = MODULE_KEY_COUNT ;
606648 buffer -> pointerCount = MODULE_POINTER_COUNT ;
607- Utils_SafeStrCopy (buffer -> gitRepo , gitRepo , MAX_STRING_PROPERTY_LENGTH );
608- Utils_SafeStrCopy (buffer -> gitTag , gitTag , MAX_STRING_PROPERTY_LENGTH );
609649 memcpy (buffer -> firmwareChecksum , DeviceMD5Checksums [DEVICE_ID ], MD5_CHECKSUM_LENGTH );
610650#endif
611651}
@@ -619,11 +659,35 @@ static void prepareLeftModuleStateData(sync_command_module_state_t *buffer) {
619659 buffer -> firmwareVersion = moduleState -> firmwareVersion ;
620660 buffer -> keyCount = moduleState -> keyCount ;
621661 buffer -> pointerCount = moduleState -> pointerCount ;
622- memcpy (buffer -> gitRepo , moduleState -> gitRepo , MAX_STRING_PROPERTY_LENGTH );
623- memcpy (buffer -> gitTag , moduleState -> gitTag , MAX_STRING_PROPERTY_LENGTH );
624662 memcpy (buffer -> firmwareChecksum , moduleState -> firmwareChecksum , MD5_CHECKSUM_LENGTH );
625663}
626664
665+ static void prepareModuleGitRepo (device_id_t dst ) {
666+ sync_command_module_git_repo_t buffer = {};
667+
668+ buffer .slotId = SlotId_LeftKeyboardHalf ;
669+ Utils_SafeStrCopy (buffer .gitRepo , gitRepo , MAX_STRING_PROPERTY_LENGTH );
670+ submitPreparedData (dst , StateSyncPropertyId_ModuleGitRepo , (const uint8_t * )& buffer , sizeof (buffer ));
671+
672+ uhk_module_state_t * moduleState = UhkModuleStates + UhkModuleSlaveDriver_SlotIdToDriverId (SlotId_LeftModule );
673+ buffer .slotId = SlotId_LeftModule ;
674+ Utils_SafeStrCopy (buffer .gitRepo , moduleState -> gitRepo , MAX_STRING_PROPERTY_LENGTH );
675+ submitPreparedData (dst , StateSyncPropertyId_ModuleGitRepo , (const uint8_t * )& buffer , sizeof (buffer ));
676+ }
677+
678+ static void prepareModuleGitTag (device_id_t dst ) {
679+ sync_command_module_git_tag_t buffer = {};
680+
681+ buffer .slotId = SlotId_LeftKeyboardHalf ;
682+ Utils_SafeStrCopy (buffer .gitTag , gitTag , MAX_STRING_PROPERTY_LENGTH );
683+ submitPreparedData (dst , StateSyncPropertyId_ModuleGitTag , (const uint8_t * )& buffer , sizeof (buffer ));
684+
685+ uhk_module_state_t * moduleState = UhkModuleStates + UhkModuleSlaveDriver_SlotIdToDriverId (SlotId_LeftModule );
686+ buffer .slotId = SlotId_LeftModule ;
687+ Utils_SafeStrCopy (buffer .gitTag , moduleState -> gitTag , MAX_STRING_PROPERTY_LENGTH );
688+ submitPreparedData (dst , StateSyncPropertyId_ModuleGitTag , (const uint8_t * )& buffer , sizeof (buffer ));
689+ }
690+
627691static void prepareData (device_id_t dst , const uint8_t * propDataPtr , state_sync_prop_id_t propId ) {
628692 state_sync_prop_t * prop = & stateSyncProps [propId ];
629693 const uint8_t * data = propDataPtr ;
@@ -636,13 +700,13 @@ static void prepareData(device_id_t dst, const uint8_t *propDataPtr, state_sync_
636700
637701 switch (propId ) {
638702 case StateSyncPropertyId_LayerActionFirst ... StateSyncPropertyId_LayerActionLast : {
639- layer_id_t layerId = propId - StateSyncPropertyId_LayerActionFirst + LayerId_First ;
703+ uint8_t layerId = propId - StateSyncPropertyId_LayerActionFirst + LayerId_First ;
640704
641705 if (prop -> dirtyState == DirtyState_NeedsClearing ) {
642706 submitPreparedData (dst , StateSyncPropertyId_LayerActionsClear , & layerId , sizeof (layerId ));
643707 return ;
644708 } else {
645- // 2 packets!
709+ // split across multiple packets
646710 prepareAndSubmitLayer (dst , propId , layerId );
647711 return ;
648712 }
@@ -659,6 +723,14 @@ static void prepareData(device_id_t dst, const uint8_t *propDataPtr, state_sync_
659723 submitPreparedData (dst , propId , (const uint8_t * )& buffer , sizeof (buffer ));
660724 return ;
661725 } break ;
726+ case StateSyncPropertyId_ModuleGitRepo : {
727+ prepareModuleGitRepo (dst );
728+ return ;
729+ } break ;
730+ case StateSyncPropertyId_ModuleGitTag : {
731+ prepareModuleGitTag (dst );
732+ return ;
733+ } break ;
662734 case StateSyncPropertyId_Backlight : {
663735 sync_command_backlight_t buffer ;
664736 prepareBacklight (& buffer );
@@ -772,6 +844,8 @@ static bool handlePropertyUpdateLeftToRight() {
772844
773845 UPDATE_AND_RETURN_IF_DIRTY (StateSyncPropertyId_ModuleStateLeftHalf , UpdateResult_UpdatedHighPrio );
774846 UPDATE_AND_RETURN_IF_DIRTY (StateSyncPropertyId_ModuleStateLeftModule , UpdateResult_UpdatedHighPrio );
847+ UPDATE_AND_RETURN_IF_DIRTY (StateSyncPropertyId_ModuleGitRepo , UpdateResult_UpdatedLowPrio );
848+ UPDATE_AND_RETURN_IF_DIRTY (StateSyncPropertyId_ModuleGitTag , UpdateResult_UpdatedLowPrio );
775849 UPDATE_AND_RETURN_IF_DIRTY (StateSyncPropertyId_KeyStatesDummy , UpdateResult_UpdatedHighPrio );
776850 UPDATE_AND_RETURN_IF_DIRTY (StateSyncPropertyId_LeftModuleDisconnected , UpdateResult_UpdatedHighPrio );
777851 UPDATE_AND_RETURN_IF_DIRTY (StateSyncPropertyId_MergeSensor , UpdateResult_UpdatedHighPrio );
@@ -915,6 +989,8 @@ void StateSync_ResetRightLeftLink(bool bidirectional) {
915989 invalidateProperty (StateSyncPropertyId_Battery );
916990 invalidateProperty (StateSyncPropertyId_ModuleStateLeftHalf );
917991 invalidateProperty (StateSyncPropertyId_ModuleStateLeftModule );
992+ invalidateProperty (StateSyncPropertyId_ModuleGitRepo );
993+ invalidateProperty (StateSyncPropertyId_ModuleGitTag );
918994 invalidateProperty (StateSyncPropertyId_KeyStatesDummy );
919995 invalidateProperty (StateSyncPropertyId_MergeSensor );
920996 }
0 commit comments