feat: update CAN integration and T2G seat firmware

This commit is contained in:
vee
2026-08-01 15:55:21 +08:00
parent 8cda026ac2
commit 4aded5c21d
1443 changed files with 1007122 additions and 4978 deletions
@@ -6,7 +6,6 @@
#include "cy_project.h"
#include "cy_device_headers.h"
#include "bsp_seat_move_can.h"
#include "motor_control.h"
#include "safety_manager.h"
#include "seat_move_application.h"
@@ -31,8 +30,6 @@ static void SeatMove_HoldSafeOff(void)
int main(void)
{
bool startupInhibited;
(void)BspSeatBackrestHeater_ForceOff();
(void)BspSeatFan_ForceOff();
SystemInit();
@@ -48,38 +45,28 @@ int main(void)
Cy_SysReset_ClearAllResetReasons();
SafetyManager_Init(g_seatMoveResetReason);
startupInhibited = SafetyManager_IsInhibited();
if(SafetyManager_IsInhibited())
{
SeatMove_HoldSafeOff();
}
__enable_irq();
g_seatMoveInitResult = Motor_Init();
if(g_seatMoveInitResult != MOTOR_API_SUCCESS)
{
SafetyManager_LatchFault(SAFETY_FAULT_DRIVER);
}
/* A retained reset/debug fault must remain fail-safe, but it must not
* suppress CAN diagnostics. Motor_Init() establishes the timer and SPI
* state needed by status reporting, so re-apply the inhibit afterwards. */
if(startupInhibited)
{
Motor_LatchSafetyInhibitFromIsr(0u);
Motor_ForceSafeOff();
SeatMove_HoldSafeOff();
}
Motor_SetWatchdogServiceEnabled(true);
if(!SeatControllerThermal_Init())
{
SafetyManager_LatchFault(SAFETY_FAULT_DRIVER);
SeatMove_HoldSafeOff();
}
if(!SeatMoveApplication_Init())
{
/* When CAN itself could not initialize there is no diagnostic path to
* preserve. Other startup failures remain visible through identity
* and inhibited status frames while every actuator stays safe-off. */
if(g_bspSeatMoveCanInitStatus != (uint32_t)CY_CANFD_SUCCESS)
{
SeatMove_HoldSafeOff();
}
SeatMove_HoldSafeOff();
}
for(;;)
@@ -2,6 +2,7 @@
#include "bsp_seat_backrest_heater.h"
#include "bsp_seat_backrest_heater_adc.h"
#include "motor_control.h"
#include "seat_backrest_heater_config.h"
volatile seat_backrest_heater_level_t g_seatBackrestHeaterRequestedLevel =
@@ -19,6 +20,7 @@ volatile uint16_t g_seatBackrestHeaterSenseRaw = 0u;
volatile uint32_t g_seatBackrestHeaterEstimatedCurrentMa = 0u;
static bool s_faultLatched = false;
static uint32_t s_activeStartTimeMs = 0u;
static uint32_t s_senseSampleElapsedMs = 0u;
static uint32_t s_senseConsecutiveErrors = 0u;
@@ -48,6 +50,7 @@ bool SeatBackrestHeater_Init(void)
}
s_faultLatched = false;
s_activeStartTimeMs = 0u;
s_senseSampleElapsedMs = 0u;
s_senseConsecutiveErrors = 0u;
g_seatBackrestHeaterRequestedLevel =
@@ -92,7 +95,12 @@ void SeatBackrestHeater_Task1ms(void)
if(g_seatBackrestHeaterAppliedLevel !=
SEAT_BACKREST_HEATER_LEVEL_OFF)
{
g_seatBackrestHeaterActiveTimeMs++;
/* The 1 ms application loop includes CAN service, ADC work and ISR
* latency, so counting loop iterations makes a nominal 600 s limit
* drift several seconds late. Use the motor driver's hardware
* monotonic timebase, which is already running before thermal init. */
g_seatBackrestHeaterActiveTimeMs =
(uint32_t)(Motor_GetTimeMs() - s_activeStartTimeMs);
if(g_seatBackrestHeaterActiveTimeMs >=
SEAT_BACKREST_HEATER_MAX_ACTIVE_TIME_MS)
{
@@ -160,6 +168,7 @@ bool SeatBackrestHeater_ClearFault(void)
g_seatBackrestHeaterState = SEAT_BACKREST_HEATER_STATE_OFF;
g_seatBackrestHeaterDutyPercent = 0u;
g_seatBackrestHeaterActiveTimeMs = 0u;
s_activeStartTimeMs = 0u;
s_senseConsecutiveErrors = 0u;
return true;
}
@@ -183,6 +192,7 @@ static bool SeatBackrestHeater_ApplyLevel(
g_seatBackrestHeaterState = SEAT_BACKREST_HEATER_STATE_OFF;
g_seatBackrestHeaterDutyPercent = 0u;
g_seatBackrestHeaterActiveTimeMs = 0u;
s_activeStartTimeMs = 0u;
return true;
}
@@ -207,6 +217,7 @@ static bool SeatBackrestHeater_ApplyLevel(
if(g_seatBackrestHeaterAppliedLevel ==
SEAT_BACKREST_HEATER_LEVEL_OFF)
{
s_activeStartTimeMs = Motor_GetTimeMs();
g_seatBackrestHeaterActiveTimeMs = 0u;
}
g_seatBackrestHeaterAppliedLevel = level;
@@ -1,6 +1,7 @@
#include "seat_controller_thermal.h"
#include "bsp_seat_backrest_heater.h"
#include "bsp_seat_current_adc.h"
#include "bsp_seat_fan.h"
#include "safety_manager.h"
#include "seat_backrest_heater.h"
@@ -12,6 +13,7 @@
#define SEAT_CONTROLLER_THERMAL_MODE_ID (0x3CEu)
#define SEAT_CONTROLLER_THERMAL_SWITCH_ID (0x42Au)
#define SEAT_CONTROLLER_THERMAL_FEEDBACK_ID (0x4FAu)
#define SEAT_CONTROLLER_THERMAL_CURRENT_DIAGNOSTIC_ID (0x305u)
#define SEAT_CONTROLLER_THERMAL_FEEDBACK_MS (100u)
volatile uint8_t g_seatControllerFanFeedbackRaw = 1u;
@@ -20,6 +22,9 @@ volatile uint32_t g_seatControllerThermalRxCount = 0u;
volatile uint32_t g_seatControllerThermalInvalidCount = 0u;
volatile uint32_t g_seatControllerThermalFeedbackTxCount = 0u;
volatile uint32_t g_seatControllerThermalFeedbackTxFailureCount = 0u;
volatile uint32_t g_seatControllerThermalOutputFaultStage = 0u;
volatile uint16_t g_seatControllerFanCurrentSenseRaw = 0u;
volatile uint32_t g_seatControllerFanCurrentAdcErrorCount = 0u;
static bool s_fanRunning = false;
static bool s_heaterModeValid = false;
@@ -32,6 +37,8 @@ static uint8_t s_heaterLastVehicleGear =
static uint8_t s_heaterConfiguredMaxLevel = 3u;
static uint32_t s_fanStartupRemainingMs = 0u;
static uint32_t s_feedbackElapsedMs = 0u;
static uint32_t s_fanCurrentSampleElapsedMs = 0u;
static bool s_fanCurrentSampleValid = false;
static void SeatControllerThermal_HandleControl29e(
const bsp_seat_move_can_frame_t *frame);
@@ -48,9 +55,12 @@ static void SeatControllerThermal_StopHeater(uint8_t feedbackRaw);
static uint8_t SeatControllerThermal_GearToDuty(uint8_t physicalGear);
static void SeatControllerThermal_LatchOutputFault(void);
static void SeatControllerThermal_ServiceFeedback(void);
static void SeatControllerThermal_ServiceFanCurrent(void);
bool SeatControllerThermal_Init(void)
{
uint16_t fanCurrentRaw;
if(!SeatBackrestHeater_Init())
{
SeatControllerThermal_ForceSafeOff();
@@ -61,6 +71,16 @@ bool SeatControllerThermal_Init(void)
SeatControllerThermal_ForceSafeOff();
return false;
}
if(!BspSeatCurrentAdc_Init() ||
!BspSeatCurrentAdc_Sample(BSP_SEAT_CURRENT_ADC_FAN,
&fanCurrentRaw))
{
SeatControllerThermal_ForceSafeOff();
return false;
}
g_seatControllerFanCurrentSenseRaw = fanCurrentRaw;
s_fanCurrentSampleValid = true;
s_fanCurrentSampleElapsedMs = 0u;
SeatControllerThermal_StopFan(1u);
SeatControllerThermal_StopHeater(1u);
@@ -101,6 +121,7 @@ void SeatControllerThermal_HandleFrame(const bsp_seat_move_can_frame_t *frame)
void SeatControllerThermal_Service1ms(void)
{
SeatBackrestHeater_Task1ms();
SeatControllerThermal_ServiceFanCurrent();
if((g_seatBackrestHeaterState ==
SEAT_BACKREST_HEATER_STATE_FAULT_SAFE_OFF) ||
(g_seatBackrestHeaterState ==
@@ -131,6 +152,7 @@ void SeatControllerThermal_Service1ms(void)
if((s_fanStartupRemainingMs == 0u) &&
!BspSeatFan_SetDutyPercent(s_fanTargetDutyPercent))
{
g_seatControllerThermalOutputFaultStage = 1u;
SeatControllerThermal_LatchOutputFault();
}
}
@@ -138,6 +160,28 @@ void SeatControllerThermal_Service1ms(void)
SeatControllerThermal_ServiceFeedback();
}
static void SeatControllerThermal_ServiceFanCurrent(void)
{
uint16_t raw;
s_fanCurrentSampleElapsedMs++;
if(s_fanCurrentSampleElapsedMs < SEAT_FAN_CURRENT_SAMPLE_MS)
{
return;
}
s_fanCurrentSampleElapsedMs = 0u;
if(BspSeatCurrentAdc_Sample(BSP_SEAT_CURRENT_ADC_FAN, &raw))
{
g_seatControllerFanCurrentSenseRaw = raw;
s_fanCurrentSampleValid = true;
}
else
{
g_seatControllerFanCurrentAdcErrorCount++;
s_fanCurrentSampleValid = false;
}
}
void SeatControllerThermal_ForceSafeOff(void)
{
SeatBackrestHeater_EmergencyOff();
@@ -159,7 +203,7 @@ static void SeatControllerThermal_HandleControl29e(
uint8_t heaterOn;
uint8_t heaterGear;
if(frame->dlc < 3u)
if(frame->dlc != SEAT_FAN_CAN_DLC)
{
g_seatControllerThermalInvalidCount++;
SeatControllerThermal_StopFan(0u);
@@ -183,6 +227,7 @@ static void SeatControllerThermal_HandleControl29e(
{
if(!SeatControllerThermal_RequestFan(fanGear))
{
g_seatControllerThermalOutputFaultStage = 2u;
SeatControllerThermal_LatchOutputFault();
}
}
@@ -202,6 +247,7 @@ static void SeatControllerThermal_HandleControl29e(
{
if(!SeatControllerThermal_RequestHeater(heaterGear))
{
g_seatControllerThermalOutputFaultStage = 3u;
SeatControllerThermal_LatchOutputFault();
}
}
@@ -219,7 +265,7 @@ static void SeatControllerThermal_HandleConfig2aa(
uint8_t fanConfig;
uint8_t heaterConfig;
if(frame->dlc < 3u)
if(frame->dlc != SEAT_FAN_CAN_DLC)
{
g_seatControllerThermalInvalidCount++;
return;
@@ -239,6 +285,7 @@ static void SeatControllerThermal_HandleConfig2aa(
if(s_fanRunning &&
!SeatControllerThermal_RequestFan(s_fanLastVehicleGear))
{
g_seatControllerThermalOutputFaultStage = 4u;
SeatControllerThermal_LatchOutputFault();
}
if(g_seatBackrestHeaterAppliedLevel !=
@@ -246,6 +293,7 @@ static void SeatControllerThermal_HandleConfig2aa(
{
if(!SeatControllerThermal_RequestHeater(s_heaterLastVehicleGear))
{
g_seatControllerThermalOutputFaultStage = 5u;
SeatControllerThermal_LatchOutputFault();
}
}
@@ -255,7 +303,7 @@ static void SeatControllerThermal_HandleMode3ce(
const bsp_seat_move_can_frame_t *frame)
{
uint8_t mode;
if(frame->dlc < 1u)
if(frame->dlc != SEAT_FAN_CAN_DLC)
{
s_heaterModeValid = false;
g_seatControllerThermalInvalidCount++;
@@ -276,7 +324,7 @@ static void SeatControllerThermal_HandleSwitch42a(
{
uint8_t fanSwitch;
uint8_t heaterSwitch;
if(frame->dlc < 1u)
if(frame->dlc != SEAT_FAN_CAN_DLC)
{
g_seatControllerThermalInvalidCount++;
SeatControllerThermal_StopFan(0u);
@@ -289,6 +337,7 @@ static void SeatControllerThermal_HandleSwitch42a(
{
if(!SeatControllerThermal_RequestFan(s_fanLastVehicleGear))
{
g_seatControllerThermalOutputFaultStage = 6u;
SeatControllerThermal_LatchOutputFault();
}
}
@@ -300,6 +349,7 @@ static void SeatControllerThermal_HandleSwitch42a(
{
if(!SeatControllerThermal_RequestHeater(s_heaterLastVehicleGear))
{
g_seatControllerThermalOutputFaultStage = 7u;
SeatControllerThermal_LatchOutputFault();
}
}
@@ -405,6 +455,13 @@ static void SeatControllerThermal_LatchOutputFault(void)
static void SeatControllerThermal_ServiceFeedback(void)
{
uint32_t data0;
uint32_t currentData0;
uint32_t currentData1;
uint8_t currentFlags;
uint8_t outputState;
uint8_t fanErrors;
uint8_t heaterErrors;
s_feedbackElapsedMs++;
if(!s_feedbackPending &&
(s_feedbackElapsedMs < SEAT_CONTROLLER_THERMAL_FEEDBACK_MS))
@@ -413,7 +470,31 @@ static void SeatControllerThermal_ServiceFeedback(void)
}
data0 = ((uint32_t)g_seatControllerFanFeedbackRaw & 0x07u) |
(((uint32_t)g_seatControllerHeaterFeedbackRaw & 0x07u) << 3u);
if(BspSeatMoveCan_Send(SEAT_CONTROLLER_THERMAL_FEEDBACK_ID, data0, 0u))
currentFlags = (uint8_t)
((s_fanCurrentSampleValid ? 0x01u : 0u) |
((g_seatBackrestHeaterState !=
SEAT_BACKREST_HEATER_STATE_FAULT_SAFE_OFF) ? 0x02u : 0u));
outputState = (uint8_t)
((s_fanRunning ? 0x01u : 0u) |
(((uint8_t)g_seatBackrestHeaterAppliedLevel & 0x03u) << 1u));
fanErrors = (g_seatControllerFanCurrentAdcErrorCount > UINT8_MAX) ?
UINT8_MAX :
(uint8_t)g_seatControllerFanCurrentAdcErrorCount;
heaterErrors = (g_seatBackrestHeaterAdcErrorCount > UINT8_MAX) ?
UINT8_MAX :
(uint8_t)g_seatBackrestHeaterAdcErrorCount;
currentData0 = (uint32_t)currentFlags |
((uint32_t)outputState << 8u) |
((uint32_t)g_seatControllerFanCurrentSenseRaw << 16u);
currentData1 = (uint32_t)g_seatBackrestHeaterSenseRaw |
((uint32_t)fanErrors << 16u) |
((uint32_t)heaterErrors << 24u);
if(BspSeatMoveCan_Send(SEAT_CONTROLLER_THERMAL_FEEDBACK_ID, data0, 0u) &&
BspSeatMoveCan_Send(
SEAT_CONTROLLER_THERMAL_CURRENT_DIAGNOSTIC_ID,
currentData0,
currentData1))
{
g_seatControllerThermalFeedbackTxCount++;
s_feedbackPending = false;
@@ -17,5 +17,9 @@ extern volatile uint32_t g_seatControllerThermalRxCount;
extern volatile uint32_t g_seatControllerThermalInvalidCount;
extern volatile uint32_t g_seatControllerThermalFeedbackTxCount;
extern volatile uint32_t g_seatControllerThermalFeedbackTxFailureCount;
/* Read-only HIL diagnostic; see seat_controller_thermal.c stage constants. */
extern volatile uint32_t g_seatControllerThermalOutputFaultStage;
extern volatile uint16_t g_seatControllerFanCurrentSenseRaw;
extern volatile uint32_t g_seatControllerFanCurrentAdcErrorCount;
#endif /* SEAT_CONTROLLER_THERMAL_H */
@@ -1,5 +1,7 @@
#include "seat_motor_manager.h"
#include "seat_move_config.h"
#include <stddef.h>
#include <string.h>
@@ -7,6 +9,7 @@
#define SEAT_MOTOR_SPEED_CAL_WARMUP_MS (500ul)
#define SEAT_MOTOR_SPEED_CAL_MEASURE_MS (1000ul)
#define SEAT_MOTOR_SPEED_CAL_DUTY_PERCENT (95u)
#define SEAT_MOTOR_DEFAULT_CAL_LEG_TIMEOUT_MS (70000ul)
typedef char seat_motor_manager_requires_four_motors[
(MOTOR_MODE_COUNT == 4) ? 1 : -1];
@@ -48,7 +51,7 @@ static uint32_t SeatMotor_MaxValueX100(motor_mode_t mode)
}
if(mode == MOTOR_MODE_1_ANGLE)
{
return MOTOR_MODE1_MAX_ANGLE_DEG_X100;
return MOTOR_MODE1_MAX_VERTICAL_MM_X100;
}
if(mode == MOTOR_MODE_2_ANGLE)
{
@@ -56,11 +59,32 @@ static uint32_t SeatMotor_MaxValueX100(motor_mode_t mode)
}
if(mode == MOTOR_MODE_3_LINEAR_TRACK)
{
return MOTOR_MODE3_MAX_POSITION_MM_X100;
return MOTOR_MODE3_MAX_ANGLE_DEG_X100;
}
return 0ul;
}
static uint8_t SeatMotor_DefaultDutyPercent(motor_mode_t mode)
{
if(mode == MOTOR_MODE_0_LINEAR)
{
return SEAT_MOVE_M0_DEFAULT_DUTY_PERCENT;
}
if(mode == MOTOR_MODE_1_ANGLE)
{
return SEAT_MOVE_M1_DEFAULT_DUTY_PERCENT;
}
if(mode == MOTOR_MODE_2_ANGLE)
{
return SEAT_MOVE_M2_DEFAULT_DUTY_PERCENT;
}
if(mode == MOTOR_MODE_3_LINEAR_TRACK)
{
return SEAT_MOVE_M3_DEFAULT_DUTY_PERCENT;
}
return 0u;
}
static bool SeatMotor_TimeReached(uint32_t now, uint32_t deadline)
{
return ((int32_t)(now - deadline) >= 0);
@@ -71,6 +95,26 @@ static uint32_t SeatMotor_AbsDelta(uint32_t lhs, uint32_t rhs)
return (lhs >= rhs) ? (lhs - rhs) : (rhs - lhs);
}
static bool SeatMotor_TargetWithinHallTolerance(
const seat_motor_task_t *task,
const motor_position_info_t *info)
{
uint32_t targetHallCount;
if((NULL == task) || (NULL == info) ||
(false == info->positionValid) || (0ul == info->maxValueX100) ||
(0ul == info->maxHallCount) ||
(task->targetValueX100 > info->maxValueX100))
{
return false;
}
targetHallCount = (uint32_t)
(((uint64_t)task->targetValueX100 * info->maxHallCount +
(info->maxValueX100 / 2ul)) / info->maxValueX100);
return SeatMotor_AbsDelta(targetHallCount, info->hallCount) <=
SEAT_MOVE_POSITION_TARGET_HALL_TOLERANCE;
}
static bool SeatMotor_DutyValid(uint8_t dutyPercent)
{
return (dutyPercent >= MOTOR_SPEED_MIN_DUTY_PERCENT) &&
@@ -496,6 +540,16 @@ void SeatMotorManager_Service(void)
(info.lastEvent == MOTOR_EVENT_FAR_ENDPOINT);
if((info.lastEvent == MOTOR_EVENT_STALL) || endpointEvent)
{
/* The low-level safety event has already stopped the hardware.
* At a discrete Hall endpoint, the mechanism may stop up to two
* pulses short of the mathematically rounded target. This is a
* successful position arrival, not a fault/retry condition. */
if(SeatMotor_TaskIsPosition(task) &&
SeatMotor_TargetWithinHallTolerance(task, &info))
{
SeatMotor_SetComplete(mode);
continue;
}
if(SeatMotor_TaskIsPosition(task) &&
(0u == task->retryCount))
{
@@ -619,6 +673,69 @@ bool SeatMotor_MoveRelativeDuty(motor_mode_t mode,
commandSequence);
}
bool SeatMotor_MoveAbsoluteNormalized(motor_mode_t mode,
uint32_t targetPercentX100,
uint32_t timeoutMs,
uint8_t dutyPercent,
uint32_t commandSequence)
{
motor_position_info_t info;
uint32_t targetValueX100;
if((targetPercentX100 > 10000ul) || (0ul == timeoutMs) ||
(MOTOR_API_SUCCESS != Motor_GetPositionInfo(mode, &info)) ||
(false == info.positionValid) || (0ul == info.maxValueX100))
{
return false;
}
targetValueX100 = (uint32_t)
((((uint64_t)targetPercentX100 * info.maxValueX100) + 5000ull) /
10000ull);
return SeatMotor_StartPositionTask(mode,
targetValueX100,
dutyPercent,
0ul,
timeoutMs,
commandSequence,
false,
false,
SEAT_MOTOR_TASK_POSITION);
}
bool SeatMotor_MoveRelativeNormalized(motor_mode_t mode,
int32_t deltaPercentX100,
uint32_t timeoutMs,
uint8_t dutyPercent,
uint32_t commandSequence)
{
motor_position_info_t info;
int32_t targetPercentX100;
if((MOTOR_API_SUCCESS != Motor_GetPositionInfo(mode, &info)) ||
(false == info.positionValid))
{
return false;
}
targetPercentX100 = (int32_t)info.percentX100 + deltaPercentX100;
if(targetPercentX100 < 0)
{
targetPercentX100 = 0;
}
else if(targetPercentX100 > 10000)
{
targetPercentX100 = 10000;
}
else
{
/* Target already lies in the normalized range. */
}
return SeatMotor_MoveAbsoluteNormalized(mode,
(uint32_t)targetPercentX100,
timeoutMs,
dutyPercent,
commandSequence);
}
bool SeatMotor_MoveTimedDuty(motor_mode_t mode,
motor_direction_t direction,
uint32_t durationMs,
@@ -793,19 +910,27 @@ bool SeatMotor_MoveAbsoluteInTime(motor_mode_t mode,
SEAT_MOTOR_TASK_POSITION);
}
bool SeatMotor_CalibrateRange(motor_mode_t mode, uint32_t commandSequence)
bool SeatMotor_CalibrateRange(motor_mode_t mode,
uint32_t legTimeoutMs,
uint32_t commandSequence)
{
motor_calibration_result_t result;
if(false == SeatMotor_ModeValid(mode))
if((false == SeatMotor_ModeValid(mode)) || (0ul == legTimeoutMs))
{
return false;
}
if((false == SeatMotor_PrepareNewTask(mode, commandSequence)) ||
(MOTOR_API_SUCCESS != Motor_SetFixedDutyPercent(
mode, MOTOR_SPEED_MIN_DUTY_PERCENT)) ||
(MOTOR_API_SUCCESS != Motor_Calibrate(mode,
mode, MOTOR_SPEED_MIN_DUTY_PERCENT)))
{
SeatMotor_SetFailed(mode, SEAT_MOTOR_RESULT_CALIBRATION_FAILED);
return false;
}
tasks[(uint32_t)mode].state = SEAT_MOTOR_TASK_RANGE_CALIBRATION;
if((MOTOR_API_SUCCESS != Motor_Calibrate(mode,
MOTOR_CALIBRATE_FIND_BOTH,
legTimeoutMs,
&result)) ||
(false == result.nearEndpointFound) ||
(false == result.farEndpointFound))
@@ -817,6 +942,39 @@ bool SeatMotor_CalibrateRange(motor_mode_t mode, uint32_t commandSequence)
return true;
}
bool SeatMotor_HomeKnownRange(motor_mode_t mode,
uint32_t legTimeoutMs,
uint32_t commandSequence)
{
motor_calibration_result_t result;
uint8_t dutyPercent;
if((false == SeatMotor_ModeValid(mode)) || (0ul == legTimeoutMs))
{
return false;
}
dutyPercent = SeatMotor_DefaultDutyPercent(mode);
if((false == SeatMotor_PrepareNewTask(mode, commandSequence)) ||
(MOTOR_API_SUCCESS != Motor_SetFixedDutyPercent(
mode, dutyPercent)))
{
SeatMotor_SetFailed(mode, SEAT_MOTOR_RESULT_CALIBRATION_FAILED);
return false;
}
tasks[(uint32_t)mode].state = SEAT_MOTOR_TASK_RANGE_CALIBRATION;
if((MOTOR_API_SUCCESS != Motor_Calibrate(mode,
MOTOR_CALIBRATE_FIND_NEAR,
legTimeoutMs,
&result)) ||
(false == result.nearEndpointFound))
{
SeatMotor_SetFailed(mode, SEAT_MOTOR_RESULT_CALIBRATION_FAILED);
return false;
}
SeatMotor_SetComplete(mode);
return true;
}
bool SeatMotor_StartMaximumSpeedCalibration(motor_mode_t mode,
uint32_t commandSequence)
{
@@ -852,6 +1010,27 @@ bool SeatMotor_StartMaximumSpeedCalibration(motor_mode_t mode,
return true;
}
bool SeatMotorManager_ClearFault(motor_mode_t mode)
{
seat_motor_task_t *task;
uint32_t sequence;
if((false == SeatMotor_ModeValid(mode)) || Motor_IsMoving(mode) ||
Motor_IsDriverFaultLatched())
{
return false;
}
task = &tasks[(uint32_t)mode];
if(false != task->active)
{
return false;
}
sequence = task->commandSequence;
(void)memset(task, 0, sizeof(*task));
task->commandSequence = sequence;
return true;
}
bool SeatMotor_RecoverPosition(motor_mode_t mode, uint32_t savedHallCount)
{
motor_calibration_result_t calibration;
@@ -860,6 +1039,7 @@ bool SeatMotor_RecoverPosition(motor_mode_t mode, uint32_t savedHallCount)
if((MOTOR_API_SUCCESS != Motor_Calibrate(mode,
MOTOR_CALIBRATE_FIND_NEAR,
SEAT_MOTOR_DEFAULT_CAL_LEG_TIMEOUT_MS,
&calibration)) ||
(false == calibration.nearEndpointFound) ||
(MOTOR_API_SUCCESS != Motor_GetPersistentState(mode, &state)))
@@ -911,7 +1091,14 @@ bool SeatMotorManager_GetStatus(motor_mode_t mode,
status->hallCount = position.hallCount;
status->maxHallCount = position.maxHallCount;
status->maxSpeedPpsX100 = persistent.maxSpeedPulsesPerSecondX100;
status->hallSpeedPpsX100 = speed.actualPulsesPerSecondX100;
status->positionPercentX100 = position.percentX100;
status->positionMmX100 = position.positionMmX100;
status->horizontalMmX100 = position.horizontalMmX100;
status->verticalMmX100 = position.verticalMmX100;
status->angleDegX100 = position.angleDegX100;
status->dutyPercent = speed.currentDutyPercent;
status->retryCount = task->retryCount;
status->active = task->active;
status->retried = (task->retryCount != 0u);
status->positionValid = position.positionValid;
@@ -13,6 +13,7 @@ typedef enum
SEAT_MOTOR_TASK_POSITION,
SEAT_MOTOR_TASK_TIMED,
SEAT_MOTOR_TASK_RETRY_DELAY,
SEAT_MOTOR_TASK_RANGE_CALIBRATION,
SEAT_MOTOR_TASK_SPEED_CAL_WARMUP,
SEAT_MOTOR_TASK_SPEED_CAL_MEASURE,
SEAT_MOTOR_TASK_SPEED_CAL_SETTLE,
@@ -45,7 +46,14 @@ typedef struct
uint32_t hallCount;
uint32_t maxHallCount;
uint32_t maxSpeedPpsX100;
uint32_t hallSpeedPpsX100;
uint32_t positionPercentX100;
uint32_t positionMmX100;
uint32_t horizontalMmX100;
uint32_t verticalMmX100;
uint32_t angleDegX100;
uint8_t dutyPercent;
uint8_t retryCount;
bool active;
bool retried;
bool positionValid;
@@ -64,6 +72,16 @@ bool SeatMotor_MoveAbsoluteDuty(motor_mode_t mode,
uint32_t targetValueX100,
uint8_t dutyPercent,
uint32_t commandSequence);
bool SeatMotor_MoveAbsoluteNormalized(motor_mode_t mode,
uint32_t targetPercentX100,
uint32_t timeoutMs,
uint8_t dutyPercent,
uint32_t commandSequence);
bool SeatMotor_MoveRelativeNormalized(motor_mode_t mode,
int32_t deltaPercentX100,
uint32_t timeoutMs,
uint8_t dutyPercent,
uint32_t commandSequence);
bool SeatMotor_MoveRelativeDuty(motor_mode_t mode,
int32_t deltaValueX100,
uint8_t dutyPercent,
@@ -94,9 +112,17 @@ bool SeatMotor_MoveAbsoluteInTime(motor_mode_t mode,
uint32_t commandSequence);
/* Range calibration is interruptible by Motor_RequestAbortAllFromIsr(). */
bool SeatMotor_CalibrateRange(motor_mode_t mode, uint32_t commandSequence);
bool SeatMotor_CalibrateRange(motor_mode_t mode,
uint32_t legTimeoutMs,
uint32_t commandSequence);
/* Re-establish zero at the known near endpoint while retaining the confirmed
* default MaxHall. This performs one near-seek only, not a full-range test. */
bool SeatMotor_HomeKnownRange(motor_mode_t mode,
uint32_t legTimeoutMs,
uint32_t commandSequence);
bool SeatMotor_StartMaximumSpeedCalibration(motor_mode_t mode,
uint32_t commandSequence);
bool SeatMotorManager_ClearFault(motor_mode_t mode);
/* Optional endpoint-based position recovery primitive. */
bool SeatMotor_RecoverPosition(motor_mode_t mode, uint32_t savedHallCount);
File diff suppressed because it is too large Load Diff
@@ -10,22 +10,35 @@
#define SEAT_MOVE_STORE_SLOT_WORDS (CY_WORK_SES_SIZE_IN_WORD)
#define SEAT_MOVE_STORE_SLOT_COUNT (2u)
#define SEAT_MOVE_STORE_LEGACY_V5_MAGIC (0x534D5635u) /* "SMV5" */
#define SEAT_MOVE_STORE_LEGACY_V5_VERSION (5u)
#define SEAT_MOVE_STORE_LEGACY_V6_MAGIC (0x534D5636u) /* "SMV6" */
#define SEAT_MOVE_STORE_LEGACY_V6_VERSION (6u)
#define SEAT_MOVE_STORE_LEGACY_V7_MAGIC (0x534D5637u) /* "SMV7" */
#define SEAT_MOVE_STORE_LEGACY_V7_VERSION (7u)
#define SEAT_MOVE_STORE_HEADER_WORDS (4u)
#define SEAT_MOVE_STORE_MOTOR_WORDS (5u)
#define SEAT_MOVE_STORE_MOTOR_WORDS (6u)
#define SEAT_MOVE_STORE_MOTOR_HALL (0u)
#define SEAT_MOVE_STORE_MOTOR_MAX_HALL (1u)
#define SEAT_MOVE_STORE_MOTOR_MAX_SPEED (2u)
#define SEAT_MOVE_STORE_MOTOR_RAW_EDGES (3u)
#define SEAT_MOVE_STORE_MOTOR_ABS_VALUE (4u)
#define SEAT_MOVE_STORE_MOTOR_VALID (5u)
#define SEAT_MOVE_STORE_CRC_WORD_INDEX \
(SEAT_MOVE_STORE_HEADER_WORDS + \
(SEAT_MOVE_MOTOR_COUNT * SEAT_MOVE_STORE_MOTOR_WORDS))
#define SEAT_MOVE_STORE_LEGACY_CRC_WORD_INDEX \
(SEAT_MOVE_STORE_HEADER_WORDS + \
(SEAT_MOVE_STORE_LEGACY_MOTOR_COUNT * SEAT_MOVE_STORE_MOTOR_WORDS))
typedef char seat_move_store_record_must_fit[
(SEAT_MOVE_STORE_CRC_WORD_INDEX < SEAT_MOVE_STORE_SLOT_WORDS) ? 1 : -1];
typedef char seat_move_store_slots_must_fit_work_flash[
((SEAT_MOVE_STORE_ADDRESS +
(SEAT_MOVE_STORE_SLOT_COUNT * CY_WORK_SES_SIZE_IN_BYTE)) <=
CY_WFLASH_SM_SBM_END) ? 1 : -1];
typedef enum
{
SEAT_MOVE_STORE_FORMAT_INVALID = 0,
SEAT_MOVE_STORE_FORMAT_LEGACY_THREE_MOTOR,
SEAT_MOVE_STORE_FORMAT_LEGACY_INCOMPATIBLE,
SEAT_MOVE_STORE_FORMAT_CURRENT_FOUR_MOTOR
} seat_move_store_format_t;
@@ -33,13 +46,21 @@ static uint32_t s_record[SEAT_MOVE_STORE_SLOT_WORDS];
static uint32_t s_activeSlot = 0u;
static bool s_valid = false;
static bool s_clean = false;
static seat_move_store_format_t s_format = SEAT_MOVE_STORE_FORMAT_INVALID;
static bool s_corrupt = false;
static uint32_t SeatMoveStore_Crc32(const uint32_t *words, uint32_t wordCount);
static uint32_t SeatMoveStore_SlotAddress(uint32_t slot);
static uint32_t SeatMoveStore_MaxValueX100(motor_mode_t mode);
static uint32_t SeatMoveStore_AbsoluteValueX100(motor_mode_t mode,
uint32_t hallCount,
uint32_t maxHallCount);
static seat_move_store_format_t SeatMoveStore_ReadSlot(
uint32_t slot, uint32_t *destination);
static bool SeatMoveStore_SequenceNewer(uint32_t candidate, uint32_t reference);
static bool SeatMoveStore_IsBlank(const uint32_t *record);
static bool SeatMoveStore_PayloadMatches(const uint32_t *candidate);
static bool SeatMoveStore_WriteRecord(const uint32_t *record,
uint32_t targetSlot);
void SeatMoveStore_Init(void)
{
@@ -54,14 +75,18 @@ void SeatMoveStore_Init(void)
Cy_FlashInit(false);
slot0Format = SeatMoveStore_ReadSlot(0u, slot0);
slot1Format = SeatMoveStore_ReadSlot(1u, slot1);
slot0Valid = (slot0Format != SEAT_MOVE_STORE_FORMAT_INVALID);
slot1Valid = (slot1Format != SEAT_MOVE_STORE_FORMAT_INVALID);
slot0Valid = (slot0Format == SEAT_MOVE_STORE_FORMAT_CURRENT_FOUR_MOTOR);
slot1Valid = (slot1Format == SEAT_MOVE_STORE_FORMAT_CURRENT_FOUR_MOTOR);
s_valid = slot0Valid || slot1Valid;
s_corrupt = !s_valid &&
(((slot0Format == SEAT_MOVE_STORE_FORMAT_INVALID) &&
!SeatMoveStore_IsBlank(slot0)) ||
((slot1Format == SEAT_MOVE_STORE_FORMAT_INVALID) &&
!SeatMoveStore_IsBlank(slot1)));
if(!s_valid)
{
s_clean = false;
s_activeSlot = 0u;
s_format = SEAT_MOVE_STORE_FORMAT_INVALID;
for(index = 0u; index < SEAT_MOVE_STORE_SLOT_WORDS; index++)
{
s_record[index] = 0xFFFFFFFFu;
@@ -73,7 +98,6 @@ void SeatMoveStore_Init(void)
(!slot0Valid || SeatMoveStore_SequenceNewer(slot1[2], slot0[2])))
{
s_activeSlot = 1u;
s_format = slot1Format;
for(index = 0u; index < SEAT_MOVE_STORE_SLOT_WORDS; index++)
{
s_record[index] = slot1[index];
@@ -82,7 +106,6 @@ void SeatMoveStore_Init(void)
else
{
s_activeSlot = 0u;
s_format = slot0Format;
for(index = 0u; index < SEAT_MOVE_STORE_SLOT_WORDS; index++)
{
s_record[index] = slot0[index];
@@ -93,33 +116,51 @@ void SeatMoveStore_Init(void)
bool SeatMoveStore_Restore(void)
{
motor_persistent_state_t states[SEAT_MOVE_MOTOR_COUNT];
uint32_t motorIndex;
uint32_t restoreMotorCount;
if(!s_valid || !s_clean)
{
return false;
}
/* Preserve the already calibrated motors 0..2 when upgrading an SMV2
* three-motor record. Motor3 remains at its estimated defaults with
* positionValid=false until it is physically connected and calibrated. */
restoreMotorCount =
(s_format == SEAT_MOVE_STORE_FORMAT_LEGACY_THREE_MOTOR) ?
SEAT_MOVE_STORE_LEGACY_MOTOR_COUNT : SEAT_MOVE_MOTOR_COUNT;
for(motorIndex = 0u; motorIndex < restoreMotorCount; motorIndex++)
for(motorIndex = 0u; motorIndex < SEAT_MOVE_MOTOR_COUNT; motorIndex++)
{
uint32_t base = SEAT_MOVE_STORE_HEADER_WORDS +
(motorIndex * SEAT_MOVE_STORE_MOTOR_WORDS);
motor_persistent_state_t state;
uint32_t savedAbsoluteValue;
uint32_t expectedAbsoluteValue;
state.positionHallCount = s_record[base];
state.maxHallCount = s_record[base + 1u];
state.maxSpeedPulsesPerSecondX100 = s_record[base + 2u];
state.rawRisingEdges = s_record[base + 3u];
state.positionValid = (s_record[base + 4u] == 1u);
states[motorIndex].positionHallCount =
s_record[base + SEAT_MOVE_STORE_MOTOR_HALL];
states[motorIndex].maxHallCount =
s_record[base + SEAT_MOVE_STORE_MOTOR_MAX_HALL];
states[motorIndex].maxSpeedPulsesPerSecondX100 =
s_record[base + SEAT_MOVE_STORE_MOTOR_MAX_SPEED];
states[motorIndex].rawRisingEdges =
s_record[base + SEAT_MOVE_STORE_MOTOR_RAW_EDGES];
savedAbsoluteValue =
s_record[base + SEAT_MOVE_STORE_MOTOR_ABS_VALUE];
states[motorIndex].positionValid =
(s_record[base + SEAT_MOVE_STORE_MOTOR_VALID] == 1u);
expectedAbsoluteValue = SeatMoveStore_AbsoluteValueX100(
(motor_mode_t)motorIndex,
states[motorIndex].positionHallCount,
states[motorIndex].maxHallCount);
if((s_record[base + SEAT_MOVE_STORE_MOTOR_VALID] > 1u) ||
(savedAbsoluteValue != expectedAbsoluteValue) ||
(MOTOR_API_SUCCESS != Motor_ValidatePersistentState(
(motor_mode_t)motorIndex,
&states[motorIndex])))
{
return false;
}
}
for(motorIndex = 0u; motorIndex < SEAT_MOVE_MOTOR_COUNT; motorIndex++)
{
if(MOTOR_API_SUCCESS != Motor_ApplyPersistentState(
(motor_mode_t)motorIndex, &state))
(motor_mode_t)motorIndex,
&states[motorIndex]))
{
return false;
}
@@ -127,15 +168,55 @@ bool SeatMoveStore_Restore(void)
return true;
}
void SeatMoveStore_RejectRestore(void)
{
/* A structurally valid record can still fail semantic validation (for
* example, an inconsistent Hall/physical value). Keep its sequence so
* the next clean save supersedes both flash slots, but never expose the
* record as restorable. This condition is recoverable by finding the
* known near endpoint; an actual flash erase/write failure remains a
* latched SAFETY_FAULT_CONFIG_STORE in the caller. */
s_clean = false;
s_corrupt = true;
}
bool SeatMoveStore_MarkMovementStarted(void)
{
uint32_t dirtyRecord[SEAT_MOVE_STORE_SLOT_WORDS];
uint32_t wordIndex;
uint32_t targetSlot;
/* No restorable state exists on a first boot or after an interrupted
* motion. There is therefore no stale clean record to invalidate. */
if(!s_valid || !s_clean)
{
s_clean = false;
return true;
}
for(wordIndex = 0u; wordIndex < SEAT_MOVE_STORE_SLOT_WORDS; wordIndex++)
{
dirtyRecord[wordIndex] = s_record[wordIndex];
}
dirtyRecord[2] = s_record[2] + 1u;
dirtyRecord[3] = 0u;
dirtyRecord[SEAT_MOVE_STORE_CRC_WORD_INDEX] =
SeatMoveStore_Crc32(dirtyRecord, SEAT_MOVE_STORE_CRC_WORD_INDEX);
targetSlot = s_activeSlot ^ 1u;
/* The dirty record is committed before PWM is allowed to start. If
* power fails while this blocking write is in progress, the old clean
* record still describes the unchanged pre-motion position. Once this
* call returns, the newer dirty sequence suppresses that old position. */
return SeatMoveStore_WriteRecord(dirtyRecord, targetSlot);
}
bool SeatMoveStore_Save(void)
{
uint32_t newRecord[SEAT_MOVE_STORE_SLOT_WORDS];
uint32_t motorIndex;
uint32_t wordIndex;
uint32_t targetSlot = s_valid ? (s_activeSlot ^ 1u) : 0u;
uint32_t address = SeatMoveStore_SlotAddress(targetSlot);
volatile const uint32_t *flashWords =
(volatile const uint32_t *)(uintptr_t)address;
for(wordIndex = 0u; wordIndex < SEAT_MOVE_STORE_SLOT_WORDS; wordIndex++)
{
@@ -151,46 +232,36 @@ bool SeatMoveStore_Save(void)
uint32_t base = SEAT_MOVE_STORE_HEADER_WORDS +
(motorIndex * SEAT_MOVE_STORE_MOTOR_WORDS);
motor_persistent_state_t state;
motor_position_info_t position;
if(MOTOR_API_SUCCESS != Motor_GetPersistentState(
(motor_mode_t)motorIndex, &state))
(motor_mode_t)motorIndex, &state) ||
MOTOR_API_SUCCESS != Motor_GetPositionInfo(
(motor_mode_t)motorIndex, &position))
{
return false;
}
newRecord[base] = state.positionHallCount;
newRecord[base + 1u] = state.maxHallCount;
newRecord[base + 2u] = state.maxSpeedPulsesPerSecondX100;
newRecord[base + 3u] = state.rawRisingEdges;
newRecord[base + 4u] = state.positionValid ? 1u : 0u;
newRecord[base + SEAT_MOVE_STORE_MOTOR_HALL] =
state.positionHallCount;
newRecord[base + SEAT_MOVE_STORE_MOTOR_MAX_HALL] =
state.maxHallCount;
newRecord[base + SEAT_MOVE_STORE_MOTOR_MAX_SPEED] =
state.maxSpeedPulsesPerSecondX100;
newRecord[base + SEAT_MOVE_STORE_MOTOR_RAW_EDGES] =
state.rawRisingEdges;
newRecord[base + SEAT_MOVE_STORE_MOTOR_ABS_VALUE] =
position.valueX100;
newRecord[base + SEAT_MOVE_STORE_MOTOR_VALID] =
state.positionValid ? 1u : 0u;
}
newRecord[SEAT_MOVE_STORE_CRC_WORD_INDEX] =
SeatMoveStore_Crc32(newRecord, SEAT_MOVE_STORE_CRC_WORD_INDEX);
Cy_FlashSectorErase(address, CY_FLASH_DRIVER_BLOCKING);
if(!Cy_WorkFlashBlankCheck(address, CY_FLASH_DRIVER_BLOCKING))
if(s_valid && s_clean && SeatMoveStore_PayloadMatches(newRecord))
{
return false;
return true;
}
for(wordIndex = 0u; wordIndex < SEAT_MOVE_STORE_SLOT_WORDS; wordIndex++)
{
Cy_FlashWriteWork(address + (wordIndex * sizeof(uint32_t)),
&newRecord[wordIndex],
CY_FLASH_DRIVER_BLOCKING);
}
for(wordIndex = 0u; wordIndex < SEAT_MOVE_STORE_SLOT_WORDS; wordIndex++)
{
if(flashWords[wordIndex] != newRecord[wordIndex])
{
return false;
}
s_record[wordIndex] = newRecord[wordIndex];
}
s_activeSlot = targetSlot;
s_valid = true;
s_clean = true;
s_format = SEAT_MOVE_STORE_FORMAT_CURRENT_FOUR_MOTOR;
return true;
return SeatMoveStore_WriteRecord(newRecord, targetSlot);
}
bool SeatMoveStore_IsValid(void)
@@ -203,6 +274,11 @@ bool SeatMoveStore_IsClean(void)
return s_clean;
}
bool SeatMoveStore_HasCorruptRecord(void)
{
return s_corrupt;
}
uint32_t SeatMoveStore_GetSequence(void)
{
return s_valid ? s_record[2] : 0u;
@@ -239,6 +315,43 @@ static uint32_t SeatMoveStore_SlotAddress(uint32_t slot)
return SEAT_MOVE_STORE_ADDRESS + (slot * CY_WORK_SES_SIZE_IN_BYTE);
}
static uint32_t SeatMoveStore_MaxValueX100(motor_mode_t mode)
{
switch(mode)
{
case MOTOR_MODE_0_LINEAR:
return MOTOR_MODE0_MAX_POSITION_MM_X100;
case MOTOR_MODE_1_ANGLE:
return MOTOR_MODE1_MAX_VERTICAL_MM_X100;
case MOTOR_MODE_2_ANGLE:
return MOTOR_MODE2_MAX_ANGLE_DEG_X100;
case MOTOR_MODE_3_LINEAR_TRACK:
return MOTOR_MODE3_MAX_ANGLE_DEG_X100;
default:
return 0u;
}
}
static uint32_t SeatMoveStore_AbsoluteValueX100(motor_mode_t mode,
uint32_t hallCount,
uint32_t maxHallCount)
{
uint32_t maxValue = SeatMoveStore_MaxValueX100(mode);
uint32_t boundedHall = hallCount;
if((0u == maxValue) || (0u == maxHallCount))
{
return UINT32_MAX;
}
if(boundedHall > maxHallCount)
{
boundedHall = maxHallCount;
}
return (uint32_t)((((uint64_t)boundedHall * maxValue) +
(maxHallCount / 2u)) /
maxHallCount);
}
static seat_move_store_format_t SeatMoveStore_ReadSlot(
uint32_t slot, uint32_t *destination)
{
@@ -266,13 +379,21 @@ static seat_move_store_format_t SeatMoveStore_ReadSlot(
{
return SEAT_MOVE_STORE_FORMAT_CURRENT_FOUR_MOTOR;
}
if((destination[0] == SEAT_MOVE_STORE_LEGACY_MAGIC) &&
(destination[1] == SEAT_MOVE_STORE_LEGACY_VERSION) &&
(destination[SEAT_MOVE_STORE_LEGACY_CRC_WORD_INDEX] ==
if((((destination[0] == SEAT_MOVE_STORE_LEGACY_V5_MAGIC) &&
(destination[1] == SEAT_MOVE_STORE_LEGACY_V5_VERSION)) ||
((destination[0] == SEAT_MOVE_STORE_LEGACY_V6_MAGIC) &&
(destination[1] == SEAT_MOVE_STORE_LEGACY_V6_VERSION)) ||
((destination[0] == SEAT_MOVE_STORE_LEGACY_V7_MAGIC) &&
(destination[1] == SEAT_MOVE_STORE_LEGACY_V7_VERSION))) &&
(destination[SEAT_MOVE_STORE_CRC_WORD_INDEX] ==
SeatMoveStore_Crc32(destination,
SEAT_MOVE_STORE_LEGACY_CRC_WORD_INDEX)))
SEAT_MOVE_STORE_CRC_WORD_INDEX)))
{
return SEAT_MOVE_STORE_FORMAT_LEGACY_THREE_MOTOR;
/* SMV5/SMV6 used obsolete Hall ranges. SMV7 stored the final
* numeric ranges against a non-identity channel map. Treat all as
* obsolete rather than corrupt, but never restore their positions.
* A new four-axis calibration will commit an SMV8 record. */
return SEAT_MOVE_STORE_FORMAT_LEGACY_INCOMPATIBLE;
}
return SEAT_MOVE_STORE_FORMAT_INVALID;
}
@@ -281,3 +402,82 @@ static bool SeatMoveStore_SequenceNewer(uint32_t candidate, uint32_t reference)
{
return ((int32_t)(candidate - reference) > 0);
}
static bool SeatMoveStore_IsBlank(const uint32_t *record)
{
uint32_t index;
if(record == NULL)
{
return false;
}
for(index = 0u; index < SEAT_MOVE_STORE_SLOT_WORDS; index++)
{
if(record[index] != 0xFFFFFFFFu)
{
return false;
}
}
return true;
}
static bool SeatMoveStore_PayloadMatches(const uint32_t *candidate)
{
uint32_t wordIndex;
if(candidate == NULL)
{
return false;
}
for(wordIndex = SEAT_MOVE_STORE_HEADER_WORDS;
wordIndex < SEAT_MOVE_STORE_CRC_WORD_INDEX;
wordIndex++)
{
if(candidate[wordIndex] != s_record[wordIndex])
{
return false;
}
}
return true;
}
static bool SeatMoveStore_WriteRecord(const uint32_t *record,
uint32_t targetSlot)
{
uint32_t address;
uint32_t wordIndex;
volatile const uint32_t *flashWords;
if((record == NULL) || (targetSlot >= SEAT_MOVE_STORE_SLOT_COUNT))
{
return false;
}
address = SeatMoveStore_SlotAddress(targetSlot);
flashWords = (volatile const uint32_t *)(uintptr_t)address;
Cy_FlashSectorErase(address, CY_FLASH_DRIVER_BLOCKING);
if(!Cy_WorkFlashBlankCheck(address, CY_FLASH_DRIVER_BLOCKING))
{
return false;
}
for(wordIndex = 0u; wordIndex < SEAT_MOVE_STORE_SLOT_WORDS; wordIndex++)
{
Cy_FlashWriteWork(address + (wordIndex * sizeof(uint32_t)),
&record[wordIndex],
CY_FLASH_DRIVER_BLOCKING);
}
for(wordIndex = 0u; wordIndex < SEAT_MOVE_STORE_SLOT_WORDS; wordIndex++)
{
if(flashWords[wordIndex] != record[wordIndex])
{
return false;
}
s_record[wordIndex] = record[wordIndex];
}
s_activeSlot = targetSlot;
s_valid = true;
s_clean = (record[3] == 1u);
s_corrupt = false;
return true;
}
@@ -6,9 +6,14 @@
void SeatMoveStore_Init(void);
bool SeatMoveStore_Restore(void);
/* Keep the record sequence for replacement, but make a failed restore
* non-restorable so known-range homing can rebuild a clean position. */
void SeatMoveStore_RejectRestore(void);
bool SeatMoveStore_MarkMovementStarted(void);
bool SeatMoveStore_Save(void);
bool SeatMoveStore_IsValid(void);
bool SeatMoveStore_IsClean(void);
bool SeatMoveStore_HasCorruptRecord(void);
uint32_t SeatMoveStore_GetSequence(void);
#endif /* SEAT_MOVE_STORE_H */