feat: update CAN integration and T2G seat firmware
This commit is contained in:
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user