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.
 
 
 
 
 
 

329 lines
7.8 KiB

  1. /*-
  2. * Copyright 2022 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. * 3. If you are STMicroelectronics N.V., one of it's subsidiaries, a
  13. * subsidiary of an owner of STMicroelectronics N.V., or an employee,
  14. * contractor, or agent of any of the preceeding entities, you are not
  15. * allowed to use this code, in either source or binary forms.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. */
  30. #include "usb_hid_def.h"
  31. #include <misc.h> /* debug_printf */
  32. #include <stdbool.h>
  33. #include <usb_hid_base.h>
  34. static uint8_t Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
  35. static uint8_t DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
  36. static uint8_t Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
  37. static uint8_t DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
  38. #if 0
  39. static uint8_t DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
  40. #endif
  41. static uint8_t ep0rxready(USBD_HandleTypeDef *pdev);
  42. #define USB_HID_EPIN_ADDR 0x81
  43. #define REPORT_CNT 10
  44. enum hid_state {
  45. IDLE,
  46. BUSY,
  47. };
  48. struct usb_hid_softc {
  49. enum hid_state state;
  50. uint8_t led_status[2];
  51. uint8_t idle_time;
  52. uint8_t report_protocol;
  53. };
  54. static USBD_HandleTypeDef *hid_handle;
  55. static uint32_t next_idle_report;
  56. static uint8_t reports[REPORT_CNT][REPORT_SIZE] = {
  57. /* mod pad keys... */
  58. #if 0
  59. [0] = { 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00 },
  60. [1] = { 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
  61. [2] = { 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 },
  62. [3] = { 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00 },
  63. [4] = { 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 },
  64. [5] = { 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 },
  65. [6] = { 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
  66. [7] = { 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
  67. [8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
  68. [9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
  69. #endif
  70. };
  71. /*
  72. * Ring buffer for reports.
  73. *
  74. * reporthead: next available report
  75. * reporttail: next empty slot
  76. *
  77. * reporthead == reporttail: ring buffer is empty
  78. * reporttail == reporthead - 1: ring buffer is full
  79. */
  80. static uint8_t reporthead = 0;
  81. static uint8_t reporttail = 0;
  82. static uint32_t reportoverflow;
  83. /* as -1 % posint == -1, adding REPORT_CNT keeps it positive if x is val - 1 when val is 0 */
  84. #define MAKE_POS(x) (((x) + REPORT_CNT) % REPORT_CNT)
  85. static bool
  86. report_is_avail(void)
  87. {
  88. return reporthead != reporttail;
  89. }
  90. static uint8_t *
  91. report_next(void)
  92. {
  93. int oldrep;
  94. /* no new report, don't advance, return previous */
  95. if (!report_is_avail())
  96. return reports[MAKE_POS(reporthead - 1)];
  97. oldrep = reporthead;
  98. reporthead = MAKE_POS(reporthead + 1);
  99. return reports[oldrep];
  100. }
  101. void
  102. report_process(void)
  103. {
  104. struct usb_hid_softc *hid;
  105. uint32_t tick;
  106. if (hid_handle == NULL)
  107. return;
  108. hid = (struct usb_hid_softc *)hid_handle->pClassData;
  109. if (hid_handle->dev_state != USBD_STATE_CONFIGURED ||
  110. hid->state != IDLE) {
  111. return;
  112. }
  113. tick = HAL_GetTick();
  114. if (!report_is_avail() && tick < next_idle_report)
  115. return;
  116. next_idle_report = tick + hid->idle_time;
  117. hid->state = BUSY;
  118. USBD_LL_Transmit(hid_handle, USB_HID_EPIN_ADDR, report_next(), REPORT_SIZE);
  119. }
  120. /*
  121. * This could be smarter by collapsing reports. The algorithm to do
  122. * so is a bit tricky, and likely not needed, BUT it does mean for a
  123. * simple algorithm, you could be limited to 50 chars per second assuming
  124. * 10ms report timing (one down, one up).
  125. *
  126. * Return true if successful, false if overflowed.
  127. */
  128. int
  129. report_insert(uint8_t rep[REPORT_SIZE])
  130. {
  131. uint8_t newtail;
  132. newtail = MAKE_POS(reporttail + 1);
  133. if (newtail == reporthead) {
  134. reportoverflow++;
  135. return 0;
  136. }
  137. memcpy(reports[reporttail], rep, sizeof reports[reporttail]);
  138. reporttail = newtail;
  139. return 1;
  140. }
  141. enum {
  142. HID_REQ_GET_REPORT = 0x01,
  143. HID_REQ_GET_IDLE = 0x02,
  144. HID_REQ_GET_PROTOCOL = 0x03,
  145. HID_REQ_SET_REPORT = 0x09,
  146. HID_REQ_SET_IDLE = 0x0a,
  147. HID_REQ_SET_PROTOCOL = 0x0b,
  148. };
  149. USBD_ClassTypeDef usb_hid_def = {
  150. .Init = Init,
  151. .DeInit = DeInit,
  152. .Setup = Setup,
  153. .EP0_RxReady = ep0rxready,
  154. .DataIn = DataIn,
  155. #if 0
  156. .DataOut = DataOut,
  157. #endif
  158. /* Get*Desc not used */
  159. };
  160. static uint8_t
  161. Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
  162. {
  163. struct usb_hid_softc *hid;
  164. int ret;
  165. ret = 0;
  166. usb_hid_epopen(pdev);
  167. /* allocate state data */
  168. hid = (void *)USBD_malloc(sizeof(struct usb_hid_softc));
  169. if (hid == NULL) {
  170. ret = 1;
  171. } else {
  172. *hid = (struct usb_hid_softc){
  173. .idle_time = 10,
  174. };
  175. pdev->pClassData = hid;
  176. hid_handle = pdev;
  177. }
  178. return ret;
  179. }
  180. static uint8_t
  181. DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
  182. {
  183. usb_hid_epclose(pdev);
  184. if (pdev->pClassData != NULL) {
  185. USBD_free(pdev->pClassData);
  186. pdev->pClassData = NULL;
  187. hid_handle = NULL;
  188. }
  189. return 0;
  190. }
  191. #define MAKE_CASE_REQ(type, req) ((((type) << 8) & USB_REQ_TYPE_MASK) | (req))
  192. #define USB_CASE_REQ(req) MAKE_CASE_REQ((req)->bmRequest, (req)->bRequest)
  193. static void
  194. send_ctlresp(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req, const uint8_t *buf, size_t len)
  195. {
  196. len = MIN(req->wLength, len);
  197. USBD_CtlSendData(pdev, (uint8_t *)(uintptr_t)buf, len);
  198. }
  199. /*
  200. * Handle non-standard control SETUP requests.
  201. *
  202. * This includes requests sent to the interface and other special
  203. * requests.
  204. */
  205. static uint8_t
  206. Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
  207. {
  208. struct usb_hid_softc *hid;
  209. uint8_t ret;
  210. ret = USBD_OK;
  211. hid = (struct usb_hid_softc *)pdev->pClassData;
  212. switch (USB_CASE_REQ(req)) {
  213. case MAKE_CASE_REQ(USB_REQ_TYPE_STANDARD, USB_REQ_GET_DESCRIPTOR):
  214. USBD_GetDescriptor(pdev, req);
  215. break;
  216. case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_GET_REPORT):
  217. send_ctlresp(pdev, req, report_next(), REPORT_SIZE);
  218. break;
  219. case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_SET_REPORT):
  220. break;
  221. case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_GET_IDLE):
  222. send_ctlresp(pdev, req, &hid->idle_time, sizeof hid->idle_time);
  223. break;
  224. case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_SET_IDLE):
  225. hid->idle_time = (uint8_t)(req->wValue >> 8);
  226. break;
  227. case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_GET_PROTOCOL):
  228. send_ctlresp(pdev, req, &hid->report_protocol, sizeof hid->idle_time);
  229. break;
  230. case MAKE_CASE_REQ(USB_REQ_TYPE_CLASS, HID_REQ_SET_PROTOCOL):
  231. hid->report_protocol = !!req->wValue;
  232. break;
  233. default:
  234. USBD_CtlError(pdev, req);
  235. ret = USBD_FAIL;
  236. break;
  237. }
  238. return ret;
  239. }
  240. static uint8_t
  241. DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
  242. {
  243. struct usb_hid_softc *hid;
  244. hid = (struct usb_hid_softc *)pdev->pClassData;
  245. /* Previously queued data was sent */
  246. hid->state = IDLE;
  247. return USBD_OK;
  248. }
  249. #if 0
  250. static uint8_t
  251. DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
  252. {
  253. /* received led status */
  254. return USBD_OK;
  255. }
  256. #endif
  257. static uint8_t
  258. ep0rxready(USBD_HandleTypeDef *pdev)
  259. {
  260. return USBD_OK;
  261. }