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.
 
 
 
 
 
 

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