finished basic d2d and external, adde flags etc

http-comm
Ondřej Hruška 7 years ago
parent 9a5bc0a274
commit 791f6e716f
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 1
      esphttpdconfig.mk.example
  2. 2
      front-end
  3. 2
      libesphttpd
  4. 4
      user/ansi_parser_callbacks.c
  5. 15
      user/api.h
  6. 137
      user/cgi_d2d.c
  7. 5
      user/cgi_d2d.h
  8. 4
      user/cgi_system.c
  9. 22
      user/routes.c
  10. 13
      user/serial.c

@ -39,6 +39,7 @@ OUTPUT_TYPE = combined
ESP_SPI_FLASH_SIZE_K = 1024 ESP_SPI_FLASH_SIZE_K = 1024
GLOBAL_CFLAGS = \ GLOBAL_CFLAGS = \
-DASYNC_LOG=1 \
-DDEBUG_D2D=0 \ -DDEBUG_D2D=0 \
-DDEBUG_ROUTER=0 \ -DDEBUG_ROUTER=0 \
-DDEBUG_CAPTDNS=0 \ -DDEBUG_CAPTDNS=0 \

@ -1 +1 @@
Subproject commit 29b813457c7a185c41e050d358b001fadd2498e4 Subproject commit 6f165da9b6237fd88efc836a663a429ed8aadb6e

@ -1 +1 @@
Subproject commit 8f4db520bce2ecdc147dd6625e05d8dda45c813a Subproject commit 348420959b919d95412daeafe5014f4255854f80

@ -11,6 +11,7 @@
#include "version.h" #include "version.h"
#include "uart_buffer.h" #include "uart_buffer.h"
#include "screen.h" #include "screen.h"
#include "uart_driver.h"
volatile bool enquiry_suppressed = false; volatile bool enquiry_suppressed = false;
ETSTimer enqTimer; ETSTimer enqTimer;
@ -26,7 +27,8 @@ void ICACHE_FLASH_ATTR enqTimerCb(void *unused)
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
apars_respond(const char *str) apars_respond(const char *str)
{ {
UART_SendAsync(str, -1); UART_WriteString(UART0, str, UART_TIMEOUT_US);
//UART_SendAsync(str, -1);
} }
/** /**

@ -0,0 +1,15 @@
//
// Created by MightyPork on 2017/10/01.
//
#ifndef ESPTERM_API_H
#define ESPTERM_API_H
// TODO use X-MACRO for access restrictions etc
#define API_D2D_MSG "/api/v1/msg"
#define API_REBOOT "/api/v1/reboot"
#define API_PING "/api/v1/ping"
#define API_CLEAR "/api/v1/clear"
#endif //ESPTERM_API_H

@ -4,39 +4,70 @@
#include <esp8266.h> #include <esp8266.h>
#include "cgi_d2d.h" #include "cgi_d2d.h"
#include "apars_logging.h"
#include "version.h" #include "version.h"
#include "ansi_parser_callbacks.h" #include "ansi_parser_callbacks.h"
#include "api.h"
#include <httpclient.h> #include <httpclient.h>
#include <esp_utils.h> #include <esp_utils.h>
#define D2D_TIMEOUT_MS 2000 #define D2D_TIMEOUT_MS 2000
#define D2D_HEADERS \ #define D2D_HEADERS \
"User-Agent: ESPTerm "FIRMWARE_VERSION"\r\n" \ "User-Agent: ESPTerm "FIRMWARE_VERSION" like curl wget HTTPie\r\n" \
"Content-Type: text/plain; charset=utf-8\r\n" \ "Content-Type: text/plain; charset=utf-8\r\n" \
"Cache-Control: max-age=0\r\n" "Accept-Encoding: identity\r\n" \
"Accept-Charset: utf-8\r\n" \
"Accept: text/*, application/json\r\n" \
"Cache-Control: no-cache,private,max-age=0\r\n"
struct d2d_request_opts { struct d2d_request_opts {
bool want_body; bool want_body;
bool want_head; bool want_head;
size_t max_result_len;
char *nonce; char *nonce;
}; };
volatile bool request_pending = false;
static void ICACHE_FLASH_ATTR
requestNoopCb(int http_status,
char *response_headers,
char *response_body,
size_t body_size,
void *userArg)
{
request_pending = false;
if (userArg != NULL) free(userArg);
}
static void ICACHE_FLASH_ATTR static void ICACHE_FLASH_ATTR
requestCb(int http_status, requestCb(int http_status,
const char *response_headers, char *response_headers,
const char *response_body, char *response_body,
size_t body_size, size_t body_size,
void *userArg) void *userArg)
{ {
if (userArg == NULL) return; if (userArg == NULL) {
request_pending = false;
return;
}
struct d2d_request_opts *opts = userArg; struct d2d_request_opts *opts = userArg;
d2d_dbg("Rx url response, code %d, nonce \"%s\"", http_status, opts->nonce?opts->nonce:"");
// ensure positive - would be hard to parse
if (http_status < 0) http_status = -http_status;
char buff100[100]; char buff100[100];
int len = 0; int len = 0;
if (opts->want_head) len += strlen(response_headers); size_t headers_size = strlen(response_headers);
if (opts->want_head) len += headers_size;
if (opts->want_body) len += body_size + (opts->want_head*2); if (opts->want_body) len += body_size + (opts->want_head*2);
if (opts->max_result_len > 0 && len > opts->max_result_len)
len = (int) opts->max_result_len;
char *bb = buff100; char *bb = buff100;
bb += sprintf(bb, "\x1b^h;%d;", http_status); bb += sprintf(bb, "\x1b^h;%d;", http_status);
const char *comma = ""; const char *comma = "";
@ -66,24 +97,35 @@ requestCb(int http_status,
apars_respond(buff100); apars_respond(buff100);
d2d_dbg("Response %d, nonce \"%s\"", http_status, opts->nonce?opts->nonce:""); //d2d_dbg("Headers (part) %100s", response_headers);
d2d_dbg("Headers %s", response_headers); //d2d_dbg("Body (part) %100s", response_body);
d2d_dbg("Body %s", response_body);
// head and payload separated by \r\n\r\n (one \r\n is at the end of head - maybe) // head and payload separated by \r\n\r\n (one \r\n is at the end of head - maybe)
if (opts->want_head) { if (opts->want_head) {
// truncate
if (headers_size > len) {
response_headers[len] = 0;
opts->want_body = false; // soz, it wouldn't fit
}
apars_respond(response_headers); apars_respond(response_headers);
if(opts->want_body) apars_respond("\r\n"); if(opts->want_body) apars_respond("\r\n");
} }
if(opts->want_body) { if(opts->want_body) {
// truncate
if (opts->want_head*(headers_size+2)+body_size > len) {
response_body[len - (opts->want_head*(headers_size+2))] = 0;
}
apars_respond(response_body); apars_respond(response_body);
} }
apars_respond("\a"); apars_respond("\a");
free(opts->nonce); free(opts->nonce);
free(userArg); free(opts);
request_pending = false;
} }
bool ICACHE_FLASH_ATTR bool ICACHE_FLASH_ATTR
@ -101,6 +143,8 @@ d2d_parse_command(char *msg)
} while(0) \ } while(0) \
if (strstarts(msg, "M;")) { if (strstarts(msg, "M;")) {
if (request_pending) return false;
// Send a esp-esp message // Send a esp-esp message
msg += 2; msg += 2;
const char *ip; const char *ip;
@ -108,7 +152,7 @@ d2d_parse_command(char *msg)
const char *payload = msg; const char *payload = msg;
d2d_dbg("D2D Tx,dest=%s,msg=%s", ip, payload); d2d_dbg("D2D Tx,dest=%s,msg=%s", ip, payload);
sprintf(buff40, "http://%s" D2D_MSG_ENDPOINT, ip); sprintf(buff40, "http://%s" API_D2D_MSG, ip);
httpclient_args args; httpclient_args args;
httpclient_args_init(&args); httpclient_args_init(&args);
@ -117,10 +161,14 @@ d2d_parse_command(char *msg)
args.headers = D2D_HEADERS; args.headers = D2D_HEADERS;
args.timeout = D2D_TIMEOUT_MS; args.timeout = D2D_TIMEOUT_MS;
args.url = buff40; // "escapes scope" warning - can ignore, strdup is used args.url = buff40; // "escapes scope" warning - can ignore, strdup is used
http_request(&args, NULL);
request_pending = true;
http_request(&args, requestNoopCb);
return true; return true;
} }
else if (strstarts(msg, "H;")) { else if (strstarts(msg, "H;")) {
if (request_pending) return false;
// Send a esp-esp message // Send a esp-esp message
msg += 2; msg += 2;
const char *method = NULL; const char *method = NULL;
@ -128,7 +176,7 @@ d2d_parse_command(char *msg)
const char *nonce = NULL; const char *nonce = NULL;
const char *url = NULL; const char *url = NULL;
const char *payload = NULL; const char *payload = NULL;
httpd_method methodNum = HTTPD_METHOD_GET; httpd_method methodNum;
FIND_NEXT(method, ';'); FIND_NEXT(method, ';');
@ -140,7 +188,8 @@ d2d_parse_command(char *msg)
else if (streq(method, "PATCH")) methodNum = HTTPD_METHOD_PATCH; else if (streq(method, "PATCH")) methodNum = HTTPD_METHOD_PATCH;
else if (streq(method, "HEAD")) methodNum = HTTPD_METHOD_HEAD; else if (streq(method, "HEAD")) methodNum = HTTPD_METHOD_HEAD;
else { else {
d2d_warn("BAD METHOD: %s, using GET", method); d2d_warn("BAD METHOD: %s", method);
return false;
} }
FIND_NEXT(params, ';'); FIND_NEXT(params, ';');
@ -148,7 +197,8 @@ d2d_parse_command(char *msg)
d2d_dbg("Method %s", method); d2d_dbg("Method %s", method);
d2d_dbg("Params %s", params); d2d_dbg("Params %s", params);
size_t max_len = HTTPCLIENT_DEF_MAX_LEN; size_t max_buf_len = HTTPCLIENT_DEF_MAX_LEN;
size_t max_result_len = 0; // 0 = no truncate
uint timeout = HTTPCLIENT_DEF_TIMEOUT_MS; uint timeout = HTTPCLIENT_DEF_TIMEOUT_MS;
bool want_body = 0; bool want_body = 0;
bool want_head = 0; bool want_head = 0;
@ -163,8 +213,10 @@ d2d_parse_command(char *msg)
if(streq(param, "H")) want_head = 1; // Return head if(streq(param, "H")) want_head = 1; // Return head
else if(streq(param, "B")) want_body = 1; // Return body else if(streq(param, "B")) want_body = 1; // Return body
else if(streq(param, "X")) no_resp = 1; // X - no response, no callback else if(streq(param, "X")) no_resp = 1; // X - no response, no callback
else if(strstarts(param, "L=")) { // max length else if(strstarts(param, "l=")) { // max buffer length
max_len = (size_t) atoi(param + 2); max_buf_len = (size_t) atoi(param + 2);
} else if(strstarts(param, "L=")) { // max length
max_result_len = (size_t) atoi(param + 2);
} else if(strstarts(param, "T=")) { // timeout } else if(strstarts(param, "T=")) { // timeout
timeout = (uint) atoi(param + 2); timeout = (uint) atoi(param + 2);
} else if(strstarts(param, "N=")) { // Nonce } else if(strstarts(param, "N=")) { // Nonce
@ -198,18 +250,20 @@ d2d_parse_command(char *msg)
args.body = payload; args.body = payload;
args.headers = D2D_HEADERS; args.headers = D2D_HEADERS;
args.timeout = timeout; args.timeout = timeout;
args.max_response_len = max_len; args.max_response_len = max_buf_len;
args.url = url; args.url = url;
if (!no_resp) { if (!no_resp) {
struct d2d_request_opts *opts = malloc(sizeof(struct d2d_request_opts)); struct d2d_request_opts *opts = malloc(sizeof(struct d2d_request_opts));
opts->want_body = want_body; opts->want_body = want_body;
opts->want_head = want_head; opts->want_head = want_head;
opts->max_result_len = max_result_len;
opts->nonce = esp_strdup(nonce); opts->nonce = esp_strdup(nonce);
args.userData = opts; args.userData = opts;
} }
http_request(&args, no_resp ? NULL : requestCb); request_pending = true;
http_request(&args, no_resp ? requestNoopCb : requestCb);
d2d_dbg("Done"); d2d_dbg("Done");
return true; return true;
@ -217,3 +271,46 @@ d2d_parse_command(char *msg)
return false; return false;
} }
httpd_cgi_state ICACHE_FLASH_ATTR cgiD2DMessage(HttpdConnData *connData)
{
if (connData->conn==NULL) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
}
size_t len = 0;
if (connData->post && connData->post->buff)
len = strlen(connData->post->buff);
else if (connData->getArgs)
len = strlen(connData->getArgs);
else
len = 0;
u8 *ip = connData->remote_ip;
char buf[20];
sprintf(buf, "\x1b^m;"IPSTR";L=%d;", ip[0], ip[1], ip[2], ip[3], (int)len);
apars_respond(buf);
if (connData->post && connData->post->buff)
apars_respond(connData->post->buff);
else if (connData->getArgs)
apars_respond(connData->getArgs);
apars_respond("\a");
d2d_dbg("D2D Rx src="IPSTR",len=%d", ip[0], ip[1], ip[2], ip[3],len);
// Received a msg
httdResponseOptions(connData, 0);
httdSetTransferMode(connData, HTTPD_TRANSFER_CLOSE);
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "text/plain");
httpdEndHeaders(connData);
httpdSend(connData, "message received\r\n", -1);
return HTTPD_CGI_DONE;
}

@ -6,6 +6,7 @@
#define ESPTERM_CGI_D2D_H #define ESPTERM_CGI_D2D_H
#include <esp8266.h> #include <esp8266.h>
#include <httpd.h>
#if DEBUG_D2D #if DEBUG_D2D
#define d2d_warn warn #define d2d_warn warn
@ -17,8 +18,8 @@
#define d2d_info(fmt, ...) #define d2d_info(fmt, ...)
#endif #endif
#define D2D_MSG_ENDPOINT "/api/v1/msg"
bool d2d_parse_command(char *msg); bool d2d_parse_command(char *msg);
httpd_cgi_state cgiD2DMessage(HttpdConnData *connData);
#endif //ESPTERM_CGI_D2D_H #endif //ESPTERM_CGI_D2D_H

@ -50,7 +50,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiResetDevice(HttpdConnData *connData)
os_timer_setfn(&tmr, tmrCb, NULL); os_timer_setfn(&tmr, tmrCb, NULL);
os_timer_arm(&tmr, 100, false); os_timer_arm(&tmr, 100, false);
httpdSend(connData, "system reset\n", -1); httpdSend(connData, "system reset\r\n", -1);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
@ -66,7 +66,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiPing(HttpdConnData *connData)
httpdHeader(connData, "Content-Type", "text/plain"); httpdHeader(connData, "Content-Type", "text/plain");
httpdEndHeaders(connData); httpdEndHeaders(connData);
httpdSend(connData, "pong\n", -1); httpdSend(connData, "pong\r\n", -1);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }

@ -14,6 +14,8 @@
#include "cgi_persist.h" #include "cgi_persist.h"
#include "syscfg.h" #include "syscfg.h"
#include "persist.h" #include "persist.h"
#include "api.h"
#include "cgi_d2d.h"
/** /**
* Password for WiFi config * Password for WiFi config
@ -45,7 +47,8 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData)
break; break;
case PWLOCK_SETTINGS_NOTERM: case PWLOCK_SETTINGS_NOTERM:
protect = strstarts(connData->url, "/cfg") && !strstarts(connData->url, "/cfg/term"); protect = strstarts(connData->url, "/cfg") &&
!strstarts(connData->url, "/cfg/term");
break; break;
case PWLOCK_SETTINGS_ALL: case PWLOCK_SETTINGS_ALL:
@ -53,7 +56,9 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData)
break; break;
case PWLOCK_MENUS: case PWLOCK_MENUS:
protect = strstarts(connData->url, "/cfg") || strstarts(connData->url, "/about") || strstarts(connData->url, "/help"); protect = strstarts(connData->url, "/cfg") ||
strstarts(connData->url, "/about") ||
strstarts(connData->url, "/help");
break; break;
default: default:
@ -64,11 +69,11 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData)
// pages outside the normal scope // pages outside the normal scope
if (sysconf->pwlock > PWLOCK_NONE) { if (sysconf->pwlock > PWLOCK_NONE) {
if (strstarts(connData->url, "/system/reset")) protect = true; if (strstarts(connData->url, "/api/v1/reboot")) protect = true;
} }
if (sysconf->pwlock > PWLOCK_SETTINGS_NOTERM) { if (sysconf->pwlock > PWLOCK_SETTINGS_NOTERM) {
if (strstarts(connData->url, "/system/cls")) protect = true; if (strstarts(connData->url, "/api/v1/clear")) protect = true;
} }
if (sysconf->access_pw[0] == 0) { if (sysconf->access_pw[0] == 0) {
@ -103,9 +108,12 @@ const HttpdBuiltInUrl routes[] ESP_CONST_DATA = {
ROUTE_WS(URL_WS_UPDATE, updateSockConnect), ROUTE_WS(URL_WS_UPDATE, updateSockConnect),
// --- System control --- // --- System control ---
ROUTE_CGI("/system/reset/?", cgiResetDevice),
ROUTE_CGI("/system/ping/?", cgiPing), // API endpoints
ROUTE_CGI("/system/cls/?", cgiResetScreen), ROUTE_CGI(API_REBOOT"/?", cgiResetDevice),
ROUTE_CGI(API_PING"/?", cgiPing),
ROUTE_CGI(API_CLEAR"/?", cgiResetScreen),
ROUTE_CGI(API_D2D_MSG"/?", cgiD2DMessage),
ROUTE_REDIRECT("/cfg/?", "/cfg/wifi"), ROUTE_REDIRECT("/cfg/?", "/cfg/wifi"),

@ -40,10 +40,10 @@ buf_pop(void *unused)
} }
} }
//LOCAL void my_putc(char c) LOCAL void my_putc(char c)
//{ {
// UART_WriteCharCRLF(UART1, (u8) c, 10); UART_WriteCharCRLF(UART1, (u8) c, 10);
//} }
/** /**
* Init the serial ports * Init the serial ports
@ -56,8 +56,11 @@ void ICACHE_FLASH_ATTR serialInitBase(void)
UART_SetStopBits(UART1, ONE_STOP_BIT); UART_SetStopBits(UART1, ONE_STOP_BIT);
UART_SetBaudrate(UART1, BIT_RATE_115200); UART_SetBaudrate(UART1, BIT_RATE_115200);
UART_SetPrintPort(UART1); UART_SetPrintPort(UART1);
#if ASYNC_LOG
os_install_putc1(buf_putc); os_install_putc1(buf_putc);
//os_install_putc1(my_putc); #else
os_install_putc1(my_putc);
#endif
UART_SetupAsyncReceiver(); UART_SetupAsyncReceiver();
// 1 ms timer // 1 ms timer

Loading…
Cancel
Save