mirror of https://github.com/jeelabs/esp-link.git
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.
194 lines
4.9 KiB
194 lines
4.9 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
|
|
|
|
//===== 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=%d 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=%u\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 (!cmdInSync && packet->cmd != CMD_SYNC) {
|
|
// we have not received a sync, perhaps we reset? Tell MCU to do a sync
|
|
cmdResponseStart(CMD_SYNC, 0, 0);
|
|
cmdResponseEnd();
|
|
} else 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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|