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.
 
 
 
 
 
 

557 lines
11 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_hid_def.h"
  27. #include "stm32f1xx.h"
  28. #include "stm32f1xx_hal.h"
  29. #include <stdbool.h>
  30. #include <comms.h>
  31. #include <misc.h>
  32. #include <rs485frame.h>
  33. #include <strobe_rng_init.h>
  34. #include <strobe_pki.h>
  35. #include <cycle.h>
  36. #include <sysinit.h>
  37. static struct pktbuf rxpktbuf;
  38. static volatile int dorx = 0;
  39. static uint8_t rxbuf[128];
  40. static volatile int gotrxdone = 0;
  41. static volatile int gottxdone = 0;
  42. static volatile int goterr = 0;
  43. static volatile int rxbufsize = 0;
  44. static volatile int rxbuftrunc = 0;
  45. enum {
  46. CMD_TERMINATE = 1,
  47. CMD_WAITFOR = 2,
  48. CMD_RUNFOR = 3,
  49. CMD_PING = 4,
  50. CMD_SETUNSET = 5,
  51. CMD_ADV = 6,
  52. CMD_CLEAR = 7,
  53. CMD_KEY = 8,
  54. };
  55. static struct comms_state cs;
  56. static void
  57. c13led(void)
  58. {
  59. GPIO_InitTypeDef GPIO_InitStruct;
  60. __HAL_RCC_GPIOB_CLK_ENABLE();
  61. __HAL_RCC_GPIOC_CLK_ENABLE();
  62. GPIO_InitStruct = (GPIO_InitTypeDef){
  63. .Pin = GPIO_PIN_13,
  64. .Mode = GPIO_MODE_OUTPUT_PP,
  65. .Pull = GPIO_NOPULL,
  66. .Speed = GPIO_SPEED_FREQ_LOW,
  67. };
  68. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  69. HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
  70. }
  71. SYSINIT_VF(c13led, SI_SUB_HAL, SI_ORDER_SECOND, c13led);
  72. void
  73. txdone(void)
  74. {
  75. gottxdone = 1;
  76. }
  77. void
  78. errfunc(void)
  79. {
  80. debug_printf("error\n");
  81. goterr = 1;
  82. }
  83. struct pktbuf shared_key_buf = {
  84. .pkt = (uint8_t *)"abcd1234",
  85. .pktlen = 8,
  86. };
  87. static uint32_t rxts;
  88. void
  89. rxdone(const uint8_t *payload, size_t size)
  90. {
  91. if (size > sizeof rxbuf) {
  92. size = sizeof rxbuf;
  93. rxbuftrunc = 1;
  94. }
  95. debug_printf("rx: %d: %02x %02x ...\n", size, payload[0], payload[1]);
  96. memcpy(rxbuf, payload, size);
  97. rxbufsize = size;
  98. gotrxdone = 1;
  99. rxts = HAL_GetTick();
  100. }
  101. static inline uint32_t
  102. letoh_32(uint8_t *v)
  103. {
  104. return v[0] | (v[1] << 8) | (v[2] << 16) | ((unsigned)v[3] << 24);
  105. }
  106. static inline void
  107. htole_32(uint8_t *d, uint32_t v)
  108. {
  109. d[0] = v;
  110. d[1] = v >> 8;
  111. d[2] = v >> 16;
  112. d[3] = v >> 24;
  113. }
  114. struct chaninfo {
  115. GPIO_TypeDef *bank;
  116. uint16_t pinnum;
  117. bool init;
  118. bool invert;
  119. } chans[] = {
  120. [0] = { .bank = GPIOB, .pinnum = GPIO_PIN_5, .invert = true, },
  121. [1] = { .bank = GPIOB, .pinnum = GPIO_PIN_6, .invert = true, },
  122. [2] = { .bank = GPIOB, .pinnum = GPIO_PIN_7, .invert = true, },
  123. [3] = { .bank = GPIOB, .pinnum = GPIO_PIN_9, .invert = true, },
  124. /* Turn on LED at start */
  125. [4] = { .bank = GPIOB, .pinnum = GPIO_PIN_8, .init = true, },
  126. };
  127. #define nitems(x) (sizeof(x) / sizeof *(x))
  128. static void
  129. set_chan(uint32_t chan, bool val)
  130. {
  131. struct chaninfo ci;
  132. if (chan < nitems(chans)) {
  133. ci = chans[chan];
  134. HAL_GPIO_WritePin(ci.bank, ci.pinnum, val ^ ci.invert ?
  135. GPIO_PIN_SET : GPIO_PIN_RESET);
  136. }
  137. }
  138. static void
  139. setup_gpio(void)
  140. {
  141. GPIO_InitTypeDef GPIO_InitStruct;
  142. int i;
  143. for (i = 0; i < nitems(chans); i++) {
  144. GPIO_InitStruct = (GPIO_InitTypeDef){
  145. .Pin = chans[i].pinnum,
  146. .Mode = GPIO_MODE_OUTPUT_PP,
  147. .Pull = GPIO_NOPULL,
  148. .Speed = GPIO_SPEED_FREQ_LOW,
  149. };
  150. HAL_GPIO_Init(chans[i].bank, &GPIO_InitStruct);
  151. set_chan(i, chans[i].init);
  152. }
  153. }
  154. SYSINIT_VF(setup_gpio, SI_SUB_STANDARD, SI_ORDER_ANY, setup_gpio);
  155. static struct sched {
  156. uint32_t cmd;
  157. uint32_t end_wait_tick; /* end if running, otherwise how long to wait */
  158. uint32_t chan;
  159. } schedule[20];
  160. static int schedpos; /* position in schedule, % nitems(schedule)*/
  161. static int schedcnt; /* total items waiting */
  162. #define SCHED_ITEM(x) (schedule[(schedpos + x) % nitems(schedule)])
  163. #define SCHED_HEAD SCHED_ITEM(0)
  164. #define SCHED_TAIL SCHED_ITEM(schedcnt)
  165. static void
  166. start_sched(struct sched *sched)
  167. {
  168. sched->end_wait_tick += uwTick;
  169. if (sched->cmd == CMD_RUNFOR)
  170. set_chan(sched->chan, 1);
  171. }
  172. static bool
  173. canproc_sched()
  174. {
  175. /* nothing to do? */
  176. if (schedcnt == 0)
  177. return false;
  178. /* not yet expired */
  179. if (uwTick < SCHED_HEAD.end_wait_tick)
  180. return false;
  181. return true;
  182. }
  183. static void
  184. process_sched()
  185. {
  186. if (!canproc_sched())
  187. return;
  188. if (SCHED_HEAD.cmd == CMD_RUNFOR)
  189. set_chan(SCHED_HEAD.chan, 0);
  190. /* we are done, advance */
  191. schedpos++;
  192. schedcnt--;
  193. if (schedcnt)
  194. start_sched(&SCHED_HEAD);
  195. }
  196. static void
  197. enqueue_sched(uint32_t cmd, uint32_t ticks, uint32_t chan)
  198. {
  199. if (schedcnt >= nitems(schedule))
  200. return;
  201. SCHED_TAIL = (struct sched){
  202. .cmd = cmd,
  203. .end_wait_tick = ticks,
  204. .chan = chan,
  205. };
  206. if (schedcnt == 0)
  207. start_sched(&SCHED_HEAD);
  208. schedcnt++;
  209. }
  210. static void
  211. procmsg(struct pktbuf inbuf, struct pktbuf *outbuf)
  212. {
  213. uint32_t args[5];
  214. uint32_t keycnt;
  215. int i, r, apos, cnt;
  216. i = 1;
  217. apos = 0;
  218. for (i = 1, apos = 0; apos < sizeof args / sizeof *args && i + 4 <= inbuf.pktlen; i += 4, apos++) {
  219. args[apos] = letoh_32(&inbuf.pkt[i]);
  220. }
  221. outbuf->pkt[0] = inbuf.pkt[0];
  222. outbuf->pktlen = 1;
  223. switch (inbuf.pkt[0]) {
  224. case CMD_WAITFOR:
  225. if (apos == 1)
  226. enqueue_sched(CMD_WAITFOR, args[0], -1);
  227. break;
  228. case CMD_RUNFOR:
  229. if (apos == 2)
  230. enqueue_sched(CMD_RUNFOR, args[0], args[1]);
  231. break;
  232. case CMD_PING:
  233. break;
  234. case CMD_SETUNSET:
  235. if (apos == 2)
  236. set_chan(args[0], args[1]);
  237. break;
  238. case CMD_ADV:
  239. cnt = 1;
  240. if (apos == 1)
  241. cnt = args[0];
  242. for (i = 0; i < cnt && i < schedcnt; i++)
  243. SCHED_ITEM(i).end_wait_tick = 0;
  244. break;
  245. case CMD_CLEAR:
  246. if (schedcnt)
  247. schedcnt = 1;
  248. break;
  249. case CMD_KEY:
  250. i = 1;
  251. keycnt = 0;
  252. for (i = 1; i + REPORT_SIZE <= inbuf.pktlen; i += REPORT_SIZE) {
  253. r = report_insert(&inbuf.pkt[i]);
  254. if (!r)
  255. break;
  256. keycnt++;
  257. }
  258. htole_32(&outbuf->pkt[1], keycnt);
  259. outbuf->pktlen = 5;
  260. break;
  261. default:
  262. outbuf->pkt[0] = 0;
  263. break;
  264. }
  265. }
  266. static void
  267. setup_button()
  268. {
  269. GPIO_InitTypeDef GPIO_InitStruct;
  270. __HAL_RCC_GPIOA_CLK_ENABLE();
  271. GPIO_InitStruct = (GPIO_InitTypeDef){
  272. .Pin = GPIO_PIN_7,
  273. .Mode = GPIO_MODE_INPUT,
  274. .Pull = GPIO_PULLUP,
  275. .Speed = GPIO_SPEED_FREQ_LOW,
  276. };
  277. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  278. }
  279. SYSINIT_VF(setup_button, SI_SUB_STANDARD, SI_ORDER_ANY, setup_button);
  280. /* check if the button has been pushed, returns true once for each "push" */
  281. static int
  282. button_pushed(void)
  283. {
  284. static uint32_t lasthightick;
  285. static uint32_t waspushed;
  286. uint32_t tick;
  287. uint8_t pinstate;
  288. tick = HAL_GetTick();
  289. pinstate = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7);
  290. if (pinstate) {
  291. /* Reset button state */
  292. waspushed = 0;
  293. lasthightick = tick;
  294. return 0;
  295. }
  296. /* only return IF the it's been held for 5ms & wasn't returned before */
  297. if (tick - lasthightick > 5 && !waspushed) {
  298. waspushed = 1;
  299. return 1;
  300. }
  301. return 0;
  302. }
  303. static const uint8_t hexkeymap[] = {
  304. [0] = 0x27,
  305. [1] = 0x1e,
  306. [2] = 0x1f,
  307. [3] = 0x20,
  308. [4] = 0x21,
  309. [5] = 0x22,
  310. [6] = 0x23,
  311. [7] = 0x24,
  312. [8] = 0x25,
  313. [9] = 0x26,
  314. [10] = 0x04,
  315. [11] = 0x05,
  316. [12] = 0x06,
  317. [13] = 0x07,
  318. [14] = 0x08,
  319. [15] = 0x09,
  320. };
  321. static_assert(sizeof hexkeymap == 16);
  322. volatile uint32_t v;
  323. void
  324. report_blocking_insert(uint8_t rep[REPORT_SIZE])
  325. {
  326. int inserted;
  327. do {
  328. report_process();
  329. inserted = report_insert(rep);
  330. } while(!inserted);
  331. }
  332. int
  333. main()
  334. {
  335. struct strobepkikey keys;
  336. debug_printf("starting...");
  337. #if 0
  338. /* turn on LED */
  339. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
  340. #endif
  341. keys = get_key();
  342. comms_init(&cs, procmsg, NULL, &keys.privkey, &keys.pubkey);
  343. /* Clear out pointer to private key. */
  344. keys.privkey = (struct pktbuf){};
  345. rs485_register(txdone, rxdone, errfunc);
  346. uint8_t txbuf[128] = "i'mhere";
  347. struct pktbuf txpktbuf;
  348. txpktbuf = (struct pktbuf){
  349. .pkt = txbuf,
  350. .pktlen = 7,
  351. };
  352. //rs485_starttx(txpktbuf.pkt, txpktbuf.pktlen);
  353. dorx = 1;
  354. int laststartrx = 0;
  355. loop:
  356. while (canproc_sched())
  357. process_sched();
  358. #if 0
  359. BoardLowPowerHandler();
  360. #else
  361. //(void)BoardLowPowerHandler;
  362. #endif
  363. /* process any pending keys */
  364. report_process();
  365. if (button_pushed()) {
  366. /* Send the public key */
  367. uint8_t pubkey[EC_PUBLIC_BYTES];
  368. uint8_t reportbuf[REPORT_SIZE];
  369. const uint8_t *buf;
  370. int remainnibbles;
  371. uint8_t lastkey, key;
  372. get_pubkey(pubkey);
  373. buf = pubkey;
  374. remainnibbles = keys.pubkey.pktlen * 2;
  375. memset(reportbuf, 0, sizeof reportbuf);
  376. /* clear any previous key presses */
  377. report_blocking_insert(reportbuf);
  378. for (remainnibbles = keys.pubkey.pktlen * 2; remainnibbles; remainnibbles--) {
  379. /* top nibble when even, bottom when odd */
  380. if (remainnibbles & 1) {
  381. key = hexkeymap[buf[0] & 0xf];
  382. buf++;
  383. } else
  384. key = hexkeymap[buf[0] >> 4];
  385. lastkey = reportbuf[2];
  386. /*
  387. * if previous key matches, we need to "up" it, to make
  388. * a transition, otherwise, speed things along.
  389. */
  390. if (key == lastkey) {
  391. reportbuf[2] = 0;
  392. report_blocking_insert(reportbuf);
  393. }
  394. reportbuf[2] = key;
  395. report_blocking_insert(reportbuf);
  396. }
  397. /* clear last key */
  398. reportbuf[2] = 0;
  399. report_blocking_insert(reportbuf);
  400. }
  401. if (gottxdone) {
  402. dorx = 1;
  403. gottxdone = 0;
  404. }
  405. if (gotrxdone) {
  406. rxpktbuf = (struct pktbuf){
  407. .pkt = rxbuf,
  408. .pktlen = rxbufsize,
  409. };
  410. txpktbuf = (struct pktbuf){
  411. .pkt = txbuf,
  412. .pktlen = sizeof txbuf,
  413. };
  414. /* process available packet */
  415. #if 1
  416. uint32_t gt;
  417. gt = HAL_GetTick();
  418. reset_timer();
  419. start_timer();
  420. comms_process(&cs, rxpktbuf, &txpktbuf);
  421. stop_timer();
  422. debug_printf("comproc: %u cycles, ticks: %u, fromrx: %u\n", getCycles(), HAL_GetTick() - gt, HAL_GetTick() - rxts);
  423. #else
  424. txpktbuf = rxpktbuf;
  425. #endif
  426. //debug_printf("totx: %d: %02x %02x ...\n", txpktbuf.pktlen, txpktbuf.pkt[0], txpktbuf.pkt[1]);
  427. gotrxdone = false;
  428. if (txpktbuf.pktlen) {
  429. int i;
  430. //debug_printf("rx to tx: %d\n", HAL_GetTick() - rxts);
  431. for (i = 0; i < 1; i++) {
  432. //HAL_Delay(20);
  433. rs485_starttx(txpktbuf.pkt, txpktbuf.pktlen);
  434. }
  435. /* Make sure we don't interrupt tx */
  436. laststartrx = HAL_GetTick();
  437. } else {
  438. dorx = 1;
  439. }
  440. }
  441. if (dorx || goterr || HAL_GetTick() > laststartrx + 1000000) {
  442. //usb_printf("dorx\r\n");
  443. laststartrx = HAL_GetTick();
  444. rs485_startrx();
  445. //usb_printf("startrx res: %s\r\n", rs485err);
  446. dorx = 0;
  447. }
  448. goto loop;
  449. }