loragw_mcu.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2020 Semtech
  8. Description:
  9. Host specific functions to address the LoRa concentrator registers through
  10. a USB interface.
  11. Single-byte read/write and burst read/write.
  12. License: Revised BSD License, see LICENSE.TXT file include in the project
  13. */
  14. /* -------------------------------------------------------------------------- */
  15. /* --- DEPENDANCIES --------------------------------------------------------- */
  16. #include <stdint.h> /* C99 types */
  17. #include <stdbool.h> /* bool type */
  18. #include <stdio.h> /* printf fprintf */
  19. #include <stdlib.h> /* rand */
  20. #include <unistd.h> /* lseek, close */
  21. #include <string.h> /* memset */
  22. #include <errno.h> /* Error number definitions */
  23. #include <termios.h> /* POSIX terminal control definitions */
  24. #include "loragw_mcu.h"
  25. #include "loragw_aux.h"
  26. /* -------------------------------------------------------------------------- */
  27. /* --- PRIVATE MACROS ------------------------------------------------------- */
  28. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  29. #if DEBUG_MCU == 1
  30. #define DEBUG_MSG(str) fprintf(stdout, str)
  31. #define DEBUG_PRINTF(fmt, args...) fprintf(stdout, fmt, args)
  32. #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return -1;}
  33. #else
  34. #define DEBUG_MSG(str)
  35. #define DEBUG_PRINTF(fmt, args...)
  36. #define CHECK_NULL(a) if(a==NULL){return -1;}
  37. #endif
  38. /* -------------------------------------------------------------------------- */
  39. /* --- PRIVATE CONSTANTS ---------------------------------------------------- */
  40. #if DEBUG_MCU == 1
  41. #define DEBUG_VERBOSE 0
  42. #endif
  43. #define HEADER_CMD_SIZE 4
  44. /* -------------------------------------------------------------------------- */
  45. /* --- PRIVATE TYPES -------------------------------------------------------- */
  46. typedef struct spi_req_bulk_s {
  47. uint16_t size;
  48. uint8_t nb_req;
  49. uint8_t buffer[LGW_USB_BURST_CHUNK];
  50. } spi_req_bulk_t;
  51. /* -------------------------------------------------------------------------- */
  52. /* --- PRIVATE VARIABLES --------------------------------------------------- */
  53. static uint8_t buf_hdr[HEADER_CMD_SIZE];
  54. static spi_req_bulk_t spi_bulk_buffer = {
  55. .size = 0,
  56. .nb_req = 0,
  57. .buffer = { 0 }
  58. };
  59. /* -------------------------------------------------------------------------- */
  60. /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
  61. int spi_req_bulk_insert(spi_req_bulk_t * bulk_buffer, uint8_t * req, uint16_t req_size) {
  62. /* Check input parameters */
  63. CHECK_NULL(bulk_buffer);
  64. CHECK_NULL(req);
  65. if (bulk_buffer->nb_req == 255) {
  66. printf("ERROR: cannot insert a new SPI request in bulk buffer - too many requests\n");
  67. return -1;
  68. }
  69. if ((bulk_buffer->size + req_size) > LGW_USB_BURST_CHUNK) {
  70. printf("ERROR: cannot insert a new SPI request in bulk buffer - buffer full\n");
  71. return -1;
  72. }
  73. /* Add a new request entry in storage buffer */
  74. memcpy(bulk_buffer->buffer + bulk_buffer->size, req, req_size);
  75. bulk_buffer->nb_req += 1;
  76. bulk_buffer->size += req_size;
  77. return 0;
  78. }
  79. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  80. uint32_t bytes_be_to_uint32_le(const uint8_t * bytes) {
  81. uint32_t val = 0;
  82. if (bytes != NULL) {
  83. /* Big endian to Little Endian */
  84. val = (uint32_t)(bytes[0] << 24);
  85. val |= (uint32_t)(bytes[1] << 16);
  86. val |= (uint32_t)(bytes[2] << 8);
  87. val |= (uint32_t)(bytes[3] << 0);
  88. }
  89. return val;
  90. }
  91. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  92. int32_t bytes_be_to_int32_le(const uint8_t * bytes) {
  93. int32_t val = 0;
  94. if (bytes != NULL) {
  95. /* Big endian to Little Endian */
  96. val = (int32_t)(bytes[0] << 24);
  97. val |= (int32_t)(bytes[1] << 16);
  98. val |= (int32_t)(bytes[2] << 8);
  99. val |= (int32_t)(bytes[3] << 0);
  100. }
  101. return val;
  102. }
  103. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  104. const char * cmd_get_str(const uint8_t cmd) {
  105. switch (cmd) {
  106. case ORDER_ID__REQ_PING:
  107. return "REQ_PING";
  108. case ORDER_ID__REQ_GET_STATUS:
  109. return "REQ_GET_STATUS";
  110. case ORDER_ID__REQ_BOOTLOADER_MODE:
  111. return "REQ_BOOTLOADER_MODE";
  112. case ORDER_ID__REQ_RESET:
  113. return "REQ_RESET";
  114. case ORDER_ID__REQ_WRITE_GPIO:
  115. return "REQ_WRITE_GPIO";
  116. case ORDER_ID__REQ_MULTIPLE_SPI:
  117. return "REQ_MULTIPLE_SPI";
  118. default:
  119. return "UNKNOWN";
  120. }
  121. }
  122. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  123. uint8_t cmd_get_id(const uint8_t * bytes) {
  124. return bytes[0];
  125. }
  126. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  127. uint16_t cmd_get_size(const uint8_t * bytes) {
  128. return (uint16_t)(bytes[1] << 8) | bytes[2];
  129. }
  130. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  131. uint8_t cmd_get_type(const uint8_t * bytes) {
  132. return bytes[3];
  133. }
  134. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  135. const char * spi_status_get_str(const uint8_t status) {
  136. switch (status) {
  137. case SPI_STATUS_OK:
  138. return "SPI_STATUS_OK";
  139. case SPI_STATUS_FAIL:
  140. return "SPI_STATUS_FAIL";
  141. case SPI_STATUS_WRONG_PARAM:
  142. return "SPI_STATUS_WRONG_PARAM";
  143. case SPI_STATUS_TIMEOUT:
  144. return "SPI_STATUS_TIMEOUT";
  145. default:
  146. return "SPI_STATUS_UNKNOWN";
  147. }
  148. }
  149. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  150. int write_req(int fd, order_id_t cmd, const uint8_t * payload, uint16_t payload_size ) {
  151. uint8_t buf_w[HEADER_CMD_SIZE];
  152. int n;
  153. /* performances variables */
  154. struct timeval tm;
  155. /* debug variables */
  156. #if DEBUG_MCU == 1
  157. struct timeval write_tv;
  158. #endif
  159. /* Record function start time */
  160. _meas_time_start(&tm);
  161. /* Check input params */
  162. if (payload_size > MAX_SIZE_COMMAND) {
  163. printf("ERROR: payload size exceeds maximum transfer size (req:%u, max:%d)\n", payload_size, MAX_SIZE_COMMAND);
  164. return -1;
  165. }
  166. /* Write command header */
  167. buf_w[0] = rand() % 255;
  168. buf_w[1] = (uint8_t)(payload_size >> 8); /* MSB */
  169. buf_w[2] = (uint8_t)(payload_size >> 0); /* LSB */
  170. buf_w[3] = cmd;
  171. n = write(fd, buf_w, HEADER_CMD_SIZE);
  172. if (n < 0) {
  173. printf("ERROR: failed to write command header to com port\n");
  174. return -1;
  175. }
  176. /* Write command payload */
  177. if (payload_size > 0) {
  178. if (payload == NULL) {
  179. printf("ERROR: invalid payload\n");
  180. return -1;
  181. }
  182. n = write(fd, payload, payload_size);
  183. if (n < 0) {
  184. printf("ERROR: failed to write command payload to com port\n");
  185. return -1;
  186. }
  187. }
  188. #if DEBUG_MCU == 1
  189. gettimeofday(&write_tv, NULL);
  190. #endif
  191. DEBUG_PRINTF("\nINFO: %ld.%ld: write_req 0x%02X (%s) done, id:0x%02X, size:%u\n", write_tv.tv_sec, write_tv.tv_usec, cmd, cmd_get_str(cmd), buf_w[0], payload_size);
  192. #if DEBUG_VERBOSE
  193. int i;
  194. for (i = 0; i < 4; i++) {
  195. printf("%02X ", buf_w[i]);
  196. }
  197. for (i = 0; i < payload_size; i++) {
  198. printf("%02X ", payload[i]);
  199. }
  200. printf("\n");
  201. #endif
  202. /* Compute time spent in this function */
  203. _meas_time_stop(5, tm, __FUNCTION__);
  204. return 0;
  205. }
  206. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  207. int read_ack(int fd, uint8_t * hdr, uint8_t * buf, size_t buf_size) {
  208. #if DEBUG_VERBOSE
  209. int i;
  210. #endif
  211. int n;
  212. size_t size;
  213. int nb_read = 0;
  214. /* performances variables */
  215. struct timeval tm;
  216. /* debug variables */
  217. #if DEBUG_MCU == 1
  218. struct timeval read_tv;
  219. #endif
  220. /* Record function start time */
  221. _meas_time_start(&tm);
  222. /* Read message header first, handle EINTR as it is a blocking call */
  223. do {
  224. n = read(fd, &hdr[0], (size_t)HEADER_CMD_SIZE);
  225. } while (n == -1 && errno == EINTR);
  226. if (n == -1) {
  227. perror("ERROR: Unable to read /dev/ttyACMx - ");
  228. return -1;
  229. } else {
  230. #if DEBUG_MCU == 1
  231. gettimeofday(&read_tv, NULL);
  232. #endif
  233. DEBUG_PRINTF("INFO: %ld.%ld: read %d bytes for header from gateway\n", read_tv.tv_sec, read_tv.tv_usec, n);
  234. }
  235. /* Compute time spent in this function */
  236. _meas_time_stop(5, tm, "read_ack(hdr)");
  237. #if DEBUG_VERBOSE
  238. printf("read_ack(hdr):");
  239. /* debug print */
  240. for (i = 0; i < (int)(HEADER_CMD_SIZE); i++) {
  241. printf("%02X ", hdr[i]);
  242. }
  243. printf("\n");
  244. #endif
  245. /* Record function start time */
  246. _meas_time_start(&tm);
  247. /* Check if the command id is valid */
  248. if ((cmd_get_type(hdr) < 0x40) || (cmd_get_type(hdr) > 0x46)) {
  249. printf("ERROR: received wrong ACK type (0x%02X)\n", cmd_get_type(hdr));
  250. return -1;
  251. }
  252. /* Get remaining payload size (metadata + pkt payload) */
  253. size = (size_t)cmd_get_size(hdr);
  254. if (size > buf_size) {
  255. printf("ERROR: not enough memory to store all data (%zd)\n", size);
  256. return -1;
  257. }
  258. /* Read payload if any */
  259. if (size > 0) {
  260. do {
  261. /* handle EINTR as it is a blocking call */
  262. do {
  263. n = read(fd, &buf[nb_read], size - nb_read);
  264. } while (n == -1 && errno == EINTR);
  265. if (n == -1) {
  266. perror("ERROR: Unable to read /dev/ttyACMx - ");
  267. return -1;
  268. } else {
  269. #if DEBUG_MCU == 1
  270. gettimeofday(&read_tv, NULL);
  271. #endif
  272. DEBUG_PRINTF("INFO: %ld.%ld: read %d bytes from gateway\n", read_tv.tv_sec, read_tv.tv_usec, n);
  273. nb_read += n;
  274. }
  275. } while (nb_read < (int)size); /* we want to read only the expected payload, not more */
  276. #if DEBUG_VERBOSE
  277. /* debug print */
  278. printf("read_ack(pld):");
  279. for (i = 0; i < (int)size; i++) {
  280. printf("%02X ", buf[i]);
  281. }
  282. printf("\n");
  283. #endif
  284. }
  285. /* Compute time spent in this function */
  286. _meas_time_stop(5, tm, "read_ack(payload)");
  287. return nb_read;
  288. }
  289. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  290. int decode_ack_ping(const uint8_t * hdr, const uint8_t * payload, s_ping_info * info) {
  291. /* sanity checks */
  292. if ((hdr == NULL) || (payload == NULL) || (info == NULL)) {
  293. printf("ERROR: invalid parameter\n");
  294. return -1;
  295. }
  296. if (cmd_get_type(hdr) != ORDER_ID__ACK_PING) {
  297. printf("ERROR: wrong ACK type for PING (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_PING, cmd_get_type(hdr));
  298. return -1;
  299. }
  300. /* payload info */
  301. info->unique_id_high = bytes_be_to_uint32_le(&payload[ACK_PING__UNIQUE_ID_0]);
  302. info->unique_id_mid = bytes_be_to_uint32_le(&payload[ACK_PING__UNIQUE_ID_4]);
  303. info->unique_id_low = bytes_be_to_uint32_le(&payload[ACK_PING__UNIQUE_ID_8]);
  304. memcpy(info->version, &payload[ACK_PING__VERSION_0], (sizeof info->version) - 1);
  305. info->version[(sizeof info->version) - 1] = '\0'; /* terminate string */
  306. #if DEBUG_VERBOSE
  307. DEBUG_MSG ("## ACK_PING\n");
  308. DEBUG_PRINTF(" id: 0x%02X\n", cmd_get_id(hdr));
  309. DEBUG_PRINTF(" size: %u\n", cmd_get_size(hdr));
  310. DEBUG_PRINTF(" unique_id: 0x%08X%08X%08X\n", info->unique_id_high, info->unique_id_mid, info->unique_id_low);
  311. DEBUG_PRINTF(" FW version: %s\n", info->version);
  312. #endif
  313. return 0;
  314. }
  315. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  316. int decode_ack_bootloader_mode(const uint8_t * hdr) {
  317. /* sanity checks */
  318. if (hdr == NULL) {
  319. printf("ERROR: invalid parameter\n");
  320. return -1;
  321. }
  322. if (cmd_get_type(hdr) != ORDER_ID__ACK_BOOTLOADER_MODE) {
  323. printf("ERROR: wrong ACK type for ACK_BOOTLOADER_MODE (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_BOOTLOADER_MODE, cmd_get_type(hdr));
  324. return -1;
  325. }
  326. #if DEBUG_VERBOSE
  327. DEBUG_MSG ("## ACK_BOOTLOADER_MODE\n");
  328. DEBUG_PRINTF(" id: 0x%02X\n", cmd_get_id(hdr));
  329. DEBUG_PRINTF(" size: %u\n", cmd_get_size(hdr));
  330. #endif
  331. return 0;
  332. }
  333. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  334. int decode_ack_get_status(const uint8_t * hdr, const uint8_t * payload, s_status * status) {
  335. int16_t temperature_sensor;
  336. /* sanity checks */
  337. if ((payload == NULL) || (status == NULL)) {
  338. printf("ERROR: invalid parameter\n");
  339. return -1;
  340. }
  341. if (cmd_get_type(hdr) != ORDER_ID__ACK_GET_STATUS) {
  342. printf("ERROR: wrong ACK type for GET_STATUS (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_GET_STATUS, cmd_get_type(hdr));
  343. return -1;
  344. }
  345. /* payload info */
  346. status->system_time_ms = bytes_be_to_uint32_le(&payload[ACK_GET_STATUS__SYSTEM_TIME_31_24]);
  347. temperature_sensor = (int16_t)(payload[ACK_GET_STATUS__TEMPERATURE_15_8] << 8) |
  348. (int16_t)(payload[ACK_GET_STATUS__TEMPERATURE_7_0] << 0);
  349. status->temperature = (float)temperature_sensor / 100.0;
  350. #if DEBUG_VERBOSE
  351. DEBUG_MSG ("## ACK_GET_STATUS\n");
  352. DEBUG_PRINTF(" id: 0x%02X\n", cmd_get_id(hdr));
  353. DEBUG_PRINTF(" size: %u\n", cmd_get_size(hdr));
  354. DEBUG_PRINTF(" sys_time: %u\n", status->system_time_ms);
  355. DEBUG_PRINTF(" temperature: %.1f\n", status->temperature);
  356. #endif
  357. return 0;
  358. }
  359. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  360. int decode_ack_gpio_access(const uint8_t * hdr, const uint8_t * payload, uint8_t * write_status) {
  361. if ((hdr == NULL) || (payload == NULL) || (write_status == NULL)) {
  362. printf("ERROR: invalid parameter\n");
  363. return -1;
  364. }
  365. if (cmd_get_type(hdr) != ORDER_ID__ACK_WRITE_GPIO) {
  366. printf("ERROR: wrong ACK type for WRITE_GPIO (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_WRITE_GPIO, cmd_get_type(hdr));
  367. return -1;
  368. }
  369. /* payload info */
  370. *write_status = payload[ACK_GPIO_WRITE__STATUS];
  371. #if DEBUG_VERBOSE
  372. DEBUG_MSG ("## ACK_WRITE_GPIO\n");
  373. DEBUG_PRINTF(" id: 0x%02X\n", cmd_get_id(hdr));
  374. DEBUG_PRINTF(" size: %u\n", cmd_get_size(hdr));
  375. DEBUG_PRINTF(" status: %u\n", *write_status);
  376. #endif
  377. return 0;
  378. }
  379. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  380. int decode_ack_spi_bulk(const uint8_t * hdr, const uint8_t * payload) {
  381. uint8_t req_id, req_type, req_status;
  382. uint16_t frame_size;
  383. int i;
  384. /* sanity checks */
  385. if ((hdr == NULL) || (payload == NULL)) {
  386. printf("ERROR: invalid parameter\n");
  387. return -1;
  388. }
  389. if (cmd_get_type(hdr) != ORDER_ID__ACK_MULTIPLE_SPI) {
  390. printf("ERROR: wrong ACK type for ACK_MULTIPLE_SPI (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_MULTIPLE_SPI, cmd_get_type(hdr));
  391. return -1;
  392. }
  393. #if DEBUG_VERBOSE
  394. DEBUG_MSG ("## ACK_SPI_BULK\n");
  395. DEBUG_PRINTF(" id: 0x%02X\n", cmd_get_id(hdr));
  396. DEBUG_PRINTF(" size: %u\n", cmd_get_size(hdr));
  397. #endif
  398. i = 0;
  399. while (i < cmd_get_size(hdr)) {
  400. /* parse the request */
  401. req_id = payload[i + 0];
  402. req_type = payload[i + 1];
  403. if (req_type != MCU_SPI_REQ_TYPE_READ_WRITE && req_type != MCU_SPI_REQ_TYPE_READ_MODIFY_WRITE) {
  404. printf("ERROR: %s: wrong type for SPI request %u (0x%02X)\n", __FUNCTION__, req_id, req_type);
  405. return -1;
  406. }
  407. req_status = payload[i + 2];
  408. if (req_status != 0) {
  409. /* Exit if any of the requests failed */
  410. printf("ERROR: %s: SPI request %u failed with %u - %s\n", __FUNCTION__, req_id, req_status, spi_status_get_str(req_status));
  411. return -1;
  412. }
  413. #if DEBUG_VERBOSE
  414. DEBUG_PRINTF(" ----- REQ_SPI %u -----\n", req_id);
  415. DEBUG_PRINTF(" type %s\n", (req_type == MCU_SPI_REQ_TYPE_READ_WRITE) ? "read/write" : "read-modify-write");
  416. DEBUG_PRINTF(" status %u\n", req_status);
  417. #endif
  418. /* Move to the next REQ */
  419. if (req_type == MCU_SPI_REQ_TYPE_READ_WRITE) {
  420. frame_size = (uint16_t)(payload[i + 3] << 8) | (uint16_t)(payload[i + 4]);
  421. #if DEBUG_VERBOSE
  422. int j;
  423. DEBUG_PRINTF(" RAW SPI frame (sz:%u): ", frame_size);
  424. for (j = 0; j < frame_size; j++) {
  425. DEBUG_PRINTF(" %02X", payload[i + 5 + j]);
  426. }
  427. DEBUG_MSG("\n");
  428. #endif
  429. i += (5 + frame_size); /* REQ ACK metadata + SPI raw frame */
  430. } else {
  431. #if DEBUG_VERBOSE
  432. DEBUG_PRINTF(" read value 0x%02X\n", payload[i + 3]);
  433. DEBUG_PRINTF(" modified value 0x%02X\n", payload[i + 4]);
  434. #endif
  435. i += 5;
  436. }
  437. }
  438. return 0;
  439. }
  440. /* -------------------------------------------------------------------------- */
  441. /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
  442. int mcu_ping(int fd, s_ping_info * info) {
  443. uint8_t buf_ack[ACK_PING_SIZE];
  444. CHECK_NULL(info);
  445. if (write_req(fd, ORDER_ID__REQ_PING, NULL, 0) != 0) {
  446. printf("ERROR: failed to write PING request\n");
  447. return -1;
  448. }
  449. if (read_ack(fd, buf_hdr, buf_ack, sizeof buf_ack) < 0) {
  450. printf("ERROR: failed to read PING ack\n");
  451. return -1;
  452. }
  453. if (decode_ack_ping(buf_hdr, buf_ack, info) != 0) {
  454. printf("ERROR: invalid PING ack\n");
  455. return -1;
  456. }
  457. return 0;
  458. }
  459. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  460. int mcu_boot(int fd) {
  461. if (write_req(fd, ORDER_ID__REQ_BOOTLOADER_MODE, NULL, 0) != 0) {
  462. printf("ERROR: failed to write BOOTLOADER_MODE request\n");
  463. return -1;
  464. }
  465. if (read_ack(fd, buf_hdr, NULL, 0) < 0) {
  466. printf("ERROR: failed to read BOOTLOADER_MODE ack\n");
  467. return -1;
  468. }
  469. if (decode_ack_bootloader_mode(buf_hdr) != 0) {
  470. printf("ERROR: invalid BOOTLOADER_MODE ack\n");
  471. return -1;
  472. }
  473. return 0;
  474. }
  475. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  476. int mcu_get_status(int fd, s_status * status) {
  477. uint8_t buf_ack[ACK_GET_STATUS_SIZE];
  478. CHECK_NULL(status);
  479. if (write_req(fd, ORDER_ID__REQ_GET_STATUS, NULL, 0) != 0) {
  480. printf("ERROR: failed to write GET_STATUS request\n");
  481. return -1;
  482. }
  483. if (read_ack(fd, buf_hdr, buf_ack, sizeof buf_ack) < 0) {
  484. printf("ERROR: failed to read GET_STATUS ack\n");
  485. return -1;
  486. }
  487. if (decode_ack_get_status(buf_hdr, buf_ack, status) != 0) {
  488. printf("ERROR: invalid GET_STATUS ack\n");
  489. return -1;
  490. }
  491. return 0;
  492. }
  493. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  494. int mcu_gpio_write(int fd, uint8_t gpio_port, uint8_t gpio_id, uint8_t gpio_value) {
  495. uint8_t status;
  496. uint8_t buf_req[REQ_WRITE_GPIO_SIZE];
  497. uint8_t buf_ack[ACK_GPIO_WRITE_SIZE];
  498. buf_req[REQ_WRITE_GPIO__PORT] = gpio_port;
  499. buf_req[REQ_WRITE_GPIO__PIN] = gpio_id;
  500. buf_req[REQ_WRITE_GPIO__STATE] = gpio_value;
  501. if (write_req(fd, ORDER_ID__REQ_WRITE_GPIO, buf_req, REQ_WRITE_GPIO_SIZE) != 0) {
  502. printf("ERROR: failed to write REQ_WRITE_GPIO request\n");
  503. return -1;
  504. }
  505. if (read_ack(fd, buf_hdr, buf_ack, sizeof buf_ack) < 0) {
  506. printf("ERROR: failed to read PING ack\n");
  507. return -1;
  508. }
  509. if (decode_ack_gpio_access(buf_hdr, buf_ack, &status) != 0) {
  510. printf("ERROR: invalid REQ_WRITE_GPIO ack\n");
  511. return -1;
  512. }
  513. if (status != 0) {
  514. printf("ERROR: Failed to write GPIO (port:%u id:%u value:%u)\n", gpio_port, gpio_id, gpio_value);
  515. return -1;
  516. }
  517. return 0;
  518. }
  519. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  520. int mcu_spi_write(int fd, uint8_t * in_out_buf, size_t buf_size) {
  521. /* Check input parameters */
  522. CHECK_NULL(in_out_buf);
  523. if (write_req(fd, ORDER_ID__REQ_MULTIPLE_SPI, in_out_buf, buf_size) != 0) {
  524. printf("ERROR: failed to write REQ_MULTIPLE_SPI request\n");
  525. return -1;
  526. }
  527. if (read_ack(fd, buf_hdr, in_out_buf, buf_size) < 0) {
  528. printf("ERROR: failed to read REQ_MULTIPLE_SPI ack\n");
  529. return -1;
  530. }
  531. if (decode_ack_spi_bulk(buf_hdr, in_out_buf) != 0) {
  532. printf("ERROR: invalid REQ_MULTIPLE_SPI ack\n");
  533. return -1;
  534. }
  535. return 0;
  536. }
  537. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  538. int mcu_spi_store(uint8_t * in_out_buf, size_t buf_size) {
  539. CHECK_NULL(in_out_buf);
  540. return spi_req_bulk_insert(&spi_bulk_buffer, in_out_buf, buf_size);
  541. }
  542. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  543. int mcu_spi_flush(int fd) {
  544. /* Write pending SPI requests to MCU */
  545. if (mcu_spi_write(fd, spi_bulk_buffer.buffer, spi_bulk_buffer.size) != 0) {
  546. printf("ERROR: %s: failed to write SPI requests to MCU\n", __FUNCTION__);
  547. return -1;
  548. }
  549. /* Reset bulk storage buffer */
  550. spi_bulk_buffer.nb_req = 0;
  551. spi_bulk_buffer.size = 0;
  552. return 0;
  553. }
  554. /* --- EOF ------------------------------------------------------------------ */