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.
 
 
 
 
 
 

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