Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

244 lines
4.2 KiB

  1. /*
  2. * Code to TX/RX RS-485 frames.
  3. *
  4. */
  5. #include <stdbool.h>
  6. #include <sysinit.h>
  7. #include <stm32f103xb.h>
  8. #include <stm32f1xx_hal.h>
  9. #include <stm32f1xx_hal_cortex.h>
  10. #include <stm32f1xx_hal_dma.h>
  11. #include <stm32f1xx_hal_rcc.h>
  12. #include <stm32f1xx_hal_gpio.h>
  13. #include <stm32f1xx_hal_uart.h>
  14. #include <rs485frame.h>
  15. const char *rs485err = NULL;
  16. static uint8_t rxbuf[1024];
  17. static txdone_fn_t txdone;
  18. static rxdone_fn_t rxdone;
  19. static txdone_fn_t errcb;
  20. static int doingrx = 0;
  21. static int doingtx = 0;
  22. static UART_HandleTypeDef rs485uart;
  23. /*
  24. * Notes:
  25. HAL_UARTEx_RxEventCallback rx evnts
  26. * HAL_UART_TxCpltCallback tx_it completed
  27. * HAL_UART_RxCpltCallback rx_it completed
  28. * HAL_UART_ErrorCallback for errors
  29. */
  30. void
  31. USART3_IRQHandler(void)
  32. {
  33. HAL_UART_IRQHandler(&rs485uart);
  34. }
  35. void
  36. rs485_register(txdone_fn_t txf, rxdone_fn_t rxf, txdone_fn_t errf)
  37. {
  38. txdone = txf;
  39. rxdone = rxf;
  40. errcb = errf;
  41. }
  42. static void
  43. settx(bool tx)
  44. {
  45. GPIO_PinState s;
  46. if (tx)
  47. s = GPIO_PIN_SET;
  48. else
  49. s = GPIO_PIN_RESET;
  50. HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, s);
  51. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, s);
  52. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, s);
  53. }
  54. void
  55. rs485_starttx(uint8_t *pkt, size_t len)
  56. {
  57. /* XXX - make sure not tx'ing */
  58. /* XXX - make sure line is idle */
  59. if (doingrx) {
  60. HAL_UART_AbortReceive_IT(&rs485uart);
  61. }
  62. settx(true);
  63. HAL_UART_Transmit_IT(&rs485uart, pkt, len);
  64. }
  65. void
  66. HAL_UART_ErrorCallback(UART_HandleTypeDef *phuart)
  67. {
  68. settx(false);
  69. doingtx = 0;
  70. doingrx = 0;
  71. errcb();
  72. }
  73. void
  74. HAL_UART_TxCpltCallback(UART_HandleTypeDef *phuart)
  75. {
  76. if (phuart != &rs485uart || txdone == NULL)
  77. return;
  78. settx(false);
  79. doingtx = 0;
  80. txdone();
  81. }
  82. void
  83. HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
  84. {
  85. if (huart != &rs485uart || rxdone == NULL)
  86. return;
  87. doingrx = 0;
  88. rxdone(rxbuf, Size);
  89. }
  90. /*
  91. * Called when the buffer has been completed, i.e. it likely
  92. * overflowed.
  93. */
  94. void
  95. HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  96. {
  97. if (huart != &rs485uart || rxdone == NULL)
  98. return;
  99. doingrx = 0;
  100. rxdone(NULL, 0);
  101. }
  102. /* USE_HAL_UART_REGISTER_CALLBACKS defaults to 0, so use this */
  103. void
  104. HAL_UART_MspInit(UART_HandleTypeDef *huart)
  105. {
  106. GPIO_InitTypeDef GPIO_InitStruct;
  107. /* UM1850 § 38.1.2 Page 550 */
  108. /* 2.a */
  109. __HAL_RCC_USART3_FORCE_RESET( );
  110. __HAL_RCC_USART3_RELEASE_RESET( );
  111. __HAL_RCC_USART3_CLK_ENABLE();
  112. /* 2.b */
  113. __HAL_RCC_GPIOB_CLK_ENABLE();
  114. /* TX pin */
  115. GPIO_InitStruct = (GPIO_InitTypeDef){
  116. .Pin = GPIO_PIN_10,
  117. .Mode = GPIO_MODE_AF_PP,
  118. .Pull = GPIO_NOPULL,
  119. .Speed = GPIO_SPEED_FREQ_LOW,
  120. };
  121. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  122. /* RX pin */
  123. GPIO_InitStruct = (GPIO_InitTypeDef){
  124. .Pin = GPIO_PIN_11,
  125. .Mode = GPIO_MODE_AF_INPUT,
  126. .Pull = GPIO_NOPULL,
  127. .Speed = GPIO_SPEED_FREQ_LOW,
  128. };
  129. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  130. /* 2.c */
  131. HAL_NVIC_SetPriority(USART3_IRQn, 1, 0);
  132. HAL_NVIC_EnableIRQ(USART3_IRQn);
  133. /* 2.d */
  134. /* DMA unused */
  135. }
  136. const char *
  137. statustostr(HAL_StatusTypeDef r)
  138. {
  139. switch (r) {
  140. case HAL_OK:
  141. return "ok";
  142. case HAL_ERROR:
  143. return "error";
  144. case HAL_BUSY:
  145. return "busy";
  146. default:
  147. return "unknown";
  148. }
  149. }
  150. int
  151. rs485_startrx()
  152. {
  153. HAL_StatusTypeDef r;
  154. if (doingtx) {
  155. rs485err = "doingtx";
  156. return 0;
  157. }
  158. r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf);
  159. if (r == HAL_BUSY) {
  160. HAL_UART_AbortReceive_IT(&rs485uart);
  161. r = HAL_UARTEx_ReceiveToIdle_IT(&rs485uart, rxbuf, sizeof rxbuf);
  162. }
  163. rs485err = statustostr(r);
  164. return r == HAL_OK;
  165. }
  166. static void
  167. rs485frame_init(const void *v)
  168. {
  169. GPIO_InitTypeDef GPIO_InitStruct;
  170. /* setup DE/RE */
  171. GPIO_InitStruct = (GPIO_InitTypeDef){
  172. .Pin = GPIO_PIN_0|GPIO_PIN_1,
  173. .Mode = GPIO_MODE_OUTPUT_OD,
  174. .Pull = GPIO_NOPULL,
  175. .Speed = GPIO_SPEED_FREQ_LOW, /* 2 MHz */
  176. };
  177. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  178. /* switch to RX */
  179. settx(false);
  180. /* UM1850 § 38.1.2 Page 550 */
  181. /* 3 */
  182. rs485uart = (UART_HandleTypeDef){
  183. .Init.BaudRate = 230400,
  184. .Init.WordLength = UART_WORDLENGTH_8B,
  185. .Init.StopBits = UART_STOPBITS_1,
  186. .Init.Parity = UART_PARITY_NONE,
  187. .Init.HwFlowCtl = UART_HWCONTROL_NONE,
  188. .Init.Mode = UART_MODE_TX_RX,
  189. .Instance = USART3,
  190. };
  191. /* 4 */
  192. HAL_UART_Init(&rs485uart);
  193. }
  194. SYSINIT(rs485frame_init, SI_SUB_STANDARD, SI_ORDER_FIRST, rs485frame_init, NULL);