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.
 
 
 
 
 
 
esp-link/cmd/cmd.c

210 lines
5.1 KiB

// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
//
// Adapted from: github.com/tuanpmt/esp_bridge, Created on: Jan 9, 2015, Author: Minh
#include "esp8266.h"
#include "cmd.h"
#include "crc16.h"
#include "uart.h"
#ifdef CMD_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
#else
#define DBG(format, ...) do { } while(0)
#endif
extern const CmdList commands[];
//===== ESP -> Serial responses
static void ICACHE_FLASH_ATTR
cmdProtoWrite(uint8_t data) {
switch(data){
case SLIP_END:
uart0_write_char(SLIP_ESC);
uart0_write_char(SLIP_ESC_END);
break;
case SLIP_ESC:
uart0_write_char(SLIP_ESC);
uart0_write_char(SLIP_ESC_ESC);
break;
default:
uart0_write_char(data);
}
}
static void ICACHE_FLASH_ATTR
cmdProtoWriteBuf(const uint8_t *data, short len) {
while (len--) cmdProtoWrite(*data++);
}
static uint16_t resp_crc;
// Start a response, returns the partial CRC
void ICACHE_FLASH_ATTR
cmdResponseStart(uint16_t cmd, uint32_t value, uint16_t argc) {
DBG("cmdResponse: cmd=%d val=%ld argc=%d\n", cmd, value, argc);
uart0_write_char(SLIP_END);
cmdProtoWriteBuf((uint8_t*)&cmd, 2);
resp_crc = crc16_data((uint8_t*)&cmd, 2, 0);
cmdProtoWriteBuf((uint8_t*)&argc, 2);
resp_crc = crc16_data((uint8_t*)&argc, 2, resp_crc);
cmdProtoWriteBuf((uint8_t*)&value, 4);
resp_crc = crc16_data((uint8_t*)&value, 4, resp_crc);
}
// Adds data to a response, returns the partial CRC
void ICACHE_FLASH_ATTR
cmdResponseBody(const void *data, uint16_t len) {
cmdProtoWriteBuf((uint8_t*)&len, 2);
resp_crc = crc16_data((uint8_t*)&len, 2, resp_crc);
cmdProtoWriteBuf(data, len);
resp_crc = crc16_data(data, len, resp_crc);
uint16_t pad = (4-((len+2)&3))&3; // get to multiple of 4
if (pad > 0) {
uint32_t temp = 0;
cmdProtoWriteBuf((uint8_t*)&temp, pad);
resp_crc = crc16_data((uint8_t*)&temp, pad, resp_crc);
}
}
// Ends a response
void ICACHE_FLASH_ATTR
cmdResponseEnd() {
cmdProtoWriteBuf((uint8_t*)&resp_crc, 2);
uart0_write_char(SLIP_END);
}
//===== serial -> ESP commands
// Execute a parsed command
static void ICACHE_FLASH_ATTR
cmdExec(const CmdList *scp, CmdPacket *packet) {
// Iterate through the command table and call the appropriate function
while (scp->sc_function != NULL) {
if(scp->sc_name == packet->cmd) {
DBG("cmdExec: Dispatching cmd=%s\n", scp->sc_text);
// call command function
scp->sc_function(packet);
return;
}
scp++;
}
DBG("cmdExec: cmd=%d not found\n", packet->cmd);
}
// Parse a packet and print info about it
void ICACHE_FLASH_ATTR
cmdParsePacket(uint8_t *buf, short len) {
// minimum command length
if (len < sizeof(CmdPacket)) return;
// init pointers into buffer
CmdPacket *packet = (CmdPacket*)buf;
uint8_t *data_ptr = (uint8_t*)&packet->args;
uint8_t *data_limit = data_ptr+len;
DBG("cmdParsePacket: cmd=%d argc=%d value=%lu\n",
packet->cmd,
packet->argc,
packet->value
);
#if 0
// print out arguments
uint16_t argn = 0;
uint16_t argc = packet->argc;
while (data_ptr+2 < data_limit && argc--) {
short l = *(uint16_t*)data_ptr;
os_printf("cmdParsePacket: arg[%d] len=%d:", argn++, l);
data_ptr += 2;
while (data_ptr < data_limit && l--) {
os_printf(" %02X", *data_ptr++);
}
os_printf("\n");
}
#endif
if (data_ptr <= data_limit) {
cmdExec(commands, packet);
} else {
DBG("cmdParsePacket: packet length overrun, parsing arg %d\n", packet->argc);
}
}
//===== Helpers to parse a command packet
// Fill out a CmdRequest struct given a CmdPacket
void ICACHE_FLASH_ATTR
cmdRequest(CmdRequest *req, CmdPacket* cmd) {
req->cmd = cmd;
req->arg_num = 0;
req->arg_ptr = (uint8_t*)&cmd->args;
}
// Return the number of arguments given a command struct
uint32_t ICACHE_FLASH_ATTR
cmdGetArgc(CmdRequest *req) {
return req->cmd->argc;
}
// Copy the next argument from a command structure into the data pointer, returns 0 on success
// -1 on error
int32_t ICACHE_FLASH_ATTR
cmdPopArg(CmdRequest *req, void *data, uint16_t len) {
uint16_t length;
if (req->arg_num >= req->cmd->argc)
return -1;
length = *(uint16_t*)req->arg_ptr;
if (length != len) return -1; // safety check
req->arg_ptr += 2;
os_memcpy(data, req->arg_ptr, length);
req->arg_ptr += (length+3)&~3; // round up to multiple of 4
req->arg_num ++;
return 0;
}
// Copy the next argument from a command structure into the data pointer, returns 0 on success
// -1 on error
int32_t ICACHE_FLASH_ATTR
cmdPopArgPtr(CmdRequest *req, void **pPtr, uint16_t *pLen) {
if (req->arg_num >= req->cmd->argc)
return -1;
*pLen = *(uint16_t*)req->arg_ptr;
req->arg_ptr += 2;
*pPtr = req->arg_ptr;
req->arg_ptr += (*pLen+3)&~3; // round up to multiple of 4
req->arg_num ++;
return 0;
}
// Skip the next argument
void ICACHE_FLASH_ATTR
cmdSkipArg(CmdRequest *req) {
uint16_t length;
if (req->arg_num >= req->cmd->argc) return;
length = *(uint16_t*)req->arg_ptr;
req->arg_ptr += 2;
req->arg_ptr += (length+3)&~3;
req->arg_num ++;
}
// Return the length of the next argument
uint16_t ICACHE_FLASH_ATTR
cmdArgLen(CmdRequest *req) {
return *(uint16_t*)req->arg_ptr;
}