Subversion Repositories canSerial

Rev

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