Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions device/src/shell/shell_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "wormhole.h"
#include "stubs.h"
#include "slave_drivers/kboot_driver.h"
#include "slot.h"
#include "i2c_addresses.h"
#include "test_suite/test_suite.h"
#include "jitter_test.h"
Expand Down Expand Up @@ -112,16 +113,19 @@ static int cmd_uhk_testled(const struct shell *shell, size_t argc, char *argv[])

static int cmd_uhk_kboot_reset(const struct shell *shell, size_t argc, char *argv[])
{
KbootDriverState.i2cAddress = I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER;
KbootDriverState.slotId = SlotId_RightModule;
KbootDriverState.moduleBootloaderAddress = I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER;
KbootDriverState.phase = 0;
KbootDriverState.command = KbootCommand_Reset;
KbootDriverState.command = KbootCommand_ResetAndJump;
shell_fprintf(shell, SHELL_NORMAL, "Kboot reset sent to right module (0x%02x)\n",
I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER);
return 0;
}

static int cmd_uhk_kboot_flash(const struct shell *shell, size_t argc, char *argv[])
{
KbootDriverState.slotId = SlotId_RightModule;
KbootDriverState.moduleBootloaderAddress = I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER;
KbootDriverState.phase = 0;
KbootDriverState.command = KbootCommand_Flash;
shell_fprintf(shell, SHELL_NORMAL, "Kboot flash sequence started for right module\n");
Expand Down
81 changes: 59 additions & 22 deletions right/src/slave_drivers/kboot_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ static bool verifyRxCrc(uint8_t totalLen)

static void togglePingAddress(void)
{
KbootDriverState.i2cAddress = KbootDriverState.i2cAddress == I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER
KbootDriverState.i2cAddress = KbootDriverState.i2cAddress == KbootDriverState.moduleBootloaderAddress
? KBOOT_DEFAULT_I2C_ADDRESS
: I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER;
: KbootDriverState.moduleBootloaderAddress;
}

typedef void (*abort_fn_t)(const char *);
Expand Down Expand Up @@ -446,6 +446,7 @@ slave_result_t KbootSlaveDriver_Update(uint8_t kbootInstanceId)
break;

case KbootCommand_Ping:
LogU("Kboot: Ping command, target addr=0x%02x, phase=%d\n", KbootDriverState.i2cAddress, KbootDriverState.phase);
switch (KbootDriverState.phase) {
case KbootPhase_SendPing:
res.status = i2cTx(pingCommand, sizeof(pingCommand));
Expand Down Expand Up @@ -475,37 +476,72 @@ slave_result_t KbootSlaveDriver_Update(uint8_t kbootInstanceId)
break;

case KbootCommand_Reset:
if (handlePing(&res, KbootResetPhase_SendPing, KbootResetPhase_SendReset, abortReset)) {
if (KbootDriverState.phase == KbootResetPhase_SendReset) {
// Legacy buspal / UHK60 path: transmit the raw reset frame to the
// caller-supplied i2cAddress. The caller has already put the target
// module into its bootloader and pinged it, so no jump/ping is done
// here - doing so (and overwriting i2cAddress) would prevent the
// module from rebooting. Use KbootCommand_ResetAndJump for the
// self-contained variant.
LogU("Kboot: Reset command, target addr=0x%02x, phase=%d\n", KbootDriverState.i2cAddress, KbootDriverState.phase);
switch (KbootDriverState.phase) {
case KbootResetPhase_SendReset: {
uint8_t len = buildResetCommand();
res.status = i2cTx(txBuffer, len);
KbootDriverState.phase = KbootResetPhase_ReceiveResetAck;
break;
}
case KbootResetPhase_ReceiveResetAck:
res.status = i2cRx(KBOOT_PACKAGE_LENGTH_ACK);
KbootDriverState.phase = KbootResetPhase_ReceiveResetGenericResponse;
break;
case KbootResetPhase_ReceiveResetGenericResponse:
res.status = i2cRx(KBOOT_PACKAGE_LENGTH_GENERIC_RESPONSE);
KbootDriverState.phase = KbootResetPhase_CheckResetSendAck;
break;
case KbootResetPhase_CheckResetSendAck:
res.status = i2cTx(ackMessage, sizeof(ackMessage));
KbootDriverState.command = KbootCommand_Idle;
break;
}
break;

case KbootCommand_ResetAndJump:
// Testing code: just jump into bootloader, talk to it, and reset back.
//
// TODO: remove it once we are sure everything works and we don't need this
if (handlePing(&res, KbootResetAndJumpPhase_SendPing, KbootResetAndJumpPhase_SendReset, abortReset)) {
if (KbootDriverState.phase == KbootResetAndJumpPhase_SendReset) {
LogU("Kboot: Sending reset\n");
buildResetCommand();
startCmdTransaction(KbootCmdId_Reset, KbootResetPhase_Done, KBOOT_CMD_TIMEOUT_MS);
startCmdTransaction(KbootCmdId_Reset, KbootResetAndJumpPhase_Done, KBOOT_CMD_TIMEOUT_MS);
}
break;
}

switch (KbootDriverState.phase) {
case KbootResetPhase_JumpToBootloader:
LogU("Kboot: Jumping to bootloader for Reset\n");
Slaves[SlaveId_RightModule].isConnected = true;
UhkModuleStates[UhkModuleDriverId_RightModule].phase = UhkModulePhase_JumpToBootloader;
KbootDriverState.i2cAddress = I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER;
case KbootResetAndJumpPhase_JumpToBootloader: {
uint8_t driverId = UhkModuleSlaveDriver_SlotIdToDriverId(KbootDriverState.slotId);
LogU("Kboot: Jumping to bootloader for Reset (slot %u)\n", KbootDriverState.slotId);
Slaves[driverId].isConnected = true;
UhkModuleStates[driverId].phase = UhkModulePhase_JumpToBootloader;
KbootDriverState.i2cAddress = KbootDriverState.moduleBootloaderAddress;
KbootDriverState.startTime = Timer_GetCurrentTime();
KbootDriverState.phase = KbootResetPhase_WaitForBootloader;
KbootDriverState.phase = KbootResetAndJumpPhase_WaitForBootloader;
pingAttemptCount = 0;
break;
}

case KbootResetPhase_WaitForBootloader:
case KbootResetAndJumpPhase_WaitForBootloader:
if (elapsedMs() < KBOOT_WAIT_AFTER_JUMP_MS) {
break;
}
LogU("Kboot: Wait done (%dms), pinging at 0x%02x/0x%02x\n",
KBOOT_WAIT_AFTER_JUMP_MS,
I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER, KBOOT_DEFAULT_I2C_ADDRESS);
KbootDriverState.phase = KbootResetPhase_SendPing;
KbootDriverState.moduleBootloaderAddress, KBOOT_DEFAULT_I2C_ADDRESS);
KbootDriverState.phase = KbootResetAndJumpPhase_SendPing;
break;

case KbootResetPhase_Done:
case KbootResetAndJumpPhase_Done:
LogU("Kboot: Reset complete (%ums)\n", elapsedMs());
KbootDriverState.command = KbootCommand_Idle;
break;
Expand Down Expand Up @@ -543,12 +579,13 @@ slave_result_t KbootSlaveDriver_Update(uint8_t kbootInstanceId)
}
LogU("Kboot: Firmware ready, %u bytes. Jumping to bootloader\n",
KbootDriverState.firmwareSize);
// Force RightModule connected so the scheduler doesn't call
// UhkModuleSlaveDriver_Init (which would reset the phase we
// are about to set back to RequestSync).
Slaves[SlaveId_RightModule].isConnected = true;
UhkModuleStates[UhkModuleDriverId_RightModule].phase = UhkModulePhase_JumpToBootloader;
KbootDriverState.i2cAddress = I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER;
// Force the target module connected so the scheduler doesn't
// call UhkModuleSlaveDriver_Init (which would reset the phase
// we are about to set back to RequestSync).
uint8_t driverId = UhkModuleSlaveDriver_SlotIdToDriverId(KbootDriverState.slotId);
Slaves[driverId].isConnected = true;
UhkModuleStates[driverId].phase = UhkModulePhase_JumpToBootloader;
KbootDriverState.i2cAddress = KbootDriverState.moduleBootloaderAddress;
KbootDriverState.startTime = Timer_GetCurrentTime();
KbootDriverState.phase = KbootFlashPhase_WaitForBootloader;
pingAttemptCount = 0;
Expand All @@ -561,7 +598,7 @@ slave_result_t KbootSlaveDriver_Update(uint8_t kbootInstanceId)
}
LogU("Kboot: Wait done (%dms), pinging at 0x%02x/0x%02x\n",
KBOOT_WAIT_AFTER_JUMP_MS,
I2C_ADDRESS_RIGHT_MODULE_BOOTLOADER, KBOOT_DEFAULT_I2C_ADDRESS);
KbootDriverState.moduleBootloaderAddress, KBOOT_DEFAULT_I2C_ADDRESS);
KbootDriverState.phase = KbootFlashPhase_SendPing;
break;

Expand Down
36 changes: 29 additions & 7 deletions right/src/slave_drivers/kboot_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
KbootCommand_Ping,
KbootCommand_Reset,
KbootCommand_Flash,
KbootCommand_ResetAndJump,
} kboot_command_t;

typedef enum {
Expand All @@ -35,17 +36,33 @@
KbootPhase_CheckPingResponseStatus,
} kboot_ping_phase_t;

// Legacy reset (buspal / UHK60 path): the caller (agent) has already jumped
// the target module into its bootloader and pinged it, and supplies the
// target i2cAddress. We just transmit the raw reset frame to that address.
typedef enum {
KbootResetPhase_JumpToBootloader,
KbootResetPhase_WaitForBootloader,
KbootResetPhase_SendPing,
KbootResetPhase_CheckPingStatus,
KbootResetPhase_ReceivePingResponse,
KbootResetPhase_CheckPingResponseStatus,
KbootResetPhase_SendReset,
KbootResetPhase_Done,
KbootResetPhase_ReceiveResetAck,
KbootResetPhase_ReceiveResetGenericResponse,
KbootResetPhase_CheckResetSendAck,
} kboot_reset_phase_t;

// Self-contained reset (UHK80 native path / shell command): jump the right
// module into its bootloader, ping until it answers, then reset it. The
// target i2cAddress is set internally, not by the caller.
// SendPing..CheckPingResponseStatus are not handled by name in the switch -
// handlePing() walks them by offset from SendPing, so they must stay
// contiguous and in this order.
typedef enum {
KbootResetAndJumpPhase_JumpToBootloader,
KbootResetAndJumpPhase_WaitForBootloader,
KbootResetAndJumpPhase_SendPing,
KbootResetAndJumpPhase_CheckPingStatus,
KbootResetAndJumpPhase_ReceivePingResponse,
KbootResetAndJumpPhase_CheckPingResponseStatus,
KbootResetAndJumpPhase_SendReset,
KbootResetAndJumpPhase_Done,
} kboot_reset_and_jump_phase_t;

// Shared command transaction phases (reused by Flash and Reset).
// Values 240-249 so they don't collide with command-specific phases.
typedef enum {
Expand Down Expand Up @@ -89,7 +106,12 @@

typedef struct {
kboot_command_t command;
// i2c address we are actually talking to. Alternates between default and moduleBootloaderAddress.
uint8_t i2cAddress;
// slotId to target - specified by Agent
uint8_t slotId;
// expected module bootloader i2c address - specified by Agent
uint8_t moduleBootloaderAddress;
uint8_t phase;
uint32_t status;
uint32_t startTime;
Expand Down
8 changes: 8 additions & 0 deletions right/src/slave_drivers/uhk_module_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,14 @@ slave_result_t UhkModuleSlaveDriver_Update(uint8_t uhkModuleDriverId)
StateSync_UpdateProperty(StateSyncPropertyId_ModuleStateLeftModule, NULL);
}
#endif
LogU("Module %d initialized: protocol version %d.%d.%d, firmware version %d.%d.%d, git tag %s, git repo %s, firmware checksum %s\n",
uhkModuleDriverId,
uhkModuleState->moduleProtocolVersion.major, uhkModuleState->moduleProtocolVersion.minor, uhkModuleState->moduleProtocolVersion.patch,
uhkModuleState->firmwareVersion.major, uhkModuleState->firmwareVersion.minor, uhkModuleState->firmwareVersion.patch,
uhkModuleState->gitTag,
uhkModuleState->gitRepo,
uhkModuleState->firmwareChecksum
);
break;
}

Expand Down
6 changes: 5 additions & 1 deletion right/src/slave_scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ static uint8_t getNextSlaveId(uint8_t slaveId)
}
return slaveId;
#elif DEVICE_IS_UHK80_LEFT
return slaveId == SlaveId_LeftModule ? SlaveId_ModuleLeftLedDriver : SlaveId_LeftModule;
switch (slaveId) {
case SlaveId_LeftModule: return SlaveId_ModuleLeftLedDriver;
case SlaveId_ModuleLeftLedDriver: return SlaveId_KbootDriver;
default: return SlaveId_LeftModule;
}
#elif DEVICE_IS_UHK80_RIGHT
switch (slaveId) {
case SlaveId_RightModule: return SlaveId_RightTouchpad;
Expand Down
3 changes: 3 additions & 0 deletions right/src/usb_commands/usb_command_flash_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ typedef enum {
void UsbCommand_FlashModule(const uint8_t *GenericHidOutBuffer, uint8_t *GenericHidInBuffer)
{
uint8_t slotId = GetUsbRxBufferUint8(1);
uint8_t bootloaderI2cAddress = GetUsbRxBufferUint8(2);

if (!IS_VALID_MODULE_SLOT(slotId)) {
SetUsbTxBufferUint8(0, UsbStatusCode_FlashModule_InvalidSlotId);
Expand All @@ -26,6 +27,8 @@ void UsbCommand_FlashModule(const uint8_t *GenericHidOutBuffer, uint8_t *Generic
ModuleFlashBusy = true;
ModuleFlashErrorCode = 0;
ModuleFlashState = ModuleFlashState_Erasing;
KbootDriverState.slotId = slotId;
KbootDriverState.moduleBootloaderAddress = bootloaderI2cAddress;
KbootDriverState.phase = 0;
KbootDriverState.command = KbootCommand_Flash;
}
Loading