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.
 
 
 
 
 
 

352 lines
7.4 KiB

  1. /*-
  2. * Copyright 2021 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 <usb_device.h>
  27. #include <usbd_cdc_if.h>
  28. #include <string.h>
  29. /* LoRaMac headers */
  30. #include <board.h>
  31. #include <adc.h>
  32. #include <radio.h>
  33. #include <delay.h>
  34. /* lora-irr headers */
  35. #include <misc.h>
  36. #include <sysinit.h>
  37. /* Start up USB */
  38. SYSINIT_VF(usb_cdc, SI_SUB_USB, SI_ORDER_MIDDLE, MX_USB_DEVICE_Init);
  39. /* XXX - where's a better place? */
  40. extern PCD_HandleTypeDef hpcd_USB_FS;
  41. void
  42. USB_LP_IRQHandler(void)
  43. {
  44. HAL_PCD_IRQHandler(&hpcd_USB_FS);
  45. }
  46. char *
  47. findeol(char *pos, size_t len)
  48. {
  49. while (len) {
  50. if (*pos == '\r' || *pos == '\n')
  51. return pos;
  52. pos++;
  53. len--;
  54. }
  55. return NULL;
  56. }
  57. void
  58. hexdump(const uint8_t *ptr, size_t len)
  59. {
  60. int i;
  61. for (i = 0; i < len; i++)
  62. usb_printf("%02x", ptr[i]);
  63. }
  64. void
  65. txdone(void)
  66. {
  67. usb_printf("txdone\r\n");
  68. Radio.Rx(0);
  69. }
  70. void
  71. txtimeout(void)
  72. {
  73. usb_printf("txtimeout\r\n");
  74. }
  75. void
  76. rxdone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
  77. {
  78. usb_printf("rxdone: size: %hu, rssi: %hd, snr: %d\r\ndata: ", size, rssi, snr);
  79. hexdump(payload, size);
  80. usb_printf("\r\n");
  81. }
  82. void
  83. rxtimeout(void)
  84. {
  85. usb_printf("rxtimeout\r\n");
  86. }
  87. void
  88. rxerr(void)
  89. {
  90. usb_printf("rxerr\r\n");
  91. }
  92. RadioEvents_t revents = {
  93. .TxDone = txdone,
  94. .TxTimeout = txtimeout,
  95. .RxDone = rxdone,
  96. .RxTimeout = rxtimeout,
  97. .RxError = rxerr,
  98. };
  99. static uint8_t
  100. hexchartonib(char s)
  101. {
  102. switch (s) {
  103. case '0'...'9':
  104. return s - '0';
  105. case 'a'...'f':
  106. return s - 'a' + 10;
  107. case 'A'...'F':
  108. return s - 'A' + 10;
  109. default:
  110. return -1;
  111. }
  112. }
  113. static bool
  114. hexdecode(char *buf, size_t len, uint8_t *out)
  115. {
  116. uint8_t topchr, botchr;
  117. if (len % 2)
  118. return false;
  119. /* NB: only needed to silence a bad gcc warning */
  120. topchr = -1;
  121. while (len) {
  122. if (len % 2) {
  123. /* bottom nibble */
  124. botchr = hexchartonib(*buf);
  125. if (topchr == -1 || botchr == -1)
  126. return false;
  127. *out = topchr << 4 | botchr;
  128. out++;
  129. } else {
  130. /* top nibble */
  131. topchr = hexchartonib(*buf);
  132. }
  133. len--;
  134. buf++;
  135. }
  136. return true;
  137. }
  138. static const char pktstart[] = "pkt:";
  139. static const size_t pktstartlen = sizeof pktstart - 1;
  140. static uint8_t pktbuf[128];
  141. static void
  142. process_line(char *start, char *end)
  143. {
  144. size_t len;
  145. /* trim off leading CR/NL */
  146. while (start < end && (*start == '\r' || *start == '\n'))
  147. start++;
  148. len = end - start;
  149. if (len >= pktstartlen && memcmp(start, pktstart, sizeof pktstart - 1) == 0) {
  150. start += pktstartlen;
  151. len -= pktstartlen;
  152. if (len % 2) {
  153. usb_printf("invalid pkt len\r\n");
  154. return;
  155. }
  156. if (!hexdecode(start, len, pktbuf)) {
  157. usb_printf("invalid pkt\r\n");
  158. return;
  159. }
  160. Radio.Send(pktbuf, len / 2);
  161. return;
  162. }
  163. usb_printf("line: %.*s", end - start, start);
  164. fflush(vcp_usb);
  165. }
  166. void
  167. radio_init(void)
  168. {
  169. Radio.Init(&revents);
  170. }
  171. SYSINIT_VF(radio_init, SI_SUB_STANDARD, SI_ORDER_ANY, radio_init);
  172. int
  173. main(void)
  174. {
  175. debug_printf("starting...\n");
  176. /* turn on LED */
  177. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
  178. setlinebuf(vcp_usb);
  179. #if 1
  180. wait_for_vcp();
  181. /*
  182. * This is required to use w/ FreeBSD. This is an issue w/ the
  183. * STM32 Core USB library:
  184. * https://github.com/STMicroelectronics/STM32CubeL1/issues/10
  185. */
  186. DelayMs(100);
  187. usb_printf("starting...\r\n");
  188. #endif
  189. uint32_t v;
  190. usb_printf("gs: %#x\r\n", Radio.GetStatus());
  191. usb_printf("set modem\r\n");
  192. Radio.SetModem(MODEM_LORA);
  193. usb_printf("check rffreq: %d\r\n", (int)Radio.CheckRfFrequency(914350 * 1000));
  194. usb_printf("set channel\r\n");
  195. Radio.SetChannel(914350 * 1000);
  196. v = Radio.Random();
  197. usb_printf("rr: %#lx\r\n", v);
  198. usb_printf("rssi: %#hx\r\n", Radio.Rssi(MODEM_LORA));
  199. /* RX/TX parameters */
  200. const uint8_t modem = MODEM_LORA;
  201. const uint8_t bandwidth = 0 /* 128 kHz */;
  202. const uint8_t datarate = 7 /* 128 chips */;
  203. const uint8_t coderate = 1 /* 4/5 */;
  204. const uint8_t preambleLen = 8 /* symbols */;
  205. const uint8_t fixLen = 0 /* variable */;
  206. const uint8_t crcOn = 1 /* on */;
  207. const uint8_t freqHopOn = 0 /* off */;
  208. const bool iqInverted = false /* not inverted */;
  209. Radio.SetRxConfig(modem, bandwidth, datarate, coderate, 0/*afc*/,
  210. preambleLen, 5/*symTimeout*/, fixLen, 0/*payloadlen*/, crcOn,
  211. freqHopOn, 0/*hopPeriod*/, iqInverted, true/*rxcont*/);
  212. Radio.SetTxConfig(modem, 11/*power*/, 0/*fdev*/, bandwidth, datarate,
  213. coderate, preambleLen, fixLen, crcOn, freqHopOn, 0/*hopPeriod*/,
  214. iqInverted, 1000/*timeout*/);
  215. uint8_t sendmsg[] = "testing lora123";
  216. usb_printf("sending...\r\n");
  217. Radio.Send(sendmsg, sizeof sendmsg);
  218. DelayMs(200);
  219. Radio.Send(sendmsg, sizeof sendmsg);
  220. DelayMs(200);
  221. Radio.Send(sendmsg, sizeof sendmsg);
  222. DelayMs(200);
  223. usb_printf("rx(0)...\r\n");
  224. Radio.Rx(0);
  225. char inpbuf[1024];
  226. char *lastcheck;
  227. char *endchr;
  228. int inpbufpos = 0;
  229. int cpylen;
  230. loop:
  231. BoardLowPowerHandler();
  232. if (Radio.IrqProcess != NULL)
  233. Radio.IrqProcess();
  234. /* while we have data */
  235. while (CDC_RX_LEN) {
  236. /* store last position */
  237. lastcheck = &inpbuf[inpbufpos];
  238. /* calculate how much space left */
  239. cpylen = MIN(sizeof inpbuf - inpbufpos, CDC_RX_LEN);
  240. /* copy into buffer */
  241. memcpy(&inpbuf[inpbufpos], CDC_RX_BUFFER, cpylen);
  242. /* and point to end of buffer */
  243. inpbufpos += cpylen;
  244. do {
  245. /* find first end of line characters */
  246. endchr = findeol(lastcheck, cpylen);
  247. if (endchr != NULL) {
  248. /* if so, process it */
  249. process_line(inpbuf, endchr);
  250. /* skip end of line char */
  251. endchr++;
  252. /* move remaining buffer to the beginning */
  253. memmove(inpbuf, endchr, inpbufpos - (endchr - inpbuf));
  254. /* and store new length */
  255. inpbufpos = inpbufpos - (endchr - inpbuf);
  256. /* mark begining of stream as last checked */
  257. lastcheck = inpbuf;
  258. /* and try to process another line */
  259. continue;
  260. } else if (inpbufpos == sizeof inpbuf) {
  261. /* we overflowed the buffer */
  262. /* XXX - best way is to throw away this line */
  263. inpbufpos = 0;
  264. }
  265. } while (0);
  266. /* if we copied all the data */
  267. if (cpylen == CDC_RX_LEN) {
  268. /* declare that we are ready to receive more data */
  269. CDC_RX_LEN = 0;
  270. USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  271. } else {
  272. /* if not, move the remaining to the begining and try again */
  273. memmove(CDC_RX_BUFFER, &CDC_RX_BUFFER[cpylen], CDC_RX_LEN - cpylen);
  274. CDC_RX_LEN -= cpylen;
  275. }
  276. }
  277. goto loop;
  278. }