Subversion Repositories canSerial

Rev

Rev 2 | Rev 4 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 mjames 1
/* USER CODE BEGIN Header */
2
/**
3
 ******************************************************************************
4
 * @file           : main.c
5
 * @brief          : Main program body
6
 ******************************************************************************
7
 * @attention
8
 *
9
 * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
10
 * All rights reserved.</center></h2>
11
 *
12
 * This software component is licensed by ST under BSD 3-Clause license,
13
 * the "License"; You may not use this file except in compliance with the
14
 * License. You may obtain a copy of the License at:
15
 *                        opensource.org/licenses/BSD-3-Clause
16
 *
17
 ******************************************************************************
18
 */
19
/* USER CODE END Header */
20
/* Includes ------------------------------------------------------------------*/
21
#include "main.h"
22
 
23
/* Private includes ----------------------------------------------------------*/
24
/* USER CODE BEGIN Includes */
3 mjames 25
#include "display.h"
26
 
2 mjames 27
#include "string.h"
28
#include "base64.h"
29
#include "libSerial/serial.H"
3 mjames 30
#include "libSerial/serialUtils.H"
2 mjames 31
#include "libSmallPrintf/small_printf.h"
32
 
33
/* USER CODE END Includes */
34
 
35
/* Private typedef -----------------------------------------------------------*/
36
/* USER CODE BEGIN PTD */
37
 
38
typedef enum
39
{
40
  FAIL,
41
  REJECT,
42
  ACCEPT,
43
  COMPLETE
44
} appendStatus;
45
 
46
typedef struct
47
{
48
  uint8_t payloadBuffer[233];
49
  uint32_t payloadId;
50
  uint8_t payloadRemaining;  // number of bytes remaining
51
  uint8_t payloadTotal;      // number total number of bytes
52
  uint8_t payloadOffset;     // byte offset
53
  uint8_t payloadNextSeq;    // next sequence frame expected
54
  uint32_t payloadTimestamp; // timestamp of reception
55
  appendStatus status;
56
} contextType;
57
 
58
/* USER CODE END PTD */
59
 
60
/* Private define ------------------------------------------------------------*/
61
/* USER CODE BEGIN PD */
62
/* USER CODE END PD */
63
 
64
/* Private macro -------------------------------------------------------------*/
65
/* USER CODE BEGIN PM */
66
#define False (0)
67
#define True (1)
68
/* USER CODE END PM */
69
 
70
/* Private variables ---------------------------------------------------------*/
71
CAN_HandleTypeDef hcan;
72
 
3 mjames 73
SPI_HandleTypeDef hspi1;
74
 
2 mjames 75
UART_HandleTypeDef huart1;
76
 
77
/* USER CODE BEGIN PV */
78
 
79
/* USER CODE END PV */
80
 
81
/* Private function prototypes -----------------------------------------------*/
82
void SystemClock_Config(void);
83
static void MX_GPIO_Init(void);
84
static void MX_CAN_Init(void);
85
static void MX_USART1_UART_Init(void);
3 mjames 86
static void MX_SPI1_Init(void);
2 mjames 87
/* USER CODE BEGIN PFP */
88
 
89
/* USER CODE END PFP */
90
 
91
/* Private user code ---------------------------------------------------------*/
92
/* USER CODE BEGIN 0 */
93
 
94
#define CONTEXTS 6
95
contextType contexts[CONTEXTS];
96
 
97
CAN_TxHeaderTypeDef TxHeader;
98
CAN_RxHeaderTypeDef RxHeader;
99
 
100
uint8_t TxData[8];
101
uint8_t RxData[8];
102
 
103
// Storage for the data
104
 
105
uint32_t TxMailbox;
106
 
107
char const version[] = "$PDGY,Mike_James_Converter_#00001_Mode:15\r\n";
108
char const keepawake[] = "$PDGY,000000,1,,4,%ld.%03ld,,,\r\n";
109
 
110
// reset a search context
111
void resetContext(contextType *c)
112
{
113
  c->payloadRemaining = 0; // number of bytes remaining
114
  c->payloadTotal = 0;     // number total number of bytes
115
  c->payloadOffset = 0;
116
  c->payloadNextSeq = 0;
117
  c->payloadTimestamp = 0;
118
  c->status = FAIL;
119
  c->payloadId = 0;
120
}
121
 
122
uint8_t singleFrame(uint32_t pgn)
123
{
124
 
125
  switch (pgn)
126
  {
127
  case 129029:
128
  case 129038:
129
  case 126996:
130
  case 127489:
131
    return False;
132
  default:
133
    break;
134
  }
135
 
136
  if (pgn >= 130816 && pgn <= 131071)
137
    return False;
138
  if (pgn >= 65536 && pgn <= 126975)
139
    return False;
140
  return True;
141
}
142
 
143
// called from CAN frame callback
144
appendStatus append(contextType *c, CAN_RxHeaderTypeDef *packet)
145
{
146
  uint32_t extId = RxHeader.ExtId;
147
 
148
  if (c->payloadId != 0 && c->payloadId != extId)
149
    return REJECT;
150
  uint8_t newId = c->payloadId == 0; // set a flag if this is a newly discovered frame
151
  c->payloadId = extId;
152
 
153
  uint32_t pgn = (c->payloadId >> 8) & ((1 << 18) - 1);
154
  uint8_t pf = (pgn >> 8) & 0xFF;
155
 
156
  if (pf < 240)
157
  {
158
    // process PS if in PDU1 , address is low byte
159
    pgn = pgn & 0x3FF00;
160
  }
161
 
162
  uint8_t packetLen = RxHeader.DLC;
163
 
164
  if (singleFrame(pgn))
165
  {
166
    c->payloadTimestamp = HAL_GetTick();
167
    memcpy(c->payloadBuffer, RxData, packetLen);
168
    c->payloadRemaining = 0;
169
    c->payloadTotal = packetLen;
170
    c->status = COMPLETE;
171
    return c->status; // successfully filled frame
172
  }
173
  else
174
  {
175
    // sort out fastpacket new ID
176
    if (newId)
177
    {
178
      if ((RxData[0] & 0x1f) != 0)
179
      {
180
        resetContext(c);
181
        return FAIL;
182
      }
183
      c->payloadTimestamp = HAL_GetTick();
184
      c->payloadNextSeq = RxData[0] + 1;
185
      c->payloadId = extId;
186
      c->payloadRemaining = RxData[1];
187
      c->payloadTotal = RxData[1];
188
      // no data , return
189
      if (c->payloadTotal == 0)
190
      {
191
        resetContext(c);
192
        return FAIL;
193
      }
194
      uint8_t numBytes = packetLen - 2;
195
      memcpy(c->payloadBuffer, RxData + 2, numBytes);
196
 
197
      // CAN frame can be longer than remaining bytes, do not make payloadRemaining wrap around !
198
      if (numBytes < c->payloadRemaining)
199
        c->payloadRemaining -= numBytes;
200
      else
201
        c->payloadRemaining = 0;
202
      c->payloadOffset = numBytes;
203
    }
204
    else
205
    {
206
      if (RxData[0] != c->payloadNextSeq)
207
      {
208
        resetContext(c);
209
        return FAIL;
210
      }
211
      // predict next payload sequence
212
      c->payloadNextSeq++;
213
      uint8_t numBytes = packetLen - 1;
214
      memcpy(c->payloadBuffer + c->payloadOffset, RxData + 1, numBytes);
215
      c->payloadRemaining -= numBytes;
216
      c->payloadOffset += numBytes;
217
    }
218
  }
219
 
220
  appendStatus stat = (c->payloadRemaining != 0) ? ACCEPT : COMPLETE;
221
  c->status = stat;
222
  return stat;
223
}
224
 
225
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
226
{
227
  HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
228
  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData);
229
 
230
  int i;
231
  for (i = 0; i < CONTEXTS; ++i)
232
  {
233
    contextType *ctx = &contexts[i];
234
    appendStatus stat = append(ctx, &RxHeader);
235
    if (stat == ACCEPT || stat == COMPLETE)
236
      break; // accepted data, stop loop
237
  }
238
}
239
 
240
void heartBeat()
241
{
242
  char lineBuff[80];
243
  uint32_t timestamp = HAL_GetTick();
244
  size_t pos = small_sprintf(lineBuff, keepawake,
245
                             timestamp / 1000, // seconds
246
                             timestamp % 1000  // milliseconds
247
  );
248
  HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
249
  if (pos < SerialTransmitSpace(&uc1))
250
  {
251
    __disable_irq();
252
    sendString(&uc1, (char *)lineBuff, pos);
253
    __enable_irq();
254
  }
255
}
256
 
257
// utility function to set up the filter mask
258
void CAN_FilterMaskEXT(CAN_FilterTypeDef *filter_, uint32_t id_, uint32_t mask_)
259
{
260
  filter_->FilterIdHigh = id_ >> 13;
261
  filter_->FilterIdLow = ((id_ & 0x1FFF) << 3) | CAN_ID_EXT;
262
  filter_->FilterMaskIdHigh = mask_ >> 13;
263
  filter_->FilterMaskIdLow = ((mask_ & 0x1FFF) << 3) | CAN_ID_EXT;
264
}
265
 
266
void processCmd(char *buff, int len)
267
{
268
  buff[len] = 0; // terminate in case of error
269
  char lineBuff[100];
270
  int pos = small_sprintf(lineBuff, "$PDGY,ACK,%s\r\n", buff + 6);
271
  if (pos < SerialTransmitSpace(&uc1))
272
  {
273
    __disable_irq();
274
    sendString(&uc1, (char *)lineBuff, pos);
275
    __enable_irq();
276
  }
277
}
278
 
279
/* USER CODE END 0 */
280
 
281
/**
282
 * @brief  The application entry point.
283
 * @retval int
284
 */
285
int main(void)
286
{
287
  /* USER CODE BEGIN 1 */
288
 
289
  /* USER CODE END 1 */
290
 
291
  /* MCU Configuration--------------------------------------------------------*/
292
 
293
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
294
  HAL_Init();
295
 
296
  /* USER CODE BEGIN Init */
297
 
298
  /* USER CODE END Init */
299
 
300
  /* Configure the system clock */
301
  SystemClock_Config();
302
 
303
  /* USER CODE BEGIN SysInit */
3 mjames 304
  cc_init();
2 mjames 305
 
306
  /* USER CODE END SysInit */
307
 
308
  /* Initialize all configured peripherals */
309
  MX_GPIO_Init();
310
  MX_CAN_Init();
311
  MX_USART1_UART_Init();
3 mjames 312
  MX_SPI1_Init();
2 mjames 313
  /* USER CODE BEGIN 2 */
314
 
315
  HAL_CAN_Start(&hcan);
316
 
317
  init_usart_ctl(&uc1, &huart1);
318
 
319
  EnableSerialRxInterrupt(&uc1);
320
 
321
  // Activate the notification
322
  HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
323
 
324
  // send out a version string on the serial port
325
  sendString(&uc1, (char *)version, sizeof(version));
326
 
327
  uint32_t sendTime = HAL_GetTick() + 1000;
328
  char cmdBuff[100];
329
 
3 mjames 330
  // serial utils library command editor 
331
  editBuffer cmdEdit;
332
 
333
  initReadLine( &cmdEdit, cmdBuff, 100, READLINES_CR);
334
 
2 mjames 335
  for (int i = 0; i < CONTEXTS; ++i)
336
    resetContext(&contexts[i]);
337
 
338
  /* USER CODE END 2 */
339
 
340
  /* Infinite loop */
341
  /* USER CODE BEGIN WHILE */
342
  while (1)
343
  {
344
    /* USER CODE END WHILE */
345
 
346
    /* USER CODE BEGIN 3 */
347
 
3 mjames 348
 editBufferReturn ret = readLine(&uc1, &cmdEdit);
349
 
350
  if (ret == EDIT_CR)
351
  {
352
      processCmd (cmdBuff,charCount(&cmdEdit));
353
  }
354
 
2 mjames 355
    if (HAL_GetTick() > sendTime)
356
    {
357
      sendTime += 1000;
358
      heartBeat();
3 mjames 359
      cc_display(2);
2 mjames 360
    }
361
 
362
    for (int i = 0; i < CONTEXTS; ++i)
363
    {
364
      contextType *ctx = &contexts[i];
365
      /// check for too old
366
      //   if (ctx->status == ACCEPT && ctx->payloadTimestamp < old)
367
      //   {
368
      //     resetContext(ctx);
369
      //     continue;
370
      //   }
371
 
372
      if (ctx->status == COMPLETE)
373
      {
374
        __disable_irq();
375
 
376
        uint8_t prio = (ctx->payloadId >> 26) & 0x7;
377
        uint8_t src = ctx->payloadId & 0xFF;
378
        uint8_t dst = 255;
379
        // mask out the PGN field as 18 bits.
380
        uint32_t pgn = (ctx->payloadId >> 8) & ((1 << 18) - 1);
381
        uint8_t pf = (pgn >> 8) & 0xFF;
382
 
383
        if (pf < 240)
384
        {
385
          // process PS if in PDU1 , address is low byte
386
          dst = pgn & 0xFF;
387
          pgn = pgn & 0x3FF00;
388
        }
389
 
390
        char lineBuff[300];
391
        size_t pos = small_sprintf(lineBuff, "!PDGY,%ld,%d,%d,%d,%ld.%03ld,",
392
                                   pgn,  // PGN
393
                                   prio, // priority
394
                                   src,  // source address
395
                                   dst,  // destination address
396
 
397
                                   ctx->payloadTimestamp / 1000, // milliseconds
398
                                   ctx->payloadTimestamp % 1000);
399
 
400
        size_t base64_len;
401
        base64_encode(ctx->payloadBuffer,
402
                      ctx->payloadTotal,
403
                      lineBuff + pos,
404
                      &base64_len);
405
 
406
        pos += base64_len;
407
        lineBuff[pos++] = '\r';
408
        lineBuff[pos++] = '\n';
409
        __enable_irq();
410
 
411
        // skip sending if this would overrun the buffer
412
        if (pos < SerialTransmitSpace(&uc1))
413
          sendString(&uc1, lineBuff, pos);
414
        __disable_irq();
415
 
416
        resetContext(ctx);
417
        __enable_irq();
418
      }
419
    }
420
  }
421
  /* USER CODE END 3 */
422
}
423
 
424
/**
425
 * @brief System Clock Configuration
426
 * @retval None
427
 */
428
void SystemClock_Config(void)
429
{
430
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
431
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
432
 
433
  /** Initializes the RCC Oscillators according to the specified parameters
434
   * in the RCC_OscInitTypeDef structure.
435
   */
436
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
437
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
438
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
439
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
440
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
441
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
442
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
443
  {
444
    Error_Handler();
445
  }
446
 
447
  /** Initializes the CPU, AHB and APB buses clocks
448
   */
449
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
450
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
451
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
452
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
453
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
454
 
455
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
456
  {
457
    Error_Handler();
458
  }
459
}
460
 
461
/**
462
 * @brief CAN Initialization Function
463
 * @param None
464
 * @retval None
465
 */
466
static void MX_CAN_Init(void)
467
{
468
 
469
  /* USER CODE BEGIN CAN_Init 0 */
470
 
471
  /* USER CODE END CAN_Init 0 */
472
 
473
  /* USER CODE BEGIN CAN_Init 1 */
474
 
475
  /* USER CODE END CAN_Init 1 */
476
  hcan.Instance = CAN1;
477
  hcan.Init.Prescaler = 16;
478
  hcan.Init.Mode = CAN_MODE_NORMAL;
479
  hcan.Init.SyncJumpWidth = CAN_SJW_2TQ;
480
  hcan.Init.TimeSeg1 = CAN_BS1_3TQ;
481
  hcan.Init.TimeSeg2 = CAN_BS2_4TQ;
482
  hcan.Init.TimeTriggeredMode = DISABLE;
483
  hcan.Init.AutoBusOff = DISABLE;
484
  hcan.Init.AutoWakeUp = DISABLE;
485
  hcan.Init.AutoRetransmission = ENABLE;
486
  hcan.Init.ReceiveFifoLocked = DISABLE;
487
  hcan.Init.TransmitFifoPriority = DISABLE;
488
  if (HAL_CAN_Init(&hcan) != HAL_OK)
489
  {
490
    Error_Handler();
491
  }
492
  /* USER CODE BEGIN CAN_Init 2 */
493
  /* USER CODE BEGIN CAN_Init 2 */
494
 
495
  // allow absolutely everything into filter
496
  CAN_FilterTypeDef filterConfig;
497
  filterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
498
  filterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
499
  filterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
500
  filterConfig.FilterActivation = CAN_FILTER_ENABLE;
501
  filterConfig.FilterBank = 0;
502
 
503
  CAN_FilterMaskEXT(&filterConfig, 0, 0);
504
 
505
  HAL_CAN_ConfigFilter(&hcan, &filterConfig);
506
 
507
  /* USER CODE END CAN_Init 2 */
508
}
509
 
510
/**
3 mjames 511
 * @brief SPI1 Initialization Function
512
 * @param None
513
 * @retval None
514
 */
515
static void MX_SPI1_Init(void)
516
{
517
 
518
  /* USER CODE BEGIN SPI1_Init 0 */
519
 
520
  /* USER CODE END SPI1_Init 0 */
521
 
522
  /* USER CODE BEGIN SPI1_Init 1 */
523
 
524
  /* USER CODE END SPI1_Init 1 */
525
  /* SPI1 parameter configuration*/
526
  hspi1.Instance = SPI1;
527
  hspi1.Init.Mode = SPI_MODE_MASTER;
528
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
529
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
530
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
531
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
532
  hspi1.Init.NSS = SPI_NSS_SOFT;
533
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
534
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
535
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
536
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
537
  hspi1.Init.CRCPolynomial = 10;
538
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
539
  {
540
    Error_Handler();
541
  }
542
  /* USER CODE BEGIN SPI1_Init 2 */
543
 
544
  /* USER CODE END SPI1_Init 2 */
545
}
546
 
547
/**
2 mjames 548
 * @brief USART1 Initialization Function
549
 * @param None
550
 * @retval None
551
 */
552
static void MX_USART1_UART_Init(void)
553
{
554
 
555
  /* USER CODE BEGIN USART1_Init 0 */
556
 
557
  /* USER CODE END USART1_Init 0 */
558
 
559
  /* USER CODE BEGIN USART1_Init 1 */
560
 
561
  /* USER CODE END USART1_Init 1 */
562
  huart1.Instance = USART1;
563
  huart1.Init.BaudRate = 460800;
564
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
565
  huart1.Init.StopBits = UART_STOPBITS_1;
566
  huart1.Init.Parity = UART_PARITY_NONE;
567
  huart1.Init.Mode = UART_MODE_TX_RX;
568
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
569
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
570
  if (HAL_UART_Init(&huart1) != HAL_OK)
571
  {
572
    Error_Handler();
573
  }
574
  /* USER CODE BEGIN USART1_Init 2 */
575
 
576
  /* USER CODE END USART1_Init 2 */
577
}
578
 
579
/**
580
 * @brief GPIO Initialization Function
581
 * @param None
582
 * @retval None
583
 */
584
static void MX_GPIO_Init(void)
585
{
586
  GPIO_InitTypeDef GPIO_InitStruct = {0};
3 mjames 587
  /* USER CODE BEGIN MX_GPIO_Init_1 */
588
  /* USER CODE END MX_GPIO_Init_1 */
2 mjames 589
 
590
  /* GPIO Ports Clock Enable */
591
  __HAL_RCC_GPIOC_CLK_ENABLE();
592
  __HAL_RCC_GPIOD_CLK_ENABLE();
593
  __HAL_RCC_GPIOA_CLK_ENABLE();
594
 
595
  /*Configure GPIO pin Output Level */
596
  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
597
 
3 mjames 598
  /*Configure GPIO pin Output Level */
599
  HAL_GPIO_WritePin(GPIOA, SPI1_CS_Pin | SPI1_CD_Pin | SPI1_RESET_Pin, GPIO_PIN_RESET);
600
 
2 mjames 601
  /*Configure GPIO pin : LED_Pin */
602
  GPIO_InitStruct.Pin = LED_Pin;
603
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
604
  GPIO_InitStruct.Pull = GPIO_NOPULL;
605
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
606
  HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
3 mjames 607
 
608
  /*Configure GPIO pins : SPI1_CS_Pin SPI1_CD_Pin SPI1_RESET_Pin */
609
  GPIO_InitStruct.Pin = SPI1_CS_Pin | SPI1_CD_Pin | SPI1_RESET_Pin;
610
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
611
  GPIO_InitStruct.Pull = GPIO_NOPULL;
612
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
613
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
614
 
615
  /* USER CODE BEGIN MX_GPIO_Init_2 */
616
  /* USER CODE END MX_GPIO_Init_2 */
2 mjames 617
}
618
 
619
/* USER CODE BEGIN 4 */
620
 
621
/* USER CODE END 4 */
622
 
623
/**
624
 * @brief  This function is executed in case of error occurrence.
625
 * @retval None
626
 */
627
void Error_Handler(void)
628
{
629
  /* USER CODE BEGIN Error_Handler_Debug */
630
  /* User can add his own implementation to report the HAL error return state */
631
 
632
  /* USER CODE END Error_Handler_Debug */
633
}
634
 
635
#ifdef USE_FULL_ASSERT
636
/**
637
 * @brief  Reports the name of the source file and the source line number
638
 *         where the assert_param error has occurred.
639
 * @param  file: pointer to the source file name
640
 * @param  line: assert_param error line source number
641
 * @retval None
642
 */
643
void assert_failed(uint8_t *file, uint32_t line)
644
{
645
  /* USER CODE BEGIN 6 */
646
  /* User can add his own implementation to report the file name and line number,
647
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
648
  /* USER CODE END 6 */
649
}
650
#endif /* USE_FULL_ASSERT */