Button feature is working

pull/193/head
Karai Csaba 9 years ago committed by Thorsten von Eicken
parent 21fbbf6a8a
commit f75c1acf95
  1. 3
      cmd/cmd.h
  2. 207
      examples/arduino/EspLinkSample/EspLink.cpp
  3. 91
      examples/arduino/EspLinkSample/EspLink.h
  4. 70
      examples/arduino/EspLinkSample/EspLinkSample.ino
  5. 11
      examples/arduino/EspLinkSample/WebServer.h
  6. 5
      serial/serbridge.c
  7. 2
      serial/serbridge.h
  8. 95
      web-server/web-server.c
  9. 10
      web-server/web-server.h

@ -48,6 +48,9 @@ typedef enum {
CMD_REST_SETUP = 20,
CMD_REST_REQUEST,
CMD_REST_SETHEADER,
CMD_WEB_DATA = 30,
CMD_WEB_REQ_CB,
} CmdName;
typedef void (*cmdfunc_t)(CmdPacket *cmd);

@ -0,0 +1,207 @@
#include "EspLink.h"
#define READ_BUF_DFLT_SIZE 64
// Standard SLIP escape chars from RFC
#define SLIP_END 0300 // indicates end of packet
#define SLIP_ESC 0333 // indicates byte stuffing
#define SLIP_ESC_END 0334 // ESC ESC_END means END data byte
#define SLIP_ESC_ESC 0335 // ESC ESC_ESC means ESC data byte
EspLink::EspLink(Stream &streamIn, CmdRequestCB callback):stream(streamIn),requestCb(callback)
{
readBuf = NULL;
readLastChar = 0;
}
EspLink::~EspLink()
{
if( readBuf != NULL )
free( readBuf );
readBuf = NULL;
}
void EspLink::writeChar(uint8_t data)
{
switch(data)
{
case SLIP_END:
stream.write(SLIP_ESC);
stream.write(SLIP_ESC_END);
break;
case SLIP_ESC:
stream.write(SLIP_ESC);
stream.write(SLIP_ESC_ESC);
break;
default:
stream.write(data);
}
crc16_add(data, &crc16_out);
}
/* CITT CRC16 polynomial ^16 + ^12 + ^5 + 1 */
/*---------------------------------------------------------------------------*/
void EspLink::crc16_add(uint8_t b, uint16_t *crc)
{
*crc ^= b;
*crc = (*crc >> 8) | (*crc << 8);
*crc ^= (*crc & 0xff00) << 4;
*crc ^= (*crc >> 8) >> 4;
*crc ^= (*crc & 0xff00) >> 5;
}
void EspLink::writeBuf(uint8_t * buf, uint16_t len)
{
while(len-- > 0)
writeChar(*buf++);
}
void EspLink::sendPacketStart(uint16_t cmd, uint32_t value, uint16_t argc)
{
crc16_out = 0;
stream.write( SLIP_END );
writeBuf((uint8_t*)&cmd, 2);
writeBuf((uint8_t*)&argc, 2);
writeBuf((uint8_t*)&value, 4);
}
void EspLink::sendPacketArg(uint16_t len, uint8_t * data)
{
writeBuf((uint8_t*)&len, 2);
writeBuf(data, len);
uint16_t pad = (4-((len+2)&3))&3; // get to multiple of 4
if (pad > 0) {
uint32_t temp = 0;
writeBuf((uint8_t*)&temp, pad);
}
}
void EspLink::sendPacketEnd() {
uint16_t crc = crc16_out;
writeBuf((uint8_t*)&crc, 2);
stream.write(SLIP_END);
}
void EspLink::parseSlipPacket()
{
CmdRequest req;
req.cmd = (CmdPacket *)readBuf;
req.arg_num = 0;
req.arg_ptr = readBuf + sizeof(CmdPacket);
requestCb(&req);
free(readBuf);
readBuf = NULL;
}
void EspLink::checkPacket()
{
if( readBufPtr <= 3 )
return;
uint16_t crc = 0;
for(uint16_t i=0; i < readBufPtr - 2; i++)
crc16_add(readBuf[i], &crc);
uint16_t crcpacket = *(uint16_t*)(readBuf + readBufPtr - 2);
if( crc == crcpacket )
{
readBufPtr -= 2;
parseSlipPacket();
}
}
void EspLink::readLoop()
{
if( stream.available() > 0 )
{
int byt = stream.read();
switch(readState)
{
case WAIT_FOR_SLIP_START:
if( byt == SLIP_END )
{
if(readBuf != NULL)
free(readBuf);
readBufPtr = 0;
readBufMax = READ_BUF_DFLT_SIZE;
readBuf = (uint8_t *)malloc(readBufMax);
readState = READ_SLIP_PACKAGE;
}
break;
case READ_SLIP_PACKAGE:
if( byt == SLIP_END )
{
readState = WAIT_FOR_SLIP_START;
checkPacket();
break;
}
if( byt == SLIP_ESC )
break;
if( readLastChar == SLIP_ESC && byt == SLIP_ESC_END )
byt = SLIP_END;
else if( readLastChar == SLIP_ESC && byt == SLIP_ESC_ESC )
byt = SLIP_ESC;
if( readBufPtr >= readBufMax )
{
readBufMax = readBufMax + READ_BUF_DFLT_SIZE;
readBuf = (uint8_t *)realloc(readBuf, readBufMax);
if( readBuf == NULL )
{
readState = WAIT_FOR_SLIP_START; // TODO
break;
}
}
readBuf[readBufPtr++] = byt;
break;
}
readLastChar = byt;
}
}
// Return the number of arguments given a command struct
uint32_t EspLink::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 EspLink::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
memcpy(data, req->arg_ptr + 2, length);
req->arg_ptr += (length+5)&~3; // round up to multiple of 4
req->arg_num ++;
return 0;
}
// Skip the next argument
void EspLink::cmdSkipArg(CmdRequest *req) {
uint16_t length;
if (req->arg_num >= req->cmd->argc) return;
length = *(uint16_t*)req->arg_ptr;
req->arg_ptr += (length+5)&~3;
req->arg_num ++;
}
// Return the length of the next argument
uint16_t EspLink::cmdArgLen(CmdRequest *req) {
return *(uint16_t*)req->arg_ptr;
}

@ -0,0 +1,91 @@
#ifndef ESP_LINK_H
#define ESP_LINK_H
#include <inttypes.h>
#include <Stream.h>
typedef struct __attribute__((__packed__)) {
uint16_t len; // length of data
uint8_t data[0]; // really data[len]
} CmdArg;
typedef struct __attribute__((__packed__)) {
uint16_t cmd; // command to perform, from CmdName enum
uint16_t argc; // number of arguments to command
uint32_t value; // callback pointer for response or first argument
CmdArg args[0]; // really args[argc]
} CmdPacket;
typedef struct {
CmdPacket *cmd; // command packet header
uint32_t arg_num; // number of args parsed
uint8_t *arg_ptr; // pointer to ??
} CmdRequest;
typedef void (* CmdRequestCB)(CmdRequest *);
typedef enum {
CMD_NULL = 0,
CMD_SYNC, // synchronize and clear
CMD_RESP_V, // response with a value
CMD_RESP_CB, // response with a callback
CMD_WIFI_STATUS, // get the current wifi status
CMD_CB_ADD,
CMD_CB_EVENTS,
CMD_GET_TIME, // get current time in seconds since the unix epoch
CMD_MQTT_SETUP = 10, // set-up callbacks
CMD_MQTT_PUBLISH, // publish a message
CMD_MQTT_SUBSCRIBE, // subscribe to a topic
CMD_MQTT_LWT, // set the last-will-topic and messge
CMD_REST_SETUP = 20,
CMD_REST_REQUEST,
CMD_REST_SETHEADER,
CMD_WEB_DATA = 30,
CMD_WEB_REQ_CB,
} CmdName;
typedef enum
{
WAIT_FOR_SLIP_START,
READ_SLIP_PACKAGE,
} ReadState;
class EspLink
{
private:
uint16_t crc16_out;
Stream &stream;
ReadState readState;
uint8_t * readBuf;
uint16_t readBufPtr;
uint16_t readBufMax;
int readLastChar;
CmdRequestCB requestCb;
void crc16_add(uint8_t b, uint16_t *crc);
void writeChar(uint8_t chr);
void writeBuf(uint8_t * buf, uint16_t len);
void checkPacket();
void parseSlipPacket();
public:
EspLink(Stream &stream, CmdRequestCB callback);
~EspLink();
void sendPacketStart(uint16_t cmd, uint32_t value, uint16_t argc);
void sendPacketArg(uint16_t len, uint8_t * data);
void sendPacketEnd();
void readLoop();
uint32_t cmdGetArgc(CmdRequest *req);
int32_t cmdPopArg(CmdRequest *req, void *data, uint16_t len);
void cmdSkipArg(CmdRequest *req);
uint16_t cmdArgLen(CmdRequest *req);
};
#endif /* ESP_LINK_H */

@ -0,0 +1,70 @@
#include "WebServer.h"
#include "EspLink.h"
void packetReceived(CmdRequest *req);
EspLink espLink(Serial, packetReceived);
void packetReceived(CmdRequest *req)
{
Serial.println("\nReceived\n");
uint16_t shrt, port;
espLink.cmdPopArg(req, &shrt, 2);
RequestReason reason = (RequestReason)shrt;
Serial.print("Reason: ");
Serial.println(reason);
uint8_t ip[4];
espLink.cmdPopArg(req, &ip, 4);
Serial.print("IP: ");
for(int i=0; i < 4; i++)
{
Serial.print(ip[i], DEC);
if( i != 3 )
Serial.print(".");
}
Serial.println();
espLink.cmdPopArg(req, &port, 2);
Serial.print("Port: ");
Serial.println(port);
{
uint16_t len = espLink.cmdArgLen(req);
char bf[len+1];
bf[len] = 0;
espLink.cmdPopArg(req, bf, len);
Serial.print("Url: ");
Serial.println(bf);
}
switch( reason )
{
case BUTTON:
{
uint16_t len = espLink.cmdArgLen(req);
char bf[len+1];
bf[len] = 0;
espLink.cmdPopArg(req, bf, len);
Serial.print("Button: ");
Serial.println(bf);
}
break;
}
}
void setup() {
Serial.begin(57600);
delay(10);
espLink.sendPacketStart(CMD_CB_ADD, 100, 1);
espLink.sendPacketArg(5, (uint8_t *)"webCb");
espLink.sendPacketEnd();
}
void loop() {
espLink.readLoop();
}

@ -0,0 +1,11 @@
#ifndef WEB_SERVER_H
#define WEB_SERVER_H
typedef enum {
LOAD=0,
REFRESH,
BUTTON,
SUBMIT,
} RequestReason;
#endif /* WEB_SERVER_H */

@ -504,3 +504,8 @@ serbridgeInit(int port1, int port2)
espconn_tcp_set_max_con_allow(&serbridgeConn2, MAX_CONN);
espconn_regist_time(&serbridgeConn2, SER_BRIDGE_TIMEOUT, 0);
}
int ICACHE_FLASH_ATTR serbridgeInProgramming()
{
return slip_disabled;
}

@ -36,6 +36,8 @@ void ICACHE_FLASH_ATTR serbridgeInitPins(void);
void ICACHE_FLASH_ATTR serbridgeUartCb(char *buf, short len);
void ICACHE_FLASH_ATTR serbridgeReset();
int ICACHE_FLASH_ATTR serbridgeInProgramming();
// callback when receiving UART chars when in programming mode
extern void (*programmingCB)(char *buffer, short length);

@ -1,8 +1,18 @@
#include "web-server.h"
#include <espconn.h>
#include "espfs.h"
#include "config.h"
#include "cgi.h"
#include "cmd.h"
#include "serbridge.h"
#define WEB_CB "webCb"
static char* web_server_reasons[] = {
"load", "refresh", "button", "submit"
};
char * webServerPages = NULL;
@ -76,7 +86,88 @@ void ICACHE_FLASH_ATTR webServerInit()
int ICACHE_FLASH_ATTR webServerProcessJsonQuery(HttpdConnData *connData)
{
os_printf("URL: %s\n", connData->url);
errorResponse(connData, 400, "Slip protocol is not enabled!");
if( !flashConfig.slip_enable )
{
errorResponse(connData, 400, "Slip processing is disabled!");
return HTTPD_CGI_DONE;
}
CmdCallback* cb = cmdGetCbByName( WEB_CB );
if( cb == NULL )
{
errorResponse(connData, 500, "No MCU callback is registered!");
return HTTPD_CGI_DONE;
}
if( serbridgeInProgramming() )
{
errorResponse(connData, 500, "Slip disabled at programming mode!");
return HTTPD_CGI_DONE;
}
char reasonBuf[16];
int i;
int len = httpdFindArg(connData->getArgs, "reason", reasonBuf, sizeof(reasonBuf));
if( len < 0 )
{
errorResponse(connData, 400, "No reason specified!");
return HTTPD_CGI_DONE;
}
RequestReason reason = INVALID;
for(i=0; i < sizeof(web_server_reasons)/sizeof(char *); i++)
{
if( os_strcmp( web_server_reasons[i], reasonBuf ) == 0 )
reason = (RequestReason)i;
}
if( reason == INVALID )
{
errorResponse(connData, 400, "Invalid reason!");
return HTTPD_CGI_DONE;
}
char body[1024];
int bodyLen = -1;
switch(reason)
{
case BUTTON:
bodyLen = httpdFindArg(connData->getArgs, "id", body, sizeof(body));
if( bodyLen <= 0 )
{
errorResponse(connData, 400, "No button ID specified!");
return HTTPD_CGI_DONE;
}
break;
case SUBMIT:
{
// TODO
}
break;
case LOAD:
case REFRESH:
default:
break;
}
os_printf("Web callback to MCU: %s\n", reasonBuf);
cmdResponseStart(CMD_WEB_REQ_CB, (uint32_t)cb->callback, bodyLen >= 0 ? 5 : 4);
uint16_t r = (uint16_t)reason;
cmdResponseBody(&r, sizeof(uint16_t));
cmdResponseBody(&connData->conn->proto.tcp->remote_ip, 4);
cmdResponseBody(&connData->conn->proto.tcp->remote_port, sizeof(uint16_t));
cmdResponseBody(connData->url, os_strlen(connData->url));
if( bodyLen >= 0 )
cmdResponseBody(body, bodyLen);
cmdResponseEnd();
if( reason == SUBMIT )
{
httpdStartResponse(connData, 204);
httpdEndHeaders(connData);
return HTTPD_CGI_DONE;
}
// TODO
return HTTPD_CGI_DONE;
}

@ -5,6 +5,16 @@
#include "httpd.h"
typedef enum
{
LOAD=0,
REFRESH,
BUTTON,
SUBMIT,
INVALID=-1,
} RequestReason;
void webServerInit();
char * webServerUserPages();

Loading…
Cancel
Save