SDCL/sdcl-firmware/Core/Src/main.c

550 lines
16 KiB
C
Raw Normal View History

2022-05-08 00:48:07 +02:00
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2022 FaSTTUBe / Oskar W.
* All rights reserved.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdbool.h>
#include <string.h>
2022-05-08 00:48:07 +02:00
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
2023-04-07 00:18:34 +02:00
/*
* VAL_ 1040 Mission_selection
* 1 "MissionSelection_acceleration"
* 2 "MissionSelection_skidpad"
* 3 "MissionSelection_trackdrive"
* 4 "MissionSelection_braketest"
* 5 "MissionSelection_inspection"
* 6 "MissionSelection_autocross"
* 7 "MissionSelection_manual";
*/
typedef enum {
M_NONE = 0,
M_ACCEL = 1,
M_SKIDPAD = 2,
M_TRACKDRIVE = 3,
M_EBSTEST = 4,
M_INSPECTION = 5,
M_AUTOX = 6,
M_MANUAL = 7
} mission_t;
/*
* BO_ 15 SDCL_rx: 3 ABX
* SG_ as_close_sdc : 0|1@1+ (1,0) [0|1] "" SDCL
* SG_ sdcl_heartbeat : 1|1@1+ (1,0) [0|1] "" SDCL
* SG_ asb_error : 2|1@1+ (1,0) [0|1] "" SDCL
* SG_ as_mission : 4|3@1+ (1,0) [0|7] "" SDCL
*/
2022-05-08 00:48:07 +02:00
typedef union {
uint8_t raw[8]; // Must be 8 bytes because HAL always writes 8 bytes
2022-05-08 00:48:07 +02:00
struct {
// BITFIELDS ARE LSB FIRST!
2022-05-08 00:48:07 +02:00
bool as_close_sdc : 1;
2023-04-07 00:18:34 +02:00
bool heartbeat : 1;
bool asb_error : 1;
unsigned int _padding1 : 1;
2023-04-07 00:18:34 +02:00
mission_t as_mission : 3;
unsigned int _padding2 : 1;
2023-04-07 00:18:34 +02:00
} __attribute__((packed)) signals;
2022-05-08 00:48:07 +02:00
} rx_data_t;
/*
* BO_ 16 SDCL_tx: 4 SDCL
* SG_ asms_state : 0|1@1+ (1,0) [0|1] "" ABX
* SG_ sdc_state_1 : 1|1@1+ (1,0) [0|1] "" ABX
* SG_ sdc_state_2 : 2|1@1+ (1,0) [0|1] "" ABX
* SG_ sdc_state_3 : 3|1@1+ (1,0) [0|1] "" ABX
* SG_ heartbeat_ok : 4|1@1+ (1,0) [0|1] "" ABX
* SG_ sdcl_sdc_ready : 5|1@1+ (1,0) [0|1] "" ABX
* SG_ ts_start_muxed : 6|1@1+ (1,0) [0|1] "" ABX
* SG_ latch_init_open : 8|1@1+ (1,0) [0|1] "" ABX
* SG_ latch_closed : 9|1@1+ (1,0) [0|1] "" ABX
* SG_ latch_reopened : 10|1@1+ (1,0) [0|1] "" ABX
* SG_ as_mission : 11|3@1+ (1,0) [0|7] "" ABX
*/
2022-05-08 00:48:07 +02:00
typedef union {
2023-04-07 00:18:34 +02:00
uint8_t raw[2];
2022-05-08 00:48:07 +02:00
struct {
// BITFIELDS ARE LSB FIRST!
2023-04-07 00:18:34 +02:00
bool asms_state : 1;
bool sdc_state_1 : 1;
bool sdc_state_2 : 1;
bool sdc_state_3 : 1;
bool heartbeat_ok : 1;
2022-05-08 00:48:07 +02:00
bool sdc_ready : 1;
2023-04-07 00:18:34 +02:00
bool ts_start_muxed : 1;
unsigned int _padding1 : 1;
2023-04-07 00:18:34 +02:00
// -- byte border
bool latch_init_open : 1;
bool latch_closed : 1;
bool latch_reopened : 1;
mission_t as_mission : 3;
unsigned int _padding2 : 2;
2023-04-07 00:18:34 +02:00
} __attribute__((packed)) signals;
2022-05-08 00:48:07 +02:00
} tx_data_t;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
2023-04-07 00:18:34 +02:00
#define CAN_ID_RX 0x00F
#define CAN_ID_TX 0x010
2022-05-08 00:48:07 +02:00
2023-04-07 00:18:34 +02:00
// Defined in DBC?
2022-05-08 00:48:07 +02:00
#define TX_UPDATE_PERIOD 100
#define AMI_GPIO_Port GPIOB
//#define WATCHDOG_UCC
#define WATCHDOG_STM
2022-05-08 00:48:07 +02:00
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
CAN_HandleTypeDef hcan;
IWDG_HandleTypeDef hiwdg;
2022-05-08 00:48:07 +02:00
/* USER CODE BEGIN PV */
// Mission Maps: NONE ACCEL SKIDPAD TRACKDRIVE EBSTEST INSPECTION AUTOX MANUAL
const uint16_t mission2led[] = {0 , AMI_ACCEL_Pin , AMI_SKIDPAD_Pin , AMI_TRACKDRIVE_Pin, AMI_EBSTEST_Pin , AMI_INSPECTION_Pin, AMI_AUTOX_Pin , AMI_MANUAL_Pin};
const mission_t mission2next[] = {M_MANUAL , M_SKIDPAD , M_AUTOX , M_EBSTEST , M_INSPECTION , M_MANUAL , M_TRACKDRIVE , M_ACCEL };
mission_t mission = M_NONE;
2022-05-08 00:48:07 +02:00
#ifdef WATCHDOG_STM
bool pHeartbeat = false;
bool WD_OK = false;
bool WD_initialized = false;
#endif
2022-05-08 00:48:07 +02:00
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN_Init(void);
static void MX_IWDG_Init(void);
2022-05-08 00:48:07 +02:00
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void setMissionLED(mission_t mission, GPIO_PinState state)
{
if (mission != M_NONE)
HAL_GPIO_WritePin(AMI_GPIO_Port, mission2led[mission], state);
}
2022-05-08 00:48:07 +02:00
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
MX_GPIO_Init();
MX_CAN_Init();
#if false
2022-05-08 00:48:07 +02:00
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CAN_Init();
MX_IWDG_Init();
2022-05-08 00:48:07 +02:00
/* USER CODE BEGIN 2 */
#endif
2022-05-08 00:48:07 +02:00
// Ensure we start with SDC disabled
HAL_GPIO_WritePin(Watchdog_GPIO_Port, Watchdog_Pin, GPIO_PIN_RESET);
if (HAL_CAN_Start(&hcan) != HAL_OK)
Error_Handler();
CAN_FilterTypeDef canfilterconfig;
canfilterconfig.FilterActivation = CAN_FILTER_ENABLE;
canfilterconfig.FilterBank = 0;
canfilterconfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
2023-05-03 14:29:03 +02:00
canfilterconfig.FilterIdHigh = CAN_ID_RX << (16 - 11);
canfilterconfig.FilterIdLow = 0;
canfilterconfig.FilterMaskIdHigh = 0x7FF << (16 - 11);
canfilterconfig.FilterMaskIdLow = 0;
canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK;
canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT;
canfilterconfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan, &canfilterconfig) != HAL_OK) {
2022-05-08 00:48:07 +02:00
Error_Handler();
}
2022-05-08 00:48:07 +02:00
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
Error_Handler();
2022-05-08 00:48:07 +02:00
2023-04-07 00:18:34 +02:00
CAN_TxHeaderTypeDef txHeader;
uint32_t txMailbox;
tx_data_t txData;
2022-05-08 00:48:07 +02:00
2023-04-07 00:18:34 +02:00
memset(&txData, 0, sizeof(tx_data_t));
2022-05-08 00:48:07 +02:00
// Prep the tx frame
2023-04-07 00:18:34 +02:00
txHeader.IDE = CAN_ID_STD;
txHeader.StdId = CAN_ID_TX;
txHeader.RTR = CAN_RTR_DATA;
txHeader.DLC = 2;
2022-05-08 00:48:07 +02:00
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
2023-04-07 00:18:34 +02:00
bool pAMC = false;
mission_t new_mission = mission; // By default, don't change mission
2022-05-08 00:48:07 +02:00
// Important to prevent bus error state while ABX is starting up
2023-04-26 15:06:03 +02:00
HAL_Delay(1000);
MX_IWDG_Init();
WD_initialized = true;
2022-05-08 00:48:07 +02:00
while (true) {
2023-04-26 15:06:03 +02:00
bool TS_activate_MUXed = HAL_GPIO_ReadPin(TS_activate_MUXed_GPIO_Port, TS_activate_MUXed_Pin) == GPIO_PIN_RESET;
bool ASMS = HAL_GPIO_ReadPin(ASMS_GPIO_Port, ASMS_Pin) == GPIO_PIN_RESET;
#ifdef WATCHDOG_UCC
bool WD_OK = HAL_GPIO_ReadPin(WD_OK_GPIO_Port, WD_OK_Pin) == GPIO_PIN_RESET;
#endif
2023-04-07 00:18:34 +02:00
bool SDC_is_ready = HAL_GPIO_ReadPin(SDC_is_ready_GPIO_Port, SDC_is_ready_Pin) == GPIO_PIN_SET;
bool SDC_in_3V3 = HAL_GPIO_ReadPin(SDC_in_3V3_GPIO_Port, SDC_in_3V3_Pin) == GPIO_PIN_SET;
bool LV_SENSE_1 = HAL_GPIO_ReadPin(LV_SENSE_1_GPIO_Port, LV_SENSE_1_Pin) == GPIO_PIN_SET;
bool LV_SENSE_2 = HAL_GPIO_ReadPin(LV_SENSE_2_GPIO_Port, LV_SENSE_2_Pin) == GPIO_PIN_SET;
2023-04-26 15:06:03 +02:00
bool INITIAL_OPEN = HAL_GPIO_ReadPin(INITIAL_OPEN_GPIO_Port, INITIAL_OPEN_Pin) == GPIO_PIN_RESET;
bool CLOSED = HAL_GPIO_ReadPin(CLOSED_GPIO_Port, CLOSED_Pin) == GPIO_PIN_RESET;
bool REOPENED = HAL_GPIO_ReadPin(REOPENED_GPIO_Port, REOPENED_Pin) == GPIO_PIN_RESET;
2023-04-07 00:18:34 +02:00
bool AMC = HAL_GPIO_ReadPin(AMC_GPIO_Port, AMC_Pin) == GPIO_PIN_SET;
// On signal edge. Debouncing usually not needed at these polling rates (10Hz)
2023-04-07 00:18:34 +02:00
if (AMC < pAMC) {
// Reset LED to indicate transaction / mission change in progress
setMissionLED(mission, GPIO_PIN_RESET);
2023-04-07 00:18:34 +02:00
new_mission = mission2next[mission];
// New LED will be set once response from ABX is received
2023-04-07 00:18:34 +02:00
}
2023-04-26 15:06:03 +02:00
txData = (tx_data_t) {
2023-04-07 00:18:34 +02:00
.signals = {
.asms_state = ASMS,
.sdc_state_1 = LV_SENSE_1,
.sdc_state_2 = LV_SENSE_2,
.sdc_state_3 = SDC_in_3V3,
.heartbeat_ok = WD_OK,
.sdc_ready = SDC_is_ready,
.ts_start_muxed = TS_activate_MUXed,
2023-04-07 00:18:34 +02:00
.latch_init_open = INITIAL_OPEN,
.latch_closed = CLOSED,
.latch_reopened = REOPENED,
.as_mission = new_mission
2023-04-07 00:18:34 +02:00
}
};
2022-05-08 00:48:07 +02:00
2023-04-07 00:18:34 +02:00
if (HAL_CAN_AddTxMessage(&hcan, &txHeader, txData.raw, &txMailbox) != HAL_OK)
Error_Handler();
// Store previous button value to detect signal edges
2023-04-07 00:18:34 +02:00
pAMC = AMC;
HAL_Delay(TX_UPDATE_PERIOD);
2022-05-08 00:48:07 +02:00
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
2022-05-08 00:48:07 +02:00
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
2022-05-08 00:48:07 +02:00
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
2023-04-07 00:18:34 +02:00
2022-05-08 00:48:07 +02:00
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief CAN Initialization Function
* @param None
* @retval None
*/
static void MX_CAN_Init(void)
{
/* USER CODE BEGIN CAN_Init 0 */
/* USER CODE END CAN_Init 0 */
/* USER CODE BEGIN CAN_Init 1 */
/* USER CODE END CAN_Init 1 */
hcan.Instance = CAN;
hcan.Init.Prescaler = 1;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_13TQ;
hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
2023-04-26 15:06:03 +02:00
hcan.Init.AutoBusOff = ENABLE;
hcan.Init.AutoWakeUp = ENABLE;
hcan.Init.AutoRetransmission = ENABLE;
2022-05-08 00:48:07 +02:00
hcan.Init.ReceiveFifoLocked = DISABLE;
hcan.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN_Init 2 */
/* USER CODE END CAN_Init 2 */
}
/**
* @brief IWDG Initialization Function
* @param None
* @retval None
*/
static void MX_IWDG_Init(void)
{
/* USER CODE BEGIN IWDG_Init 0 */
/* USER CODE END IWDG_Init 0 */
/* USER CODE BEGIN IWDG_Init 1 */
/* USER CODE END IWDG_Init 1 */
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_4;
hiwdg.Init.Window = 1000;
hiwdg.Init.Reload = 1000;
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN IWDG_Init 2 */
/* USER CODE END IWDG_Init 2 */
}
2022-05-08 00:48:07 +02:00
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
2023-04-07 00:18:34 +02:00
HAL_GPIO_WritePin(GPIOB, AMI_EBSTEST_Pin|AMI_INSPECTION_Pin|ASB_Error_Pin|AMI_TRACKDRIVE_Pin
|AMI_AUTOX_Pin|AMI_SKIDPAD_Pin|AMI_ACCEL_Pin|AMI_MANUAL_Pin, GPIO_PIN_RESET);
2022-05-08 00:48:07 +02:00
2023-04-07 00:18:34 +02:00
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, AS_close_SDC_Pin|Watchdog_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : TS_activate_MUXed_Pin ASMS_Pin INITIAL_OPEN_Pin CLOSED_Pin
REOPENED_Pin WD_OK_Pin SDC_is_ready_Pin SDC_in_3V3_Pin
AMC_Pin */
GPIO_InitStruct.Pin = TS_activate_MUXed_Pin|ASMS_Pin|INITIAL_OPEN_Pin|CLOSED_Pin
|REOPENED_Pin|WD_OK_Pin|SDC_is_ready_Pin|SDC_in_3V3_Pin
|AMC_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : LV_SENSE_1_Pin LV_SENSE_2_Pin */
GPIO_InitStruct.Pin = LV_SENSE_1_Pin|LV_SENSE_2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
2023-04-07 00:18:34 +02:00
/*Configure GPIO pins : AMI_EBSTEST_Pin AMI_INSPECTION_Pin ASB_Error_Pin AMI_TRACKDRIVE_Pin
AMI_AUTOX_Pin AMI_SKIDPAD_Pin AMI_ACCEL_Pin AMI_MANUAL_Pin */
GPIO_InitStruct.Pin = AMI_EBSTEST_Pin|AMI_INSPECTION_Pin|ASB_Error_Pin|AMI_TRACKDRIVE_Pin
|AMI_AUTOX_Pin|AMI_SKIDPAD_Pin|AMI_ACCEL_Pin|AMI_MANUAL_Pin;
2022-05-08 00:48:07 +02:00
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
2023-04-07 00:18:34 +02:00
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
2022-05-08 00:48:07 +02:00
2023-04-07 00:18:34 +02:00
/*Configure GPIO pins : AS_close_SDC_Pin Watchdog_Pin */
GPIO_InitStruct.Pin = AS_close_SDC_Pin|Watchdog_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
2022-05-08 00:48:07 +02:00
}
/* USER CODE BEGIN 4 */
// CAN RX interrupt handler
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
2023-04-07 00:18:34 +02:00
CAN_RxHeaderTypeDef rxHeader;
rx_data_t rxData;
2022-05-08 00:48:07 +02:00
// Read frame from HW into buffer
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxData.raw) != HAL_OK)
2022-05-08 00:48:07 +02:00
Error_Handler();
// Discard if it's not for us (shouldn't happen thanks to filter, but just to be sure)
if (rxHeader.StdId != CAN_ID_RX)
return;
HAL_GPIO_WritePin(ASB_Error_GPIO_Port, ASB_Error_Pin, rxData.signals.asb_error);
HAL_GPIO_WritePin(AS_close_SDC_GPIO_Port, AS_close_SDC_Pin, rxData.signals.as_close_sdc);
#ifdef WATCHDOG_STM
if (rxData.signals.heartbeat != pHeartbeat) {
if (WD_initialized)
HAL_IWDG_Refresh(&hiwdg);
WD_OK = true;
HAL_GPIO_WritePin(Watchdog_GPIO_Port, Watchdog_Pin, GPIO_PIN_SET);
}
pHeartbeat = rxData.signals.heartbeat;
#endif
#ifdef WATCHDOG_UCC
HAL_GPIO_WritePin(Watchdog_GPIO_Port, Watchdog_Pin, rxData.signals.heartbeat);
#endif
// Reset old mission LED
setMissionLED(mission, GPIO_PIN_RESET);
mission = rxData.signals.as_mission;
setMissionLED(mission, GPIO_PIN_SET);
2022-05-08 00:48:07 +02:00
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */