307 lines
9.3 KiB
C++
307 lines
9.3 KiB
C++
/* Included into the generated main_cm0plus.c for the eight Android-controlled
|
|
* direction-test images. It intentionally lives in the same translation unit
|
|
* so it can reuse the proven static motor safety/event implementation without
|
|
* changing the bundled third_party reference source. */
|
|
|
|
static bool otaInteractiveDriverInitOk;
|
|
static bool otaInteractiveFinalized = true;
|
|
|
|
static void OtaInteractive_ClearResult(void)
|
|
{
|
|
simpleDirectionResult.risingEdges = 0ul;
|
|
simpleDirectionResult.totalEdges = 0ul;
|
|
simpleDirectionResult.activeMs = 0ul;
|
|
simpleDirectionResult.safetyWindowPulses = 0ul;
|
|
simpleDirectionResult.driverStatus = 0u;
|
|
simpleDirectionResult.driverFaults = 0u;
|
|
simpleDirectionResult.finalHallLevel = 0u;
|
|
simpleDirectionResult.stopReason =
|
|
SIMPLE_DIRECTION_STOP_REASON_NOT_STARTED;
|
|
simpleDirectionResult.armed = false;
|
|
simpleDirectionResult.prepared = false;
|
|
simpleDirectionResult.timingValid = false;
|
|
simpleDirectionResult.diagnosticsValid = false;
|
|
simpleDirectionRunActive = false;
|
|
simpleDirectionRunComplete = false;
|
|
}
|
|
|
|
static void OtaInteractive_Finalize(void)
|
|
{
|
|
uint8_t driverStatus = 0u;
|
|
bool statusReadOk;
|
|
bool stopOk;
|
|
|
|
if((false == simpleDirectionRunComplete) ||
|
|
(false != otaInteractiveFinalized))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Motor_ServiceAll();
|
|
statusReadOk = Drv8718_ReadRegRaw(DRV8718_REG_IC_STAT1,
|
|
&driverStatus);
|
|
if(false != statusReadOk)
|
|
{
|
|
simpleDirectionResult.driverStatus = driverStatus;
|
|
simpleDirectionResult.driverFaults =
|
|
(uint16_t)(driverStatus & DRV8718_IC_STAT1_ALERT_MASK);
|
|
}
|
|
stopOk = (MOTOR_API_SUCCESS ==
|
|
Motor_StopMode((motor_mode_t)MOTOR_AUTOMATED_TEST_MODE));
|
|
if(false != stopOk)
|
|
{
|
|
stopOk = Motor_WaitForCoastToSettle(
|
|
(motor_mode_t)MOTOR_AUTOMATED_TEST_MODE);
|
|
}
|
|
simpleDirectionResult.diagnosticsValid = statusReadOk && stopOk;
|
|
SimpleDirectionTest_ImmediateAllOff();
|
|
(void)OtaSeat_SavePersistentState();
|
|
otaInteractiveFinalized = true;
|
|
}
|
|
|
|
static void OtaInteractive_Stop(void)
|
|
{
|
|
uint32_t savedIntrStatus;
|
|
|
|
if(false != simpleDirectionRunActive)
|
|
{
|
|
savedIntrStatus = Cy_SysLib_EnterCriticalSection();
|
|
Motor_RequestEventFromIsr(MOTOR_AUTOMATED_TEST_MODE,
|
|
MOTOR_EVENT_ABORTED);
|
|
Cy_SysLib_ExitCriticalSection(savedIntrStatus);
|
|
}
|
|
if((false == simpleDirectionRunComplete) &&
|
|
(false == otaInteractiveFinalized))
|
|
{
|
|
SimpleDirectionTest_ImmediateAllOff();
|
|
SimpleDirectionTest_CaptureStopFromIsr(
|
|
(uint32_t)(hallTimebaseTicks - simpleDirectionStartTicks),
|
|
Hall_ReadLevel(MOTOR_AUTOMATED_TEST_MODE),
|
|
SIMPLE_DIRECTION_STOP_REASON_ABORTED,
|
|
motorRuntime[MOTOR_AUTOMATED_TEST_MODE].recentWindowPulses);
|
|
}
|
|
OtaInteractive_Finalize();
|
|
}
|
|
|
|
static bool OtaInteractive_Start(void)
|
|
{
|
|
if((false != simpleDirectionRunActive) ||
|
|
(false != driverFaultLatched))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
OtaInteractive_ClearResult();
|
|
simpleDirectionResult.armed = true;
|
|
simpleDirectionResult.prepared =
|
|
SimpleDirectionTest_Prepare(otaInteractiveDriverInitOk);
|
|
if(false == simpleDirectionResult.prepared)
|
|
{
|
|
simpleDirectionResult.prepared = false;
|
|
SimpleDirectionTest_ImmediateAllOff();
|
|
return false;
|
|
}
|
|
|
|
/* OtaInteractiveTest_Run() and every completed/stopped test use
|
|
* SimpleDirectionTest_ImmediateAllOff(), which asserts the external
|
|
* DRVOFF pin. The original one-shot direction test never starts again
|
|
* after that call, but an interactive OTA image must explicitly release
|
|
* DRVOFF before each new TEST_START. Without this transition the SPI
|
|
* bridge/PWM setup succeeds while the DRV8718 power outputs remain
|
|
* hardware-disabled (IC_STAT1 still reads 0x80 and Hall stays at zero). */
|
|
Cy_GPIO_Clr(DRV_DRVOFF_PORT, DRV_DRVOFF_PIN);
|
|
Cy_SysTick_DelayInUs(100ul);
|
|
if(false == SimpleDirectionTest_Start())
|
|
{
|
|
simpleDirectionResult.prepared = false;
|
|
SimpleDirectionTest_ImmediateAllOff();
|
|
return false;
|
|
}
|
|
otaInteractiveFinalized = false;
|
|
return true;
|
|
}
|
|
|
|
static uint32_t OtaInteractive_StateValue(void)
|
|
{
|
|
uint32_t value =
|
|
((uint32_t)simpleDirectionResult.stopReason <<
|
|
OTA_TEST_STATE_STOP_REASON_SHIFT) |
|
|
((uint32_t)MOTOR_AUTOMATED_TEST_MODE <<
|
|
OTA_TEST_STATE_MODE_SHIFT) |
|
|
((uint32_t)MOTOR_AUTOMATED_TEST_DIRECTION <<
|
|
OTA_TEST_STATE_DIRECTION_SHIFT);
|
|
|
|
if(false != simpleDirectionRunActive)
|
|
{
|
|
value |= OTA_TEST_STATE_ACTIVE;
|
|
}
|
|
if(false != simpleDirectionRunComplete)
|
|
{
|
|
value |= OTA_TEST_STATE_COMPLETE;
|
|
}
|
|
if(false != driverFaultLatched)
|
|
{
|
|
value |= OTA_TEST_STATE_DRIVER_FAULT;
|
|
}
|
|
if(false != simpleDirectionResult.prepared)
|
|
{
|
|
value |= OTA_TEST_STATE_PREPARED;
|
|
}
|
|
if(false != simpleDirectionResult.timingValid)
|
|
{
|
|
value |= OTA_TEST_STATE_TIMING_VALID;
|
|
}
|
|
if(false != simpleDirectionResult.diagnosticsValid)
|
|
{
|
|
value |= OTA_TEST_STATE_DIAGNOSTICS_VALID;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static uint32_t OtaInteractive_InfoValue(uint8_t selector)
|
|
{
|
|
switch((ota_test_info_selector_t)selector)
|
|
{
|
|
case OTA_TEST_INFO_STATE:
|
|
return OtaInteractive_StateValue();
|
|
case OTA_TEST_INFO_RISING_EDGES:
|
|
return simpleDirectionResult.risingEdges;
|
|
case OTA_TEST_INFO_TOTAL_EDGES:
|
|
return simpleDirectionResult.totalEdges;
|
|
case OTA_TEST_INFO_ACTIVE_MS:
|
|
return simpleDirectionResult.activeMs;
|
|
case OTA_TEST_INFO_SAFETY_WINDOW_PULSES:
|
|
return simpleDirectionResult.safetyWindowPulses;
|
|
case OTA_TEST_INFO_DRIVER_DIAGNOSTICS:
|
|
return ((uint32_t)simpleDirectionResult.driverFaults << 16u) |
|
|
(uint32_t)simpleDirectionResult.driverStatus;
|
|
default:
|
|
return 0ul;
|
|
}
|
|
}
|
|
|
|
static void OtaInteractive_Respond(const ota_can_control_frame_t *frame,
|
|
ota_status_t status,
|
|
uint32_t value)
|
|
{
|
|
(void)OtaCan_QueueResponse(frame->data[1], frame->data[2],
|
|
(uint8_t)status, value);
|
|
}
|
|
|
|
static void OtaInteractive_EnterBootloader(
|
|
const ota_can_control_frame_t *frame)
|
|
{
|
|
uint32_t waitMs;
|
|
|
|
OtaInteractive_Stop();
|
|
(void)OtaSeat_SavePersistentState();
|
|
OtaInteractive_Respond(frame, OTA_STATUS_OK,
|
|
OtaInteractive_StateValue());
|
|
for(waitMs = 0ul; waitMs < 100ul; waitMs++)
|
|
{
|
|
OtaCan_Service();
|
|
if(false != OtaCan_TxIdle())
|
|
{
|
|
break;
|
|
}
|
|
Cy_SysTick_DelayInUs(1000ul);
|
|
}
|
|
SimpleDirectionTest_ImmediateAllOff();
|
|
Ota_EnterBootloader();
|
|
}
|
|
|
|
static void OtaInteractive_HandleControl(
|
|
const ota_can_control_frame_t *frame)
|
|
{
|
|
uint8_t opcode = frame->data[2];
|
|
|
|
if(frame->data[0] != OTA_CONTROL_MAGIC)
|
|
{
|
|
OtaInteractive_Respond(frame, OTA_STATUS_BAD_MAGIC, 0ul);
|
|
return;
|
|
}
|
|
|
|
if(false != OtaSeat_HandleInfoControl(frame))
|
|
{
|
|
return;
|
|
}
|
|
switch((ota_opcode_t)opcode)
|
|
{
|
|
case OTA_OPCODE_TEST_INFO:
|
|
if(frame->data[3] > OTA_TEST_INFO_DRIVER_DIAGNOSTICS)
|
|
{
|
|
OtaInteractive_Respond(frame, OTA_STATUS_BAD_ARGUMENT,
|
|
frame->data[3]);
|
|
}
|
|
else
|
|
{
|
|
OtaInteractive_Respond(
|
|
frame, OTA_STATUS_OK,
|
|
OtaInteractive_InfoValue(frame->data[3]));
|
|
}
|
|
break;
|
|
case OTA_OPCODE_TEST_START:
|
|
if(false != OtaInteractive_Start())
|
|
{
|
|
OtaInteractive_Respond(frame, OTA_STATUS_OK,
|
|
OtaInteractive_StateValue());
|
|
}
|
|
else
|
|
{
|
|
OtaInteractive_Respond(frame, OTA_STATUS_BAD_STATE,
|
|
OtaInteractive_StateValue());
|
|
}
|
|
break;
|
|
case OTA_OPCODE_TEST_STOP:
|
|
OtaInteractive_Stop();
|
|
OtaInteractive_Respond(frame, OTA_STATUS_OK,
|
|
OtaInteractive_StateValue());
|
|
break;
|
|
case OTA_OPCODE_ENTER_BOOTLOADER:
|
|
OtaInteractive_EnterBootloader(frame);
|
|
break;
|
|
default:
|
|
OtaInteractive_Respond(frame, OTA_STATUS_BAD_OPCODE, opcode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int OtaInteractiveTest_Run(bool driverInitOk)
|
|
{
|
|
ota_can_control_frame_t frame;
|
|
|
|
/* Keep the original one-shot runner linked for source-level parity; the
|
|
* interactive build intentionally dispatches through this loop instead. */
|
|
(void)SimpleDirectionTest_Run;
|
|
otaInteractiveDriverInitOk = driverInitOk;
|
|
OtaInteractive_ClearResult();
|
|
OtaSeat_RestorePersistentState();
|
|
SimpleDirectionTest_ImmediateAllOff();
|
|
OtaCan_DebugStart();
|
|
if(false == OtaCan_Init())
|
|
{
|
|
for(;;)
|
|
{
|
|
SimpleDirectionTest_ImmediateAllOff();
|
|
}
|
|
}
|
|
|
|
for(;;)
|
|
{
|
|
Motor_ServiceAll();
|
|
OtaCan_Service();
|
|
|
|
if((false != simpleDirectionRunComplete) &&
|
|
(false == otaInteractiveFinalized))
|
|
{
|
|
OtaInteractive_Finalize();
|
|
}
|
|
while(false != OtaCan_PopControl(&frame))
|
|
{
|
|
OtaInteractive_HandleControl(&frame);
|
|
OtaCan_Service();
|
|
}
|
|
__WFI();
|
|
}
|
|
}
|