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.
 
 
 
 
 
 

347 lines
7.6 KiB

  1. /*-
  2. * Copyright 2022 John-Mark Gurney.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23. * SUCH DAMAGE.
  24. *
  25. */
  26. #include <usbd_cdc_if.h>
  27. #include <misc.h>
  28. #include <stdbool.h>
  29. #include <stdint.h>
  30. #include <string.h>
  31. #include <sysinit.h>
  32. SYSINIT(hal_init, SI_SUB_HAL, SI_ORDER_FIRST, (void (*)(const void *))HAL_Init, NULL);
  33. void
  34. clkenable(const void *none)
  35. {
  36. GPIO_InitTypeDef GPIO_InitStruct;
  37. __HAL_RCC_GPIOB_CLK_ENABLE();
  38. __HAL_RCC_GPIOC_CLK_ENABLE();
  39. GPIO_InitStruct = (GPIO_InitTypeDef){
  40. .Pin = GPIO_PIN_13,
  41. .Mode = GPIO_MODE_OUTPUT_PP,
  42. .Pull = GPIO_NOPULL,
  43. .Speed = GPIO_SPEED_FREQ_LOW,
  44. };
  45. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  46. HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
  47. }
  48. SYSINIT(clkenable, SI_SUB_HAL, SI_ORDER_SECOND, clkenable, NULL);
  49. void
  50. oscconfig(const void *none)
  51. {
  52. RCC_ClkInitTypeDef clkinitstruct;
  53. RCC_OscInitTypeDef oscinitstruct;
  54. RCC_PeriphCLKInitTypeDef rccperiphclkinit;
  55. __HAL_RCC_PWR_CLK_ENABLE();
  56. oscinitstruct = (RCC_OscInitTypeDef){
  57. .OscillatorType = RCC_OSCILLATORTYPE_HSE,
  58. .HSEState = RCC_HSE_ON,
  59. .HSEPredivValue = RCC_HSE_PREDIV_DIV1,
  60. .PLL.PLLMUL = RCC_PLL_MUL9,
  61. .PLL.PLLState = RCC_PLL_ON,
  62. .PLL.PLLSource = RCC_PLLSOURCE_HSE,
  63. };
  64. HAL_RCC_OscConfig(&oscinitstruct);
  65. /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
  66. * clocks dividers */
  67. clkinitstruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
  68. RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  69. clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  70. clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  71. clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
  72. clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
  73. HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2);
  74. /* USB clock selection */
  75. rccperiphclkinit = (RCC_PeriphCLKInitTypeDef){
  76. .PeriphClockSelection = RCC_PERIPHCLK_USB,
  77. .UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5,
  78. };
  79. HAL_RCCEx_PeriphCLKConfig(&rccperiphclkinit);
  80. /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
  81. clocks dividers */
  82. clkinitstruct = (RCC_ClkInitTypeDef){
  83. .ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2),
  84. .SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
  85. .AHBCLKDivider = RCC_SYSCLK_DIV1,
  86. .APB1CLKDivider = RCC_HCLK_DIV2,
  87. .APB2CLKDivider = RCC_HCLK_DIV1,
  88. };
  89. HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2);
  90. }
  91. SYSINIT(oscconfig, SI_SUB_HAL, SI_ORDER_THIRD, oscconfig, NULL);
  92. char *
  93. findeol(char *pos, size_t len)
  94. {
  95. while (len) {
  96. if (*pos == '\r' || *pos == '\n')
  97. return pos;
  98. pos++;
  99. len--;
  100. }
  101. return NULL;
  102. }
  103. void
  104. hexdump(const uint8_t *ptr, size_t len)
  105. {
  106. int i;
  107. for (i = 0; i < len; i++)
  108. usb_printf("%02x", ptr[i]);
  109. }
  110. void
  111. txdone(void)
  112. {
  113. usb_printf("txdone\r\n");
  114. //Radio.Rx(0);
  115. }
  116. void
  117. txtimeout(void)
  118. {
  119. usb_printf("txtimeout\r\n");
  120. }
  121. void
  122. rxdone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
  123. {
  124. usb_printf("rxdone: size: %hu, rssi: %hd, snr: %d\r\ndata: ", size, rssi, snr);
  125. hexdump(payload, size);
  126. usb_printf("\r\n");
  127. }
  128. void
  129. rxtimeout(void)
  130. {
  131. usb_printf("rxtimeout\r\n");
  132. }
  133. void
  134. rxerr(void)
  135. {
  136. usb_printf("rxerr\r\n");
  137. }
  138. static uint8_t
  139. hexchartonib(char s)
  140. {
  141. switch (s) {
  142. case '0'...'9':
  143. return s - '0';
  144. case 'a'...'f':
  145. return s - 'a' + 10;
  146. case 'A'...'F':
  147. return s - 'A' + 10;
  148. default:
  149. return -1;
  150. }
  151. }
  152. static bool
  153. hexdecode(char *buf, size_t len, uint8_t *out)
  154. {
  155. uint8_t topchr, botchr;
  156. if (len % 2)
  157. return false;
  158. /* NB: only needed to silence a bad gcc warning */
  159. topchr = -1;
  160. while (len) {
  161. if (len % 2) {
  162. /* bottom nibble */
  163. botchr = hexchartonib(*buf);
  164. if (topchr == -1 || botchr == -1)
  165. return false;
  166. *out = topchr << 4 | botchr;
  167. out++;
  168. } else {
  169. /* top nibble */
  170. topchr = hexchartonib(*buf);
  171. }
  172. len--;
  173. buf++;
  174. }
  175. return true;
  176. }
  177. static const char pktstart[] = "pkt:";
  178. static const size_t pktstartlen = sizeof pktstart - 1;
  179. static uint8_t pktbuf[128];
  180. static void
  181. process_line(char *start, char *end)
  182. {
  183. size_t len;
  184. /* trim off leading CR/NL */
  185. while (start < end && (*start == '\r' || *start == '\n'))
  186. start++;
  187. len = end - start;
  188. if (len >= pktstartlen && memcmp(start, pktstart, sizeof pktstart - 1) == 0) {
  189. start += pktstartlen;
  190. len -= pktstartlen;
  191. if (len % 2) {
  192. usb_printf("invalid pkt len\r\n");
  193. return;
  194. }
  195. if (!hexdecode(start, len, pktbuf)) {
  196. usb_printf("invalid pkt\r\n");
  197. return;
  198. }
  199. //Radio.Send(pktbuf, len / 2);
  200. return;
  201. }
  202. usb_printf("line: %.*s", end - start, start);
  203. fflush(vcp_usb);
  204. }
  205. int
  206. main(void)
  207. {
  208. //debug_printf("starting...\n");
  209. //clkenable(NULL);
  210. sysinit_run();
  211. //Radio.Init(&revents);
  212. setlinebuf(vcp_usb);
  213. #if 1
  214. wait_for_vcp();
  215. /*
  216. * This is required to use w/ FreeBSD. This is an issue w/ the
  217. * STM32 Core USB library:
  218. * https://github.com/STMicroelectronics/STM32CubeL1/issues/10
  219. */
  220. HAL_Delay(50);
  221. usb_printf("starting...\r\n");
  222. #endif
  223. uint32_t v;
  224. char inpbuf[1024];
  225. char *lastcheck;
  226. char *endchr;
  227. int inpbufpos = 0;
  228. int cpylen;
  229. loop:
  230. //BoardLowPowerHandler();
  231. /* while we have data */
  232. while (CDC_RX_LEN) {
  233. /* store last position */
  234. lastcheck = &inpbuf[inpbufpos];
  235. /* calculate how much space left */
  236. cpylen = MIN(sizeof inpbuf - inpbufpos, CDC_RX_LEN);
  237. /* copy into buffer */
  238. memcpy(&inpbuf[inpbufpos], CDC_RX_BUFFER, cpylen);
  239. /* and point to end of buffer */
  240. inpbufpos += cpylen;
  241. do {
  242. /* find first end of line characters */
  243. endchr = findeol(lastcheck, cpylen);
  244. if (endchr != NULL) {
  245. /* if so, process it */
  246. process_line(inpbuf, endchr);
  247. /* skip end of line char */
  248. endchr++;
  249. /* move remaining buffer to the beginning */
  250. memmove(inpbuf, endchr, inpbufpos - (endchr - inpbuf));
  251. /* and store new length */
  252. inpbufpos = inpbufpos - (endchr - inpbuf);
  253. /* mark begining of stream as last checked */
  254. lastcheck = inpbuf;
  255. /* and try to process another line */
  256. continue;
  257. } else if (inpbufpos == sizeof inpbuf) {
  258. /* we overflowed the buffer */
  259. /* XXX - best way is to throw away this line */
  260. inpbufpos = 0;
  261. }
  262. } while (0);
  263. /* if we copied all the data */
  264. if (cpylen == CDC_RX_LEN) {
  265. /* declare that we are ready to receive more data */
  266. CDC_RX_LEN = 0;
  267. USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  268. } else {
  269. /* if not, move the remaining to the begining and try again */
  270. memmove(CDC_RX_BUFFER, &CDC_RX_BUFFER[cpylen], CDC_RX_LEN - cpylen);
  271. CDC_RX_LEN -= cpylen;
  272. }
  273. }
  274. goto loop;
  275. }