Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

438 lignes
8.9 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 "stm32l1xx.h"
  27. #include "stm32l1xx_hal.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. #include <comms.h>
  37. enum {
  38. CMD_TERMINATE = 1,
  39. CMD_WAITFOR = 2,
  40. CMD_RUNFOR = 3,
  41. CMD_PING = 4,
  42. CMD_SETUNSET = 5,
  43. CMD_ADV = 6,
  44. CMD_CLEAR = 7,
  45. };
  46. /*
  47. * rxpktavail is initialized to true meaning that the data in rxpkt
  48. * can be over written. When a packet is received, the data is copied
  49. * to rxpkt, and then rxpktavail is set to false. Once the packet has
  50. * been processed, it is set back to true.
  51. */
  52. static uint8_t rxpkt[128];
  53. static struct pktbuf rxpktbuf;
  54. static volatile bool rxpktavail;
  55. static uint8_t shared_key[] = "foobar";
  56. static struct pktbuf shared_key_buf = (struct pktbuf){
  57. .pkt = shared_key,
  58. .pktlen = sizeof shared_key - 1,
  59. };
  60. static struct comms_state cs;
  61. void
  62. txdone(void)
  63. {
  64. /* restart Rx when Tx done */
  65. Radio.Rx(0);
  66. }
  67. void
  68. txtimeout(void)
  69. {
  70. /* restart Rx when Tx done */
  71. Radio.Rx(0);
  72. }
  73. void
  74. rxdone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
  75. {
  76. if (rxpktavail) {
  77. memcpy(rxpkt, payload, MIN(sizeof rxpkt, size));
  78. rxpktbuf = (struct pktbuf){
  79. .pkt = rxpkt,
  80. .pktlen = size,
  81. };
  82. rxpktavail = false;
  83. }
  84. }
  85. void
  86. rxtimeout(void)
  87. {
  88. }
  89. void
  90. rxerr(void)
  91. {
  92. }
  93. RadioEvents_t revents = {
  94. .TxDone = txdone,
  95. .TxTimeout = txtimeout,
  96. .RxDone = rxdone,
  97. .RxTimeout = rxtimeout,
  98. .RxError = rxerr,
  99. };
  100. /*
  101. * Seed the randomness from the radio. This is not a great
  102. * seed, and is hard to gauge how much randomness is really
  103. * there. Assuming about 1 bit per 8 bits looks pretty safe,
  104. * so add 256 * 8 / 32 words.
  105. */
  106. static void
  107. radio_seed_rng(void)
  108. {
  109. #if 1
  110. uint32_t v;
  111. int i;
  112. for (i = 0; i < 256 * 8 / 32; i++) {
  113. v = Radio.Random();
  114. strobe_seed_prng((uint8_t *)&v, sizeof v);
  115. }
  116. #endif
  117. }
  118. static void
  119. analog_seed_rng(void)
  120. {
  121. #if 1
  122. uint16_t v;
  123. int i;
  124. for (i = 0; i < 256 / 2; i++) {
  125. /*
  126. * Capture some ADC data. If pin is floating, 0xfff
  127. * happens frequently, if pin is grounded, 0 happens
  128. * frequently, filter these values out.
  129. */
  130. do {
  131. v = AdcReadChannel(&Adc, ADC_CHANNEL_21);
  132. } while (v == 0 || v == 0xfff);
  133. strobe_seed_prng((uint8_t *)&v, sizeof v);
  134. }
  135. #endif
  136. }
  137. static inline uint32_t
  138. letoh_32(uint8_t *v)
  139. {
  140. return v[0] | (v[1] << 8) | (v[2] << 16) | (v[3] << 24);
  141. }
  142. struct chaninfo {
  143. GPIO_TypeDef *bank;
  144. uint16_t pinnum;
  145. bool init;
  146. bool invert;
  147. } chans[] = {
  148. [0] = { .bank = GPIOB, .pinnum = GPIO_PIN_5, .invert = true, },
  149. [1] = { .bank = GPIOB, .pinnum = GPIO_PIN_6, .invert = true, },
  150. [2] = { .bank = GPIOB, .pinnum = GPIO_PIN_7, .invert = true, },
  151. [3] = { .bank = GPIOB, .pinnum = GPIO_PIN_9, .invert = true, },
  152. /* Turn on LED at start */
  153. [4] = { .bank = GPIOB, .pinnum = GPIO_PIN_8, .init = true, },
  154. };
  155. #define nitems(x) (sizeof(x) / sizeof *(x))
  156. static void
  157. set_chan(uint32_t chan, bool val)
  158. {
  159. struct chaninfo ci;
  160. if (chan < nitems(chans)) {
  161. ci = chans[chan];
  162. HAL_GPIO_WritePin(ci.bank, ci.pinnum, val ^ ci.invert ?
  163. GPIO_PIN_SET : GPIO_PIN_RESET);
  164. }
  165. }
  166. static void
  167. setup_gpio()
  168. {
  169. GPIO_InitTypeDef GPIO_InitStruct;
  170. int i;
  171. for (i = 0; i < nitems(chans); i++) {
  172. GPIO_InitStruct = (GPIO_InitTypeDef){
  173. .Pin = chans[i].pinnum,
  174. .Mode = GPIO_MODE_OUTPUT_PP,
  175. .Pull = GPIO_NOPULL,
  176. .Speed = GPIO_SPEED_FREQ_LOW,
  177. };
  178. HAL_GPIO_Init(chans[i].bank, &GPIO_InitStruct);
  179. set_chan(i, chans[i].init);
  180. }
  181. }
  182. static struct sched {
  183. uint32_t cmd;
  184. uint32_t end_wait_tick; /* end if running, otherwise how long to wait */
  185. uint32_t chan;
  186. } schedule[20];
  187. static int schedpos; /* position in schedule, % nitems(schedule)*/
  188. static int schedcnt; /* total items waiting */
  189. #define SCHED_ITEM(x) (schedule[(schedpos + x) % nitems(schedule)])
  190. #define SCHED_HEAD SCHED_ITEM(0)
  191. #define SCHED_TAIL SCHED_ITEM(schedcnt)
  192. static void
  193. start_sched(struct sched *sched)
  194. {
  195. sched->end_wait_tick += uwTick;
  196. if (sched->cmd == CMD_RUNFOR)
  197. set_chan(sched->chan, 1);
  198. }
  199. static void
  200. process_sched()
  201. {
  202. /* nothing to do? */
  203. if (schedcnt == 0)
  204. return;
  205. /* not yet expired */
  206. if (uwTick < SCHED_HEAD.end_wait_tick)
  207. return;
  208. if (SCHED_HEAD.cmd == CMD_RUNFOR)
  209. set_chan(SCHED_HEAD.chan, 0);
  210. /* we are done, advance */
  211. schedpos++;
  212. schedcnt--;
  213. if (schedcnt)
  214. start_sched(&SCHED_HEAD);
  215. }
  216. static void
  217. enqueue_sched(uint32_t cmd, uint32_t ticks, uint32_t chan)
  218. {
  219. if (schedcnt >= nitems(schedule))
  220. return;
  221. SCHED_TAIL = (struct sched){
  222. .cmd = cmd,
  223. .end_wait_tick = ticks,
  224. .chan = chan,
  225. };
  226. if (schedcnt == 0)
  227. start_sched(&SCHED_HEAD);
  228. schedcnt++;
  229. }
  230. static void
  231. procmsg(struct pktbuf inbuf, struct pktbuf *outbuf)
  232. {
  233. uint32_t args[5];
  234. int i, apos, cnt;
  235. i = 1;
  236. apos = 0;
  237. while (i < inbuf.pktlen) {
  238. if (i + 4 <= inbuf.pktlen) {
  239. args[apos++] = letoh_32(&inbuf.pkt[i]);
  240. i += 4;
  241. }
  242. }
  243. outbuf->pkt[0] = inbuf.pkt[0];
  244. switch (inbuf.pkt[0]) {
  245. case CMD_WAITFOR:
  246. if (apos == 1)
  247. enqueue_sched(CMD_WAITFOR, args[0], -1);
  248. break;
  249. case CMD_RUNFOR:
  250. if (apos == 2)
  251. enqueue_sched(CMD_RUNFOR, args[0], args[1]);
  252. break;
  253. case CMD_PING:
  254. break;
  255. case CMD_SETUNSET:
  256. if (apos == 2)
  257. set_chan(args[0], args[1]);
  258. break;
  259. case CMD_ADV:
  260. cnt = 1;
  261. if (apos == 1)
  262. cnt = args[0];
  263. for (i = 0; i < cnt && i < schedcnt; i++)
  264. SCHED_ITEM(i).end_wait_tick = 0;
  265. break;
  266. case CMD_CLEAR:
  267. if (schedcnt)
  268. schedcnt = 1;
  269. break;
  270. default:
  271. outbuf->pkt[0] = 0;
  272. break;
  273. }
  274. outbuf->pktlen = 1;
  275. }
  276. int
  277. main()
  278. {
  279. strobe_rng_init();
  280. BoardInitMcu();
  281. Radio.Init(&revents);
  282. analog_seed_rng();
  283. radio_seed_rng();
  284. strobe_rng_save();
  285. setup_gpio();
  286. /* turn on LED */
  287. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
  288. Radio.SetModem(MODEM_LORA);
  289. Radio.SetChannel(914350 * 1000);
  290. /* RX/TX parameters */
  291. const uint8_t modem = MODEM_LORA;
  292. const uint8_t bandwidth = 0 /* 128 kHz */;
  293. const uint8_t datarate = 7 /* 128 chips */;
  294. const uint8_t coderate = 1 /* 4/5 */;
  295. const uint8_t preambleLen = 8 /* symbols */;
  296. const uint8_t fixLen = 0 /* variable */;
  297. const uint8_t crcOn = 1 /* on */;
  298. const uint8_t freqHopOn = 0 /* off */;
  299. const bool iqInverted = false /* not inverted */;
  300. Radio.SetRxConfig(modem, bandwidth, datarate, coderate, 0/*afc*/,
  301. preambleLen, 5/*symTimeout*/, fixLen, 0/*payloadlen*/, crcOn,
  302. freqHopOn, 0/*hopPeriod*/, iqInverted, true/*rxcont*/);
  303. Radio.SetTxConfig(modem, 11/*power*/, 0/*fdev*/, bandwidth, datarate,
  304. coderate, preambleLen, fixLen, crcOn, freqHopOn, 0/*hopPeriod*/,
  305. iqInverted, 1000/*timeout*/);
  306. /* blink led */
  307. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
  308. DelayMs(300);
  309. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
  310. Radio.Rx(0);
  311. comms_init(&cs, procmsg, &shared_key_buf);
  312. uint8_t txbuf[128] = "i'mhere";
  313. struct pktbuf txpktbuf;
  314. txpktbuf = (struct pktbuf){
  315. .pkt = txbuf,
  316. .pktlen = 8,
  317. };
  318. Radio.Send(txpktbuf.pkt, txpktbuf.pktlen);
  319. rxpktavail = true;
  320. //Radio.Rx(0);
  321. loop:
  322. process_sched();
  323. BoardLowPowerHandler();
  324. if (Radio.IrqProcess != NULL)
  325. Radio.IrqProcess();
  326. if (!rxpktavail) {
  327. txpktbuf = (struct pktbuf){
  328. .pkt = txbuf,
  329. .pktlen = sizeof txbuf,
  330. };
  331. /* process available packet */
  332. comms_process(&cs, rxpktbuf, &txpktbuf);
  333. rxpktavail = true;
  334. if (txpktbuf.pktlen) {
  335. int i;
  336. for (i = 0; i < 1; i++) {
  337. DelayMs(20);
  338. Radio.Send(txpktbuf.pkt, txpktbuf.pktlen);
  339. }
  340. #if 0
  341. /* blink led */
  342. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
  343. DelayMs(300);
  344. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
  345. DelayMs(300);
  346. #endif
  347. }
  348. #if 0
  349. /* blink led */
  350. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
  351. DelayMs(300);
  352. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
  353. #endif
  354. }
  355. goto loop;
  356. }