/* Shared board-authoritative position/range state for every OTA application. * This file is included after the motor implementation so it can snapshot and * restore the proven per-axis runtime without changing the bundled source. */ static bool otaSeatStateLoaded; static bool otaSeatLastSaveOk; static uint32_t otaSeatPersistedMask; static uint32_t otaSeatStateSequence; static bool otaSeatJobActive; static bool otaSeatJobComplete; static bool otaSeatJobSuccess; static ota_seat_job_type_t otaSeatJobType = OTA_SEAT_JOB_NONE; static ota_seat_job_phase_t otaSeatJobPhase = OTA_SEAT_PHASE_IDLE; static uint8_t otaSeatJobAxis = 0x0Fu; static uint8_t otaSeatJobError; static uint8_t otaSeatJobProgress; static bool OtaSeat_SavePersistentState(void); static uint32_t OtaSeat_RuntimeKind(void) { #if (MOTOR_OTA_CALIBRATION != 0u) return OTA_SEAT_RUNTIME_CALIBRATION; #elif (MOTOR_OTA_SELF_COMPOSE != 0u) return OTA_SEAT_RUNTIME_DUAL_PROTOCOL; #else return OTA_SEAT_RUNTIME_FBL; #endif } static void OtaSeat_RestorePersistentState(void) { ota_seat_state_data_t stored; uint32_t axis; uint32_t savedIntrStatus; bool normalizePersistentState = false; otaSeatStateLoaded = OtaSeatState_Load(&stored); otaSeatLastSaveOk = otaSeatStateLoaded; otaSeatPersistedMask = 0ul; otaSeatStateSequence = 0ul; if(false == otaSeatStateLoaded) { return; } savedIntrStatus = Cy_SysLib_EnterCriticalSection(); otaSeatStateSequence = stored.sequence; otaSeatPersistedMask = 0ul; for(axis = 0ul; axis < MOTOR_PROFILE_COUNT; axis++) { uint32_t defaultRange = motorProfiles[axis].defaultMaxHallCount; motorRuntime[axis].maxHallCount = defaultRange; if((stored.validMask & (1ul << axis)) != 0ul) { uint32_t position = stored.position[axis]; /* The Base owns all four physical Hall ranges. Persistent storage * remembers position only and can never override a Base range. */ if(stored.range[axis] != defaultRange) { normalizePersistentState = true; } if(position > defaultRange) { position = defaultRange; normalizePersistentState = true; } motorRuntime[axis].positionHallCount = position; motorRuntime[axis].positionValid = true; otaSeatPersistedMask |= 1ul << axis; } } Cy_SysLib_ExitCriticalSection(savedIntrStatus); if(false != normalizePersistentState) { (void)OtaSeat_SavePersistentState(); } } static bool OtaSeat_SavePersistentState(void) { ota_seat_state_data_t state; uint32_t axis; uint32_t savedIntrStatus; state.sequence = otaSeatStateSequence + 1ul; state.validMask = 0ul; savedIntrStatus = Cy_SysLib_EnterCriticalSection(); for(axis = 0ul; axis < MOTOR_PROFILE_COUNT; axis++) { uint32_t range = motorProfiles[axis].defaultMaxHallCount; uint32_t position = motorRuntime[axis].positionHallCount; motorRuntime[axis].maxHallCount = range; if(position > range) { position = range; } state.range[axis] = range; state.position[axis] = position; if(false != motorRuntime[axis].positionValid) { state.validMask |= 1ul << axis; } } Cy_SysLib_ExitCriticalSection(savedIntrStatus); otaSeatLastSaveOk = OtaSeatState_Save(&state); if(false != otaSeatLastSaveOk) { otaSeatStateLoaded = true; otaSeatStateSequence = state.sequence; otaSeatPersistedMask = state.validMask; } return otaSeatLastSaveOk; } static uint32_t OtaSeat_JobStateValue(void) { uint32_t value = ((uint32_t)otaSeatJobType << OTA_SEAT_JOB_TYPE_SHIFT) | ((uint32_t)otaSeatJobPhase << OTA_SEAT_JOB_PHASE_SHIFT) | ((uint32_t)otaSeatJobAxis << OTA_SEAT_JOB_AXIS_SHIFT) | ((uint32_t)otaSeatJobError << OTA_SEAT_JOB_ERROR_SHIFT) | ((uint32_t)otaSeatJobProgress << OTA_SEAT_JOB_PROGRESS_SHIFT); if(false != otaSeatJobActive) value |= OTA_SEAT_JOB_ACTIVE; if(false != otaSeatJobComplete) value |= OTA_SEAT_JOB_COMPLETE; if(false != otaSeatJobSuccess) value |= OTA_SEAT_JOB_SUCCESS; if(false != otaSeatLastSaveOk) value |= OTA_SEAT_JOB_STORAGE_OK; return value; } static uint32_t OtaSeat_AxisPositionRangeValue(uint32_t axis) { uint32_t position; uint32_t range; uint32_t savedIntrStatus; savedIntrStatus = Cy_SysLib_EnterCriticalSection(); position = motorRuntime[axis].positionHallCount; range = motorRuntime[axis].maxHallCount; Cy_SysLib_ExitCriticalSection(savedIntrStatus); if(position > 65535ul) position = 65535ul; if(range > 65535ul) range = 65535ul; return (range << 16u) | position; } static uint32_t OtaSeat_AxisFlagsValue(uint32_t axis) { uint32_t value; uint32_t savedIntrStatus; savedIntrStatus = Cy_SysLib_EnterCriticalSection(); value = ((uint32_t)motorRuntime[axis].direction << OTA_SEAT_AXIS_DIRECTION_SHIFT) | ((uint32_t)motorRuntime[axis].lastEvent << OTA_SEAT_AXIS_EVENT_SHIFT); if(false != motorRuntime[axis].positionValid) { value |= OTA_SEAT_AXIS_VALID; } if((motorRuntime[axis].direction != MOTOR_DIRECTION_STOPPED) || (false != motorRuntime[axis].startPending)) { value |= OTA_SEAT_AXIS_MOVING; } if(false != motorRuntime[axis].calibrating) { value |= OTA_SEAT_AXIS_CALIBRATING; } Cy_SysLib_ExitCriticalSection(savedIntrStatus); if(false != driverFaultLatched) value |= OTA_SEAT_AXIS_DRIVER_FAULT; if((otaSeatPersistedMask & (1ul << axis)) != 0ul) { value |= OTA_SEAT_AXIS_PERSISTED; } return value; } static uint32_t OtaSeat_InfoValue(uint8_t selector) { uint32_t axis; if(selector == OTA_SEAT_INFO_JOB) { return OtaSeat_JobStateValue(); } if((selector >= OTA_SEAT_INFO_AXIS0_POSITION_RANGE) && (selector <= OTA_SEAT_INFO_AXIS3_POSITION_RANGE)) { axis = (uint32_t)(selector - OTA_SEAT_INFO_AXIS0_POSITION_RANGE); return OtaSeat_AxisPositionRangeValue(axis); } if((selector >= OTA_SEAT_INFO_AXIS0_FLAGS) && (selector <= OTA_SEAT_INFO_AXIS3_FLAGS)) { axis = (uint32_t)(selector - OTA_SEAT_INFO_AXIS0_FLAGS); return OtaSeat_AxisFlagsValue(axis); } if((selector >= OTA_SEAT_INFO_AXIS0_PHYSICAL_X100) && (selector <= OTA_SEAT_INFO_AXIS3_PHYSICAL_X100)) { axis = (uint32_t)(selector - OTA_SEAT_INFO_AXIS0_PHYSICAL_X100); return motorProfiles[axis].maxPhysicalValueX100; } if(selector == OTA_SEAT_INFO_STORAGE) { return (otaSeatPersistedMask & 0x0Ful) | ((false != otaSeatStateLoaded) ? (1ul << 8u) : 0ul) | ((false != otaSeatLastSaveOk) ? (1ul << 9u) : 0ul) | ((otaSeatStateSequence & 0xFFFFul) << 16u); } if(selector == OTA_SEAT_INFO_RUNTIME_KIND) { return OtaSeat_RuntimeKind(); } return 0ul; } static bool OtaSeat_HandleInfoControl(const ota_can_control_frame_t *frame) { uint8_t selector; if(frame->data[2] != OTA_OPCODE_SEAT_INFO) { return false; } selector = frame->data[3]; if(selector > OTA_SEAT_INFO_RUNTIME_KIND) { (void)OtaCan_QueueResponse(frame->data[1], frame->data[2], OTA_STATUS_BAD_ARGUMENT, selector); } else { (void)OtaCan_QueueResponse(frame->data[1], frame->data[2], OTA_STATUS_OK, OtaSeat_InfoValue(selector)); } return true; }