cmd.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
  2. //
  3. // Adapted from: github.com/tuanpmt/esp_bridge, Created on: Jan 9, 2015, Author: Minh
  4. #include "esp8266.h"
  5. #include "cmd.h"
  6. #include "crc16.h"
  7. #include "uart.h"
  8. #ifdef CMD_DBG
  9. #define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
  10. #else
  11. #define DBG(format, ...) do { } while(0)
  12. #endif
  13. //===== ESP -> Serial responses
  14. static void ICACHE_FLASH_ATTR
  15. cmdProtoWrite(uint8_t data) {
  16. switch(data){
  17. case SLIP_END:
  18. uart0_write_char(SLIP_ESC);
  19. uart0_write_char(SLIP_ESC_END);
  20. break;
  21. case SLIP_ESC:
  22. uart0_write_char(SLIP_ESC);
  23. uart0_write_char(SLIP_ESC_ESC);
  24. break;
  25. default:
  26. uart0_write_char(data);
  27. }
  28. }
  29. static void ICACHE_FLASH_ATTR
  30. cmdProtoWriteBuf(const uint8_t *data, short len) {
  31. while (len--) cmdProtoWrite(*data++);
  32. }
  33. static uint16_t resp_crc;
  34. // Start a response, returns the partial CRC
  35. void ICACHE_FLASH_ATTR
  36. cmdResponseStart(uint16_t cmd, uint32_t value, uint16_t argc) {
  37. DBG("cmdResponse: cmd=%d val=%d argc=%d\n", cmd, value, argc);
  38. uart0_write_char(SLIP_END);
  39. cmdProtoWriteBuf((uint8_t*)&cmd, 2);
  40. resp_crc = crc16_data((uint8_t*)&cmd, 2, 0);
  41. cmdProtoWriteBuf((uint8_t*)&argc, 2);
  42. resp_crc = crc16_data((uint8_t*)&argc, 2, resp_crc);
  43. cmdProtoWriteBuf((uint8_t*)&value, 4);
  44. resp_crc = crc16_data((uint8_t*)&value, 4, resp_crc);
  45. }
  46. // Adds data to a response, returns the partial CRC
  47. void ICACHE_FLASH_ATTR
  48. cmdResponseBody(const void *data, uint16_t len) {
  49. cmdProtoWriteBuf((uint8_t*)&len, 2);
  50. resp_crc = crc16_data((uint8_t*)&len, 2, resp_crc);
  51. cmdProtoWriteBuf(data, len);
  52. resp_crc = crc16_data(data, len, resp_crc);
  53. uint16_t pad = (4-((len+2)&3))&3; // get to multiple of 4
  54. if (pad > 0) {
  55. uint32_t temp = 0;
  56. cmdProtoWriteBuf((uint8_t*)&temp, pad);
  57. resp_crc = crc16_data((uint8_t*)&temp, pad, resp_crc);
  58. }
  59. }
  60. // Ends a response
  61. void ICACHE_FLASH_ATTR
  62. cmdResponseEnd() {
  63. cmdProtoWriteBuf((uint8_t*)&resp_crc, 2);
  64. uart0_write_char(SLIP_END);
  65. }
  66. //===== serial -> ESP commands
  67. // Execute a parsed command
  68. static void ICACHE_FLASH_ATTR
  69. cmdExec(const CmdList *scp, CmdPacket *packet) {
  70. // Iterate through the command table and call the appropriate function
  71. while (scp->sc_function != NULL) {
  72. if(scp->sc_name == packet->cmd) {
  73. DBG("cmdExec: Dispatching cmd=%s\n", scp->sc_text);
  74. // call command function
  75. scp->sc_function(packet);
  76. return;
  77. }
  78. scp++;
  79. }
  80. DBG("cmdExec: cmd=%d not found\n", packet->cmd);
  81. }
  82. // Parse a packet and print info about it
  83. void ICACHE_FLASH_ATTR
  84. cmdParsePacket(uint8_t *buf, short len) {
  85. // minimum command length
  86. if (len < sizeof(CmdPacket)) return;
  87. // init pointers into buffer
  88. CmdPacket *packet = (CmdPacket*)buf;
  89. uint8_t *data_ptr = (uint8_t*)&packet->args;
  90. uint8_t *data_limit = data_ptr+len;
  91. DBG("cmdParsePacket: cmd=%d argc=%d value=%u\n",
  92. packet->cmd,
  93. packet->argc,
  94. packet->value
  95. );
  96. #if 0
  97. // print out arguments
  98. uint16_t argn = 0;
  99. uint16_t argc = packet->argc;
  100. while (data_ptr+2 < data_limit && argc--) {
  101. short l = *(uint16_t*)data_ptr;
  102. os_printf("cmdParsePacket: arg[%d] len=%d:", argn++, l);
  103. data_ptr += 2;
  104. while (data_ptr < data_limit && l--) {
  105. os_printf(" %02X", *data_ptr++);
  106. }
  107. os_printf("\n");
  108. }
  109. #endif
  110. if (!cmdInSync && packet->cmd != CMD_SYNC) {
  111. // we have not received a sync, perhaps we reset? Tell MCU to do a sync
  112. cmdResponseStart(CMD_SYNC, 0, 0);
  113. cmdResponseEnd();
  114. } else if (data_ptr <= data_limit) {
  115. cmdExec(commands, packet);
  116. } else {
  117. DBG("cmdParsePacket: packet length overrun, parsing arg %d\n", packet->argc);
  118. }
  119. }
  120. //===== Helpers to parse a command packet
  121. // Fill out a CmdRequest struct given a CmdPacket
  122. void ICACHE_FLASH_ATTR
  123. cmdRequest(CmdRequest *req, CmdPacket* cmd) {
  124. req->cmd = cmd;
  125. req->arg_num = 0;
  126. req->arg_ptr = (uint8_t*)&cmd->args;
  127. }
  128. // Return the number of arguments given a command struct
  129. uint32_t ICACHE_FLASH_ATTR
  130. cmdGetArgc(CmdRequest *req) {
  131. return req->cmd->argc;
  132. }
  133. // Copy the next argument from a command structure into the data pointer, returns 0 on success
  134. // -1 on error
  135. int32_t ICACHE_FLASH_ATTR
  136. cmdPopArg(CmdRequest *req, void *data, uint16_t len) {
  137. uint16_t length;
  138. if (req->arg_num >= req->cmd->argc)
  139. return -1;
  140. length = *(uint16_t*)req->arg_ptr;
  141. if (length != len) return -1; // safety check
  142. req->arg_ptr += 2;
  143. os_memcpy(data, req->arg_ptr, length);
  144. req->arg_ptr += (length+3)&~3; // round up to multiple of 4
  145. req->arg_num ++;
  146. return 0;
  147. }
  148. // Skip the next argument
  149. void ICACHE_FLASH_ATTR
  150. cmdSkipArg(CmdRequest *req) {
  151. uint16_t length;
  152. if (req->arg_num >= req->cmd->argc) return;
  153. length = *(uint16_t*)req->arg_ptr;
  154. req->arg_ptr += 2;
  155. req->arg_ptr += (length+3)&~3;
  156. req->arg_num ++;
  157. }
  158. // Return the length of the next argument
  159. uint16_t ICACHE_FLASH_ATTR
  160. cmdArgLen(CmdRequest *req) {
  161. return *(uint16_t*)req->arg_ptr;
  162. }