Subversion Repositories canSerial

Rev

Rev 3 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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 */
  591.