Merge branch 'master' of https://github.com/jeelabs/esp-link into jeelabs-master

Conflicts:
	esp-link/cgi.c
	include/user_config.h
	mqtt/mqtt.h
	user/user_main.c
pull/47/head
Benjamin Runnels 9 years ago
commit 33f9ede084
  1. 6
      Makefile
  2. 39
      README.md
  3. 2
      cmd/handlers.c
  4. 87
      esp-link/cgi.c
  5. 3
      esp-link/cgi.h
  6. 111
      esp-link/cgimqtt.c
  7. 8
      esp-link/cgimqtt.h
  8. 19
      esp-link/config.c
  9. 5
      esp-link/config.h
  10. 19
      esp-link/main.c
  11. 2
      html/console.html
  12. 99
      html/mqtt.html
  13. 4
      html/style.css
  14. 80
      html/ui.js
  15. 4
      httpd/httpd.c
  16. 887
      mqtt/mqtt.c
  17. 148
      mqtt/mqtt.h
  18. 11
      mqtt/mqtt_cmd.c
  19. 1
      mqtt/mqtt_cmd.h
  20. 9
      mqtt/mqtt_msg.c
  21. 46
      mqtt/mqtt_msg.h
  22. 64
      mqtt/pktbuf.c
  23. 29
      mqtt/pktbuf.h
  24. 86
      mqtt/proto.c
  25. 21
      mqtt/proto.h
  26. 53
      mqtt/queue.c
  27. 46
      mqtt/queue.h
  28. 63
      mqtt/ringbuf.c
  29. 17
      mqtt/ringbuf.h
  30. 12
      rest/rest.c
  31. 15
      serial/serbridge.c
  32. 1
      serial/serled.h
  33. 19
      serial/slip.c
  34. 6
      serial/slip.h
  35. 2
      serial/uart.c
  36. 149
      user/user_main.c

@ -164,7 +164,7 @@ EXTRA_INCDIR =include .
EXTRA_INCDIR = include .
# libraries used in this project, mainly provided by the SDK
LIBS = c gcc hal phy pp net80211 wpa main lwip
LIBS = c gcc hal phy pp net80211 wpa main lwip # crypto ssl
# compiler flags using during compilation of source files
CFLAGS += -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
@ -373,8 +373,8 @@ release: all
$(Q) egrep -a 'esp-link [a-z0-9.]+ - 201' $(FW_BASE)/user2.bin | cut -b 1-80
$(Q) cp $(FW_BASE)/user1.bin $(FW_BASE)/user2.bin $(SDK_BASE)/bin/blank.bin \
"$(SDK_BASE)/bin/boot_v1.4(b1).bin" wiflash release/esp-link-$(BRANCH)
$(Q) tar zcf esp-link-$(BRANCH)-$(FLASH_SIZE).tgz -C release esp-link-$(BRANCH)
$(Q) echo "Release file: esp-link-$(BRANCH)-$(FLASH_SIZE).tgz"
$(Q) tar zcf esp-link-$(BRANCH).tgz -C release esp-link-$(BRANCH)
$(Q) echo "Release file: esp-link-$(BRANCH).tgz"
$(Q) rm -rf release
clean:

@ -26,6 +26,28 @@ Many thanks to https://github.com/brunnels for contributions around the espduino
For quick support and questions:
[![Chat at https://gitter.im/jeelabs/esp-link](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jeelabs/esp-link?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Esp-link uses
-------------
The simplest use of esp-link is as a transparent serial to wifi bridge. You can flash an attached
uC over wifi and you can watch the uC's serial debug output by connecting to port 23 or looking
at the uC Console web page.
The next level is to use the outbound connectivity of esp-link in the uC code. For example, the
uC can use REST requests to services like thingspeak.com to send sensor values that then get
stored and plotted by the external service.
The uC can also use REST requests to retrieve simple configuration
information or push other forms of notifications. (MQTT functionality is forthcoming.)
An additional option is to add code to esp-link to customize it and put all the communication
code into esp-link and only keep simple sensor/actuator control in the attached uC. In this
mode the attached uC sends custom commands to esp-link with sensor/acturator info and
registers a set of callbacks with esp-link that control sensors/actuators. This way, custom
commands in esp-link can receive MQTT messages, make simple callbacks into the uC to get sensor
values or change actuators, and then respond back with MQTT. The way this is architected is that
the attached uC registers callbacks at start-up such that the code in the esp doesn't need to
know which exact sensors/actuators the attached uC has, it learns thta through the initial
callback registration.
Eye Candy
---------
These screen shots show the Home page, the Wifi configuration page, the console for the
@ -237,7 +259,22 @@ The attached micro-controller can open outbound TCP connections using a simple
[serial protocol](https://gist.github.com/tve/a46c44bf1f6b42bc572e).
More info and sample code forthcoming...
Outbound HTTP REST requests
---------------------------
The V2 versions of esp-link support the espduino SLIP protocol that supports simple outbound
HTTP REST requests. The SLIP protocol consists of commands with binary arguments sent from the
attached microcontroller to the esp8266, which then performs the command and responds back.
The responses back use a callback address in the attached microcontroller code, i.e., the
command sent by the uC contains a callback address and the response from the esp8266 starts
with that callback address. This enables asynchronous communication where esp-link can notify the
uC when requests complete or when other actions happen, such as wifi connectivity status changes.
Support for MQTT is forthcoming.
You can find a demo sketch in a fork of the espduino library at
https://github.com/tve/espduino in the
[examples/demo folder](https://github.com/tve/espduino/tree/master/espduino/examples/demo).
Contact
-------
If you find problems with esp-link, please create a github issue. If you have a question, please
use the gitter link at the top of this page.
use the gitter chat link at the top of this page.

@ -94,7 +94,7 @@ cmdCallback* ICACHE_FLASH_ATTR
CMD_GetCbByName(char* name) {
char checkname[16];
os_strncpy(checkname, name, sizeof(checkname));
for (uint8_t i = 0; i < sizeof(commands); i++) {
for (uint8_t i = 0; i < MAX_CALLBACKS; i++) {
//os_printf("CMD_GetCbByName: index %d name=%s cb=%p\n", i, callbacks[i].name,
// (void *)callbacks[i].callback);
// if callback doesn't exist or it's null

@ -12,55 +12,69 @@ Some random cgi routines.
* Heavily modified and enhanced by Thorsten von Eicken in 2015
* ----------------------------------------------------------------------------
*/
#include <esp8266.h>
#include "cgi.h"
#include "espfs.h"
void ICACHE_FLASH_ATTR
jsonHeader(HttpdConnData *connData, int code) {
void noCacheHeaders(HttpdConnData *connData, int code) {
httpdStartResponse(connData, code);
httpdHeader(connData, "Cache-Control", "no-cache, no-store, must-revalidate");
httpdHeader(connData, "Pragma", "no-cache");
httpdHeader(connData, "Expires", "0");
}
void ICACHE_FLASH_ATTR
jsonHeader(HttpdConnData *connData, int code) {
noCacheHeaders(connData, code);
httpdHeader(connData, "Content-Type", "application/json");
httpdEndHeaders(connData);
}
uint8_t ICACHE_FLASH_ATTR
UTILS_StrToIP(const char* str, void *ip){
/* The count of the number of bytes processed. */
int i;
/* A pointer to the next digit to process. */
const char * start;
start = str;
for (i = 0; i < 4; i++) {
/* The digit being processed. */
char c;
/* The value of this byte. */
int n = 0;
while (1) {
c = *start;
start++;
if (c >= '0' && c <= '9') {
n *= 10;
n += c - '0';
}
/* We insist on stopping at "." if we are still parsing
the first, second, or third numbers. If we have reached
the end of the numbers, we will allow any character. */
else if ((i < 3 && c == '.') || i == 3) {
break;
}
else {
return 0;
void ICACHE_FLASH_ATTR
errorResponse(HttpdConnData *connData, int code, char *message) {
noCacheHeaders(connData, code);
httpdEndHeaders(connData);
httpdSend(connData, message, -1);
os_printf("HTTP %d error response: \"%s\"\n", code, message);
}
// look for the HTTP arg 'name' and store it at 'config' with max length 'max_len' (incl
// terminating zero), returns -1 on error, 0 if not found, 1 if found and OK
int ICACHE_FLASH_ATTR
getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) {
char buff[128];
int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff));
if (len < 0) return 0; // not found, skip
if (len >= max_len) {
os_sprintf(buff, "Value for %s too long (%d > %d allowed)", name, len, max_len-1);
errorResponse(connData, 400, buff);
return -1;
}
if (n >= 256) {
return 0;
strcpy(config, buff);
return 1;
}
((uint8_t*)ip)[i] = n;
int ICACHE_FLASH_ATTR
getBoolArg(HttpdConnData *connData, char *name, bool*config) {
char buff[64];
int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff));
if (len < 0) return 0; // not found, skip
if (strcmp(buff, "1") == 0 || strcmp(buff, "true") == 0) {
*config = true;
return 1;
}
if (strcmp(buff, "0") == 0 || strcmp(buff, "false") == 0) {
*config = false;
return 1;
}
os_sprintf(buff, "Invalid value for %s", name);
errorResponse(connData, 400, buff);
return -1;
}
#define TOKEN(x) (os_strcmp(token, x) == 0)
#if 0
@ -98,8 +112,11 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) {
httpdEndHeaders(connData);
// construct json response
os_sprintf(buff,
"{\"menu\": [\"Home\", \"/home.html\", \"Wifi\", \"/wifi/wifi.html\","
"\"\xC2\xB5" "C Console\", \"/console.html\", \"Debug log\", \"/log.html\" ],\n"
"{\"menu\": [\"Home\", \"/home.html\", "
"\"Wifi\", \"/wifi/wifi.html\","
"\"\xC2\xB5" "C Console\", \"/console.html\", "
"\"REST/MQTT\", \"/mqtt.html\","
"\"Debug log\", \"/log.html\" ],\n"
" \"version\": \"%s\" }", esp_link_version);
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;

@ -5,6 +5,9 @@
#include "httpd.h"
void jsonHeader(HttpdConnData *connData, int code);
void errorResponse(HttpdConnData *connData, int code, char *message);
int getStringArg(HttpdConnData *connData, char *name, char *config, int max_len);
int getBoolArg(HttpdConnData *connData, char *name, bool*config);
int cgiMenu(HttpdConnData *connData);
uint8_t UTILS_StrToIP(const char* str, void *ip);

@ -0,0 +1,111 @@
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
// // TCP Client settings
#include <esp8266.h>
#include "cgi.h"
#include "config.h"
#include "cgimqtt.h"
// Cgi to return MQTT settings
int ICACHE_FLASH_ATTR cgiMqttGet(HttpdConnData *connData) {
char buff[2048];
int len;
if (connData->conn==NULL) return HTTPD_CGI_DONE;
len = os_sprintf(buff, "{ "
"\"slip-enable\":%d, "
"\"mqtt-enable\":%d, "
"\"mqtt-status-enable\":%d, "
"\"mqtt-port\":%d, "
"\"mqtt-host\":\"%s\", "
"\"mqtt-client-id\":\"%s\", "
"\"mqtt-username\":\"%s\", "
"\"mqtt-password\":\"%s\", "
"\"mqtt-status-topic\":\"%s\", "
"\"mqtt-state\":\"%s\" }",
flashConfig.slip_enable, flashConfig.mqtt_enable, flashConfig.mqtt_status_enable,
flashConfig.mqtt_port, flashConfig.mqtt_hostname, flashConfig.mqtt_client,
flashConfig.mqtt_username, flashConfig.mqtt_password,
flashConfig.mqtt_status_topic, "connected");
jsonHeader(connData, 200);
httpdSend(connData, buff, len);
return HTTPD_CGI_DONE;
}
// Cgi to change choice of pin assignments
int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE;
// handle MQTT server settings
int mqtt_server = 0; // accumulator for changes/errors
mqtt_server |= getStringArg(connData, "mqtt-host",
flashConfig.mqtt_hostname, sizeof(flashConfig.mqtt_hostname));
if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getStringArg(connData, "mqtt-client-id",
flashConfig.mqtt_client, sizeof(flashConfig.mqtt_client));
if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getStringArg(connData, "mqtt-username",
flashConfig.mqtt_username, sizeof(flashConfig.mqtt_username));
if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getStringArg(connData, "mqtt-password",
flashConfig.mqtt_password, sizeof(flashConfig.mqtt_password));
if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getBoolArg(connData, "mqtt-enable",
&flashConfig.mqtt_enable);
// handle mqtt port
char buff[16];
if (httpdFindArg(connData->getArgs, "mqtt-port", buff, sizeof(buff)) > 0) {
int32_t port = atoi(buff);
if (port > 0 && port < 65536) {
flashConfig.mqtt_port = port;
mqtt_server |= 1;
} else {
errorResponse(connData, 400, "Invalid MQTT port");
return HTTPD_CGI_DONE;
}
}
// if server setting changed, we need to "make it so"
if (mqtt_server) {
os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable);
// TODO
}
// no action required if mqtt status settings change, they just get picked up at the
// next status tick
if (getBoolArg(connData, "mqtt-status-enable", &flashConfig.mqtt_status_enable) < 0)
return HTTPD_CGI_DONE;
if (getStringArg(connData, "mqtt-status-topic",
flashConfig.mqtt_status_topic, sizeof(flashConfig.mqtt_status_topic)) < 0)
return HTTPD_CGI_DONE;
// if SLIP-enable is toggled it gets picked-up immediately by the parser
int slip_update = getBoolArg(connData, "slip-enable", &flashConfig.slip_enable);
if (slip_update < 0) return HTTPD_CGI_DONE;
if (slip_update > 0) os_printf("SLIP-enable changed: %d\n", flashConfig.slip_enable);
os_printf("Saving config\n");
if (configSave()) {
httpdStartResponse(connData, 200);
httpdEndHeaders(connData);
} else {
httpdStartResponse(connData, 500);
httpdEndHeaders(connData);
httpdSend(connData, "Failed to save config", -1);
}
return HTTPD_CGI_DONE;
}
int ICACHE_FLASH_ATTR cgiMqtt(HttpdConnData *connData) {
if (connData->requestType == HTTPD_METHOD_GET) {
return cgiMqttGet(connData);
} else if (connData->requestType == HTTPD_METHOD_POST) {
return cgiMqttSet(connData);
} else {
jsonHeader(connData, 404);
return HTTPD_CGI_DONE;
}
}

@ -0,0 +1,8 @@
#ifndef CGIMQTT_H
#define CGIMQTT_H
#include "httpd.h"
int cgiMqtt(HttpdConnData *connData);
#endif

@ -5,9 +5,7 @@
#include <osapi.h>
#include "config.h"
#include "espfs.h"
// hack: this from LwIP
extern uint16_t inet_chksum(void *dataptr, uint16_t len);
#include "crc16.h"
FlashConfig flashConfig;
FlashConfig flashDefault = {
@ -20,11 +18,14 @@ FlashConfig flashDefault = {
0, // swap uart (don't by default)
1, 0, // tcp_enable, rssi_enable
"\0", // api_key
0, 0, 0, // slip_enable, mqtt_enable, mqtt_status_enable
1833, // mqtt port
"\0", "\0", "\0", "\0", "\0", // mqtt host, client, user, password, status-topic
};
typedef union {
FlashConfig fc;
uint8_t block[128];
uint8_t block[1024];
} FlashFull;
// magic number to recognize thet these are our flash settings as opposed to some random stuff
@ -63,7 +64,7 @@ bool ICACHE_FLASH_ATTR configSave(void) {
ff.fc.crc = 0;
//os_printf("cksum of: ");
//memDump(&ff, sizeof(ff));
ff.fc.crc = inet_chksum(&ff, sizeof(ff));
ff.fc.crc = crc16_data((unsigned char*)&ff, sizeof(ff), 0);
//os_printf("cksum is %04x\n", ff.fc.crc);
// write primary with incorrect seq
ff.fc.seq = 0xffffffff;
@ -121,12 +122,16 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) {
// check CRC of ff0
uint16_t crc = ff0->fc.crc;
ff0->fc.crc = 0;
bool ff0_crc_ok = inet_chksum(ff0, sizeof(FlashFull)) == crc;
bool ff0_crc_ok = crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0) == crc;
os_printf("FLASH chk=0x%04x crc=0x%04x full_sz=%d sz=%d\n",
crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0),
crc, sizeof(FlashFull), sizeof(FlashConfig));
// check CRC of ff1
crc = ff1->fc.crc;
ff1->fc.crc = 0;
bool ff1_crc_ok = inet_chksum(ff1, sizeof(FlashFull)) == crc;
bool ff1_crc_ok = crc16_data((unsigned char*)ff1, sizeof(FlashFull), 0) == crc;
// decided which we like better
if (ff0_crc_ok)

@ -16,6 +16,11 @@ typedef struct {
uint8_t swap_uart; // swap uart0 to gpio 13&15
uint8_t tcp_enable, rssi_enable; // TCP client settings
char api_key[48]; // RSSI submission API key (Grovestreams for now)
uint8_t slip_enable, mqtt_enable, // SLIP protocol, MQTT client
mqtt_status_enable; // MQTT status reporting
uint16_t mqtt_port;
char mqtt_hostname[32], mqtt_client[48], mqtt_username[32], mqtt_password[32];
char mqtt_status_topic[32];
} FlashConfig;
extern FlashConfig flashConfig;

@ -17,6 +17,7 @@
#include "cgiwifi.h"
#include "cgipins.h"
#include "cgitcp.h"
#include "cgimqtt.h"
#include "cgiflash.h"
#include "auth.h"
#include "espfs.h"
@ -29,7 +30,7 @@
#include "log.h"
#include <gpio.h>
//#define SHOW_HEAP_USE
#define SHOW_HEAP_USE
//Function that tells the authentication system what users/passwords live on the system.
//This is disabled in the default build; if you want to try it, enable the authBasic line in
@ -90,6 +91,7 @@ HttpdBuiltInUrl builtInUrls[] = {
{ "/wifi/special", cgiWiFiSpecial, NULL },
{ "/pins", cgiPins, NULL },
{ "/tcpclient", cgiTcp, NULL },
{ "/mqtt", cgiMqtt, NULL },
{ "*", cgiEspFsHook, NULL }, //Catch-all cgi function for the filesystem
{ NULL, NULL, NULL }
@ -120,16 +122,22 @@ static char *rst_codes[] = {
# define VERS_STR(V) VERS_STR_STR(V)
char* esp_link_version = VERS_STR(VERSION);
//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done.
extern void app_init(void);
// Main routine to initialize esp-link.
void user_init(void) {
uart_init(115200, 115200);
logInit(); // must come after init of uart
os_delay_us(10000L);
// get the flash config so we know how to init things
//configWipe(); // uncomment to reset the config for testing purposes
bool restoreOk = configRestore();
// init gpio pin registers
gpio_init();
gpio_output_set(0, 0, 0, (1<<15)); // some people tie it GND, gotta ensure it's disabled
// init UART
uart_init(flashConfig.baud_rate, 115200);
logInit(); // must come after init of uart
// uart_init(flashConfig.baud_rate, 115200);
// logInit(); // must come after init of uart
// say hello (leave some time to cause break in TX after boot loader's msg
os_delay_us(10000L);
os_printf("\n\n** %s\n", esp_link_version);
@ -163,6 +171,5 @@ void user_init(void) {
os_printf("** esp-link ready\n");
// call user_main init
init();
app_init();
}

@ -20,7 +20,7 @@
<script type="text/javascript">console_url = "/console/text"</script>
<script src="console.js"></script>
<script type="text/javascript">
var rates = [57600, 115200, 230400, 460800];
var rates = [9600, 57600, 115200, 250000];
onLoad(function() {
fetchText(100, true);

@ -0,0 +1,99 @@
<div id="main">
<div class="header">
<h1>REST &amp; MQTT</h1>
</div>
<div class="content">
<div class="pure-g">
<div class="pure-u-1"><div class="card">
<p>The REST &amp; MQTT support uses the SLIP protocol over the serial port to enable
the attached microcontroller to initiate outbound connections.
The REST support lets the uC initiate simple HTTP requests while the MQTT support
lets it communicate with an MQTT server bidirectionally at QoS 0 thru 2.</p>
<p>The MQTT support is in the form of a built-in client that connects to a server
using parameters set below and stored in esp-link's flash settings. This allows
esp-link to take care of connection parameters and disconnect/reconnect operations.</p>
<p>The MQTT client also supports sending periodic status messages about esp-link itself,
including Wifi RSSI, and free heap memory.</p>
<div class="form-horizontal">
<input type="checkbox" name="slip-enable"/>
<label>Enable SLIP on serial port</label>
</div>
</div></div>
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>MQTT
<div id="mqtt-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="mqtt-form" class="pure-form" hidden>
<div class="form-horizontal">
<input type="checkbox" name="mqtt-enable"/>
<label>Enable MQTT client</label>
</div>
<div class="form-horizontal">
<label>MQTT client state: </label>
<b id="mqtt-state"></b>
</div>
<br>
<legend>MQTT server settings</legend>
<div class="pure-form-stacked">
<label>Server hostname/ip</label>
<input type="text" name="mqtt-host"/>
<label>Server port/ip</label>
<input type="text" name="mqtt-port"/>
<label>Client ID</label>
<input type="text" name="mqtt-client-id"/>
<label>Username</label>
<input type="text" name="mqtt-username"/>
<label>Password</label>
<input type="password" name="mqtt-password"/>
</div>
<button id="mqtt-button" type="submit" class="pure-button button-primary">
Update server settings!
</button>
</form>
</div>
</div>
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>Status reporting
<div id="mqtt-status-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="mqtt-status-form" class="pure-form" hidden>
<div class="form-horizontal">
<input type="checkbox" name="mqtt-status-enable"/>
<label>Enable status reporting via MQTT</label>
</div>
<br>
<legend>Status reporting settings</legend>
<div class="pure-form-stacked">
<label>Topic prefix</label>
<input type="text" name="mqtt-status-topic"/>
Suffixes: rssi, heap-free, ...
</div>
<button id="mqtt-status-button" type="submit" class="pure-button button-primary">
Update status settings!
</button>
</form>
</div>
<div class="card">
<h1>REST</h1>
<p>REST requests are enabled as soon as SLIP is enabled.
There are no REST-specific settings.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
onLoad(function() {
fetchMqtt();
bnd($("#mqtt-form"), "submit", changeMqtt);
bnd($("#mqtt-status-form"), "submit", changeMqttStatus);
});
</script>
</body></html>

@ -3,6 +3,10 @@ html, button, input, select, textarea, .pure-g [class *= "pure-u"] {
font-family: sans-serif;
}
input[type="text"], input[type="password"] {
width: 100%;
}
body {
color: #777;
}

@ -374,11 +374,11 @@ function changeTcpClient(e) {
addClass(cb, 'pure-button-disabled');
ajaxSpin("POST", url, function(resp) {
removeClass(cb, 'pure-button-disabled');
getWifiInfo();
fetchTcpClient();
}, function(s, st) {
showWarning("Error: "+st);
removeClass(cb, 'pure-button-disabled');
getWifiInfo();
fetchTcpClient();
});
}
@ -394,4 +394,80 @@ function fetchTcpClient() {
});
}
//===== MQTT cards
function changeMqtt(e) {
e.preventDefault();
var url = "mqtt?1=1";
var i, inputs = document.querySelectorAll('#mqtt-form input');
for (i=0; i<inputs.length; i++) {
if (inputs[i].type != "checkbox")
url += "&" + inputs[i].name + "=" + inputs[i].value;
};
hideWarning();
var cb = $("#mqtt-button");
addClass(cb, 'pure-button-disabled');
ajaxSpin("POST", url, function(resp) {
showNotification("MQTT updated");
removeClass(cb, 'pure-button-disabled');
}, function(s, st) {
showWarning("Error: "+st);
removeClass(cb, 'pure-button-disabled');
window.setTimeout(fetchMqtt, 100);
});
}
function displayMqtt(data) {
Object.keys(data).forEach(function(v) {
el = $("#" + v);
if (el != null) {
if (el.nodeName === "INPUT") el.value = data[v];
else el.innerHTML = data[v];
return;
}
el = document.querySelector('input[name="' + v + '"]');
if (el != null) {
if (el.type == "checkbox") el.checked = data[v] > 0;
else el.value = data[v];
}
});
$("#mqtt-spinner").setAttribute("hidden", "");
$("#mqtt-status-spinner").setAttribute("hidden", "");
$("#mqtt-form").removeAttribute("hidden");
$("#mqtt-status-form").removeAttribute("hidden");
var i, inputs = $("input");
for (i=0; i<inputs.length; i++) {
if (inputs[i].type == "checkbox")
inputs[i].onclick = function() { console.log(this); setMqtt(this.name, this.checked) };
}
}
function fetchMqtt() {
ajaxJson("GET", "/mqtt", displayMqtt, function() {
window.setTimeout(fetchMqtt, 1000);
});
}
function changeMqttStatus(e) {
e.preventDefault();
var v = document.querySelector('input[name="mqtt-status-topic"]').value;
ajaxSpin("POST", "/mqtt?mqtt-status-topic=" + v, function() {
showNotification("MQTT status settings updated");
}, function(s, st) {
showWarning("Error: "+st);
window.setTimeout(fetchMqtt, 100);
});
}
function setMqtt(name, v) {
ajaxSpin("POST", "/mqtt?" + name + "=" + (v ? 1 : 0), function() {
var n = name.replace("-enable", "");
showNotification(n + " is now " + (v ? "enabled" : "disabled"));
}, function() {
showWarning("Enable/disable failed");
window.setTimeout(fetchMqtt, 100);
});
}

@ -191,7 +191,7 @@ int ICACHE_FLASH_ATTR httpdFindArg(char *line, char *arg, char *buff, int buffLe
p=(char*)os_strstr(p, "&");
if (p!=NULL) p+=1;
}
os_printf("Finding %s in %s: Not found :/\n", arg, line);
//os_printf("Finding %s in %s: Not found :/\n", arg, line);
return -1; //not found
}
@ -521,7 +521,7 @@ static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) {
}
// Callback indicating a failure in the connection. "Recon" is probably intended in the sense
// of "you need to reconnect". Sigh... Note that there is no DiconCb after ReconCb
// of "you need to reconnect". Sigh... Note that there is no DisconCb after ReconCb
static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) {
debugConn(arg, "httpdReconCb");
HttpdConnData *conn = httpdFindConnData(arg);

File diff suppressed because it is too large Load Diff

@ -27,71 +27,57 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef USER_AT_MQTT_H_
#define USER_AT_MQTT_H_
#ifndef MQTT_H_
#define MQTT_H_
#include <esp8266.h>
#include "mqtt_msg.h"
#include "queue.h"
#include "pktbuf.h"
typedef struct mqtt_event_data_t {
uint8_t type;
const char* topic;
const char* data;
uint16_t topic_length;
uint16_t data_length;
uint16_t data_offset;
} mqtt_event_data_t;
typedef struct mqtt_state_t {
uint16_t port;
int auto_reconnect;
mqtt_connect_info_t* connect_info;
uint8_t* in_buffer;
uint8_t* out_buffer;
int in_buffer_length;
int out_buffer_length;
uint16_t message_length;
uint16_t message_length_read;
mqtt_message_t* outbound_message;
mqtt_connection_t mqtt_connection;
uint16_t pending_msg_id;
int pending_msg_type;
int pending_publish_qos;
} mqtt_state_t;
// in rest.c
uint8_t UTILS_StrToIP(const char* str, void *ip);
// State of MQTT connection
typedef enum {
WIFI_INIT,
WIFI_CONNECTING,
WIFI_CONNECTING_ERROR,
WIFI_CONNECTED,
DNS_RESOLVE,
TCP_DISCONNECTED,
TCP_RECONNECT_REQ,
TCP_RECONNECT,
TCP_CONNECTING,
TCP_CONNECTING_ERROR,
TCP_CONNECTED,
MQTT_CONNECT_SEND,
MQTT_CONNECT_SENDING,
MQTT_SUBSCIBE_SEND,
MQTT_SUBSCIBE_SENDING,
MQTT_DATA,
MQTT_PUBLISH_RECV,
MQTT_PUBLISHING
MQTT_DISCONNECTED, // we're in disconnected state
TCP_RECONNECT_REQ, // connect failed, needs reconnecting
TCP_CONNECTING, // in TCP connection process
MQTT_CONNECTED, // conneted (or connecting)
} tConnState;
// Simple notification callback
typedef void (*MqttCallback)(uint32_t* args);
typedef void (*MqttDataCallback)(uint32_t* args, const char* topic, uint32_t topic_len, const char* data, uint32_t lengh);
// Callback with data messge
typedef void (*MqttDataCallback)(uint32_t* args, const char* topic, uint32_t topic_len,
const char* data, uint32_t data_len);
// MQTTY client data structure
typedef struct {
struct espconn* pCon;
uint8_t security;
char* host;
uint32_t port;
ip_addr_t ip;
mqtt_state_t mqtt_state;
mqtt_connect_info_t connect_info;
struct espconn* pCon; // socket
// connection information
char* host; // MQTT server
uint16_t port;
uint8_t security; // 0=tcp, 1=ssl
ip_addr_t ip; // MQTT server IP address
mqtt_connect_info_t connect_info; // info to connect/reconnect
// protocol state and message assembly
tConnState connState; // connection state
bool sending; // espconn_send is pending
mqtt_connection_t mqtt_connection; // message assembly descriptor
PktBuf* msgQueue; // queued outbound messages
// TCP input buffer
uint8_t* in_buffer;
int in_buffer_size; // length allocated
int in_buffer_filled; // number of bytes held
// outstanding message when we expect an ACK
PktBuf* pending_buffer; // buffer sent and awaiting ACK
PktBuf* sending_buffer; // buffer sent not awaiting ACK
// timer and associated timeout counters
ETSTimer mqttTimer; // timer for this connection
uint8_t keepAliveTick; // seconds 'til keep-alive is required (0=no k-a)
uint8_t keepAliveAckTick; // seconds 'til keep-alive ack is overdue (0=no k-a)
uint8_t timeoutTick; // seconds 'til other timeout
uint8_t sendTimeout; // value of send timeout setting
// callbacks
MqttCallback connectedCb;
MqttCallback cmdConnectedCb;
MqttCallback disconnectedCb;
@ -102,42 +88,40 @@ typedef struct {
MqttCallback cmdPublishedCb;
MqttDataCallback dataCb;
MqttDataCallback cmdDataCb;
ETSTimer mqttTimer;
uint32_t keepAliveTick;
uint32_t reconnectTick;
uint32_t sendTimeout;
tConnState connState;
QUEUE msgQueue;
// misc
void* user_data;
} MQTT_Client;
#define SEC_NONSSL 0
#define SEC_SSL 1
// Initialize client data structure
void MQTT_Init(MQTT_Client* mqttClient, char* host, uint32 port,
uint8_t security, uint8_t sendTimeout,
char* client_id, char* client_user, char* client_pass,
uint8_t keepAliveTime, uint8_t cleanSession);
// Set Last Will Topic on client, must be called before MQTT_InitConnection
void MQTT_InitLWT(MQTT_Client* mqttClient, char* will_topic, char* will_msg,
uint8_t will_qos, uint8_t will_retain);
// Kick of a persistent connection to the broker, will reconnect anytime conn breaks
void MQTT_Connect(MQTT_Client* mqttClient);
// Kill persistent connection
void MQTT_Disconnect(MQTT_Client* mqttClient);
#define MQTT_FLAG_CONNECTED 1
#define MQTT_FLAG_READY 2
#define MQTT_FLAG_EXIT 4
// Subscribe to a topic
bool MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos);
#define MQTT_EVENT_TYPE_NONE 0
#define MQTT_EVENT_TYPE_CONNECTED 1
#define MQTT_EVENT_TYPE_DISCONNECTED 2
#define MQTT_EVENT_TYPE_SUBSCRIBED 3
#define MQTT_EVENT_TYPE_UNSUBSCRIBED 4
#define MQTT_EVENT_TYPE_PUBLISH 5
#define MQTT_EVENT_TYPE_PUBLISHED 6
#define MQTT_EVENT_TYPE_EXITED 7
#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8
// Publish a message
bool MQTT_Publish(MQTT_Client* client, const char* topic, const char* data,
uint8_t qos, uint8_t retain);
void MQTT_InitConnection(MQTT_Client* mqttClient, char* host, uint32 port, uint8_t security);
void MQTT_InitClient(MQTT_Client* mqttClient, char* client_id, char* client_user, char* client_pass, uint8_t keepAliveTime, uint8_t cleanSession);
void MQTT_InitLWT(MQTT_Client* mqttClient, char* will_topic, char* will_msg, uint8_t will_qos, uint8_t will_retain);
// Callback when connected
void MQTT_OnConnected(MQTT_Client* mqttClient, MqttCallback connectedCb);
// Callback when disconnected
void MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb);
// Callback when publish succeeded
void MQTT_OnPublished(MQTT_Client* mqttClient, MqttCallback publishedCb);
// Callback when data arrives for subscription
void MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb);
bool MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos);
void MQTT_Connect(MQTT_Client* mqttClient);
void MQTT_Disconnect(MQTT_Client* mqttClient);
bool MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t qos, uint8_t retain);
#endif /* USER_AT_MQTT_H_ */

@ -1,3 +1,5 @@
#include <esp8266.h>
#include "mqtt.h"
#include "mqtt_cmd.h"
uint32_t connectedCb = 0, disconnectCb = 0, tcpDisconnectedCb = 0, publishedCb = 0, dataCb = 0;
@ -65,10 +67,12 @@ MQTTCMD_Setup(CmdPacket *cmd) {
// create mqtt client
uint8_t clientLen = sizeof(MQTT_Client);
MQTT_Client* client = (MQTT_Client*)os_zalloc(clientLen);
if (client == NULL)
return 0;
if (client == NULL) return 0;
os_memset(client, 0, clientLen);
return 0;
#if 0
uint16_t len;
uint8_t *client_id, *user_data, *pass_data;
uint32_t keepalive, clean_session, cb_data;
@ -136,6 +140,7 @@ MQTTCMD_Setup(CmdPacket *cmd) {
os_free(pass_data);
return (uint32_t)client;
#endif
}
uint32_t ICACHE_FLASH_ATTR
@ -217,7 +222,7 @@ MQTTCMD_Connect(CmdPacket *cmd) {
// get security
CMD_PopArg(&req, (uint8_t*)&client->security, 4);
os_printf("MQTT: MQTTCMD_Connect host=%s, port=%ld, security=%d\n",
os_printf("MQTT: MQTTCMD_Connect host=%s, port=%d, security=%d\n",
client->host,
client->port,
client->security);

@ -2,7 +2,6 @@
#define MODULES_MQTT_CMD_H_
#include "cmd.h"
#include "mqtt.h"
typedef struct {
uint32_t connectedCb;

@ -29,6 +29,7 @@
*
*/
#include <esp8266.h>
#include "mqtt_msg.h"
#define MQTT_MAX_FIXED_HEADER_SIZE 3
@ -129,7 +130,7 @@ mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_le
}
int ICACHE_FLASH_ATTR
mqtt_get_total_length(uint8_t* buffer, uint16_t length) {
mqtt_get_total_length(const uint8_t* buffer, uint16_t length) {
int i;
int totlen = 0;
@ -146,7 +147,7 @@ mqtt_get_total_length(uint8_t* buffer, uint16_t length) {
}
const char* ICACHE_FLASH_ATTR
mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) {
mqtt_get_publish_topic(const uint8_t* buffer, uint16_t* length) {
int i;
int totlen = 0;
int topiclen;
@ -173,7 +174,7 @@ mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) {
}
const char* ICACHE_FLASH_ATTR
mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) {
mqtt_get_publish_data(const uint8_t* buffer, uint16_t* length) {
int i;
int totlen = 0;
int topiclen;
@ -215,7 +216,7 @@ mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) {
}
uint16_t ICACHE_FLASH_ATTR
mqtt_get_id(uint8_t* buffer, uint16_t length) {
mqtt_get_id(const uint8_t* buffer, uint16_t length) {
if (length < 1)
return 0;

@ -31,7 +31,8 @@
#ifndef MQTT_MSG_H
#define MQTT_MSG_H
#include <esp8266.h>
#define PROTOCOL_NAMEv311
enum mqtt_message_type {
MQTT_MSG_TYPE_CONNECT = 1,
@ -50,21 +51,22 @@ enum mqtt_message_type {
MQTT_MSG_TYPE_DISCONNECT = 14
};
// Descriptor for a serialized MQTT message, this is returned by functions that compose a message
// (It's really an MQTT packet in v3.1.1 terminology)
typedef struct mqtt_message {
uint8_t* data;
uint16_t length;
} mqtt_message_t;
// Descriptor for a connection with message assembly storage
typedef struct mqtt_connection {
mqtt_message_t message;
uint16_t message_id;
uint8_t* buffer;
uint16_t buffer_length;
mqtt_message_t message; // resulting message
uint16_t message_id; // id of assembled message and memo to calculate next message id
uint8_t* buffer; // buffer for assembling messages
uint16_t buffer_length; // buffer length
} mqtt_connection_t;
// Descriptor for a connect request
typedef struct mqtt_connect_info {
char* client_id;
char* username;
@ -75,32 +77,40 @@ typedef struct mqtt_connect_info {
uint8_t will_qos;
uint8_t will_retain;
uint8_t clean_session;
} mqtt_connect_info_t;
static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) {
static inline int ICACHE_FLASH_ATTR mqtt_get_type(const uint8_t* buffer) {
return (buffer[0] & 0xf0) >> 4;
}
static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) {
static inline int ICACHE_FLASH_ATTR mqtt_get_dup(const uint8_t* buffer) {
return (buffer[0] & 0x08) >> 3;
}
static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) {
static inline int ICACHE_FLASH_ATTR mqtt_get_qos(const uint8_t* buffer) {
return (buffer[0] & 0x06) >> 1;
}
static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) {
static inline int ICACHE_FLASH_ATTR mqtt_get_retain(const uint8_t* buffer) {
return (buffer[0] & 0x01);
}
// Init a connection descriptor
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length);
// Returns the total length of a message including MQTT fixed header
int mqtt_get_total_length(const uint8_t* buffer, uint16_t length);
// Return pointer to topic, length in in/out param: in=length of buffer, out=length of topic
const char* mqtt_get_publish_topic(const uint8_t* buffer, uint16_t* length);
// Return pointer to data, length in in/out param: in=length of buffer, out=length of data
const char* mqtt_get_publish_data(const uint8_t* buffer, uint16_t* length);
// Return message id
uint16_t mqtt_get_id(const uint8_t* buffer, uint16_t length);
// The following functions construct an outgoing message
mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);

@ -0,0 +1,64 @@
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
#include <esp8266.h>
#include "pktbuf.h"
void ICACHE_FLASH_ATTR
PktBuf_Print(PktBuf *buf) {
os_printf("PktBuf:");
for (int i=-16; i<0; i++)
os_printf(" %02X", ((uint8_t*)buf)[i]);
os_printf(" %p", buf);
for (int i=0; i<16; i++)
os_printf(" %02X", ((uint8_t*)buf)[i]);
os_printf("\n");
os_printf("PktBuf: next=%p len=0x%04x\n",
((void**)buf)[-4], ((uint16_t*)buf)[-6]);
}
PktBuf * ICACHE_FLASH_ATTR
PktBuf_New(uint16_t length) {
PktBuf *buf = os_zalloc(length+sizeof(PktBuf));
buf->next = NULL;
buf->filled = 0;
//os_printf("PktBuf_New: %p l=%d->%d d=%p\n",
// buf, length, length+sizeof(PktBuf), buf->data);
return buf;
}
PktBuf * ICACHE_FLASH_ATTR
PktBuf_Push(PktBuf *headBuf, PktBuf *buf) {
if (headBuf == NULL) {
//os_printf("PktBuf_Push: %p\n", buf);
return buf;
}
PktBuf *h = headBuf;
while (h->next != NULL) h = h->next;
h->next = buf;
//os_printf("PktBuf_Push: %p->..->%p\n", headBuf, buf);
return headBuf;
}
PktBuf * ICACHE_FLASH_ATTR
PktBuf_Unshift(PktBuf *headBuf, PktBuf *buf) {
buf->next = headBuf;
//os_printf("PktBuf_Unshift: %p->%p\n", buf, buf->next);
return buf;
}
PktBuf * ICACHE_FLASH_ATTR
PktBuf_Shift(PktBuf *headBuf) {
PktBuf *buf = headBuf->next;
headBuf->next = NULL;
//os_printf("PktBuf_Shift: (%p)->%p\n", headBuf, buf);
return buf;
}
PktBuf * ICACHE_FLASH_ATTR
PktBuf_ShiftFree(PktBuf *headBuf) {
PktBuf *buf = headBuf->next;
//os_printf("PktBuf_ShiftFree: (%p)->%p\n", headBuf, buf);
os_free(headBuf);
return buf;
}

@ -0,0 +1,29 @@
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
#ifndef PKTBUF_H
#define PKTBUF_H
typedef struct PktBuf {
struct PktBuf *next; // next buffer in chain
uint16_t filled; // number of bytes filled in buffer
uint8_t data[0]; // data in buffer
} PktBuf;
// Allocate a new packet buffer of given length
PktBuf *PktBuf_New(uint16_t length);
// Append a buffer to the end of a packet buffer queue, returns new head
PktBuf *PktBuf_Push(PktBuf *headBuf, PktBuf *buf);
// Prepend a buffer to the beginning of a packet buffer queue, return new head
PktBuf * PktBuf_Unshift(PktBuf *headBuf, PktBuf *buf);
// Shift first buffer off queue, returns new head (not shifted buffer!)
PktBuf *PktBuf_Shift(PktBuf *headBuf);
// Shift first buffer off queue, free it, return new head
PktBuf *PktBuf_ShiftFree(PktBuf *headBuf);
void PktBuf_Print(PktBuf *buf);
#endif

@ -1,86 +0,0 @@
#include "proto.h"
int8_t ICACHE_FLASH_ATTR
PROTO_Init(PROTO_PARSER* parser, PROTO_PARSE_CALLBACK* completeCallback, uint8_t* buf, uint16_t bufSize) {
parser->buf = buf;
parser->bufSize = bufSize;
parser->dataLen = 0;
parser->callback = completeCallback;
parser->isEsc = 0;
return 0;
}
int8_t ICACHE_FLASH_ATTR
PROTO_ParseByte(PROTO_PARSER* parser, uint8_t value) {
switch (value) {
case 0x7D:
parser->isEsc = 1;
break;
case 0x7E:
parser->dataLen = 0;
parser->isEsc = 0;
parser->isBegin = 1;
break;
case 0x7F:
if (parser->callback != NULL)
parser->callback();
parser->isBegin = 0;
return 0;
break;
default:
if (parser->isBegin == 0) break;
if (parser->isEsc) {
value ^= 0x20;
parser->isEsc = 0;
}
if (parser->dataLen < parser->bufSize)
parser->buf[parser->dataLen++] = value;
break;
}
return -1;
}
int16_t ICACHE_FLASH_ATTR
PROTO_ParseRb(RINGBUF* rb, uint8_t* bufOut, uint16_t* len, uint16_t maxBufLen) {
uint8_t c;
PROTO_PARSER proto;
PROTO_Init(&proto, NULL, bufOut, maxBufLen);
while (RINGBUF_Get(rb, &c) == 0) {
if (PROTO_ParseByte(&proto, c) == 0) {
*len = proto.dataLen;
return 0;
}
}
return -1;
}
int16_t ICACHE_FLASH_ATTR
PROTO_AddRb(RINGBUF* rb, const uint8_t* packet, int16_t len) {
uint16_t i = 2;
if (RINGBUF_Put(rb, 0x7E) == -1) return -1;
while (len--) {
switch (*packet) {
case 0x7D:
case 0x7E:
case 0x7F:
if (RINGBUF_Put(rb, 0x7D) == -1) return -1;
if (RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1;
i += 2;
break;
default:
if (RINGBUF_Put(rb, *packet++) == -1) return -1;
i++;
break;
}
}
if (RINGBUF_Put(rb, 0x7F) == -1) return -1;
return i;
}

@ -1,21 +0,0 @@
#ifndef _PROTO_H_
#define _PROTO_H_
#include <esp8266.h>
#include "ringbuf.h"
typedef void (PROTO_PARSE_CALLBACK)();
typedef struct {
uint8_t* buf;
uint16_t bufSize;
uint16_t dataLen;
uint8_t isEsc;
uint8_t isBegin;
PROTO_PARSE_CALLBACK* callback;
} PROTO_PARSER;
int8_t PROTO_Init(PROTO_PARSER* parser, PROTO_PARSE_CALLBACK* completeCallback, uint8_t* buf, uint16_t bufSize);
int16_t PROTO_AddRb(RINGBUF* rb, const uint8_t* packet, int16_t len);
int8_t PROTO_ParseByte(PROTO_PARSER* parser, uint8_t value);
int16_t PROTO_ParseRb(RINGBUF* rb, uint8_t* bufOut, uint16_t* len, uint16_t maxBufLen);
#endif

@ -1,53 +0,0 @@
/* str_queue.c
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "queue.h"
void ICACHE_FLASH_ATTR
QUEUE_Init(QUEUE* queue, int bufferSize) {
queue->buf = (uint8_t*)os_zalloc(bufferSize);
RINGBUF_Init(&queue->rb, queue->buf, bufferSize);
}
int32_t ICACHE_FLASH_ATTR
QUEUE_Puts(QUEUE* queue, uint8_t* buffer, uint16_t len) {
return PROTO_AddRb(&queue->rb, buffer, len);
}
int32_t ICACHE_FLASH_ATTR
QUEUE_Gets(QUEUE* queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen) {
return PROTO_ParseRb(&queue->rb, buffer, len, maxLen);
}
bool ICACHE_FLASH_ATTR
QUEUE_IsEmpty(QUEUE* queue) {
if (queue->rb.fill_cnt <= 0)
return TRUE;
return FALSE;
}

@ -1,46 +0,0 @@
/* str_queue.h --
*
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef USER_QUEUE_H_
#define USER_QUEUE_H_
#include <esp8266.h>
#include "proto.h"
#include "ringbuf.h"
typedef struct {
uint8_t* buf;
RINGBUF rb;
} QUEUE;
void QUEUE_Init(QUEUE* queue, int bufferSize);
int32_t QUEUE_Puts(QUEUE* queue, uint8_t* buffer, uint16_t len);
int32_t QUEUE_Gets(QUEUE* queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen);
bool QUEUE_IsEmpty(QUEUE* queue);
#endif /* USER_QUEUE_H_ */

@ -1,63 +0,0 @@
#include "ringbuf.h"
/**
* \brief init a RINGBUF object
* \param r pointer to a RINGBUF object
* \param buf pointer to a byte array
* \param size size of buf
* \return 0 if successfull, otherwise failed
*/
int16_t ICACHE_FLASH_ATTR
RINGBUF_Init(RINGBUF* r, uint8_t* buf, int32_t size) {
if (r == NULL || buf == NULL || size < 2) return -1;
r->p_o = r->p_r = r->p_w = buf;
r->fill_cnt = 0;
r->size = size;
return 0;
}
/**
* \brief put a character into ring buffer
* \param r pointer to a ringbuf object
* \param c character to be put
* \return 0 if successfull, otherwise failed
*/
int16_t ICACHE_FLASH_ATTR
RINGBUF_Put(RINGBUF* r, uint8_t c) {
if (r->fill_cnt >= r->size)return -1; // ring buffer is full, this should be atomic operation
r->fill_cnt++; // increase filled slots count, this should be atomic operation
*r->p_w++ = c; // put character into buffer
if (r->p_w >= r->p_o + r->size) // rollback if write pointer go pass
r->p_w = r->p_o; // the physical boundary
return 0;
}
/**
* \brief get a character from ring buffer
* \param r pointer to a ringbuf object
* \param c read character
* \return 0 if successfull, otherwise failed
*/
int16_t ICACHE_FLASH_ATTR
RINGBUF_Get(RINGBUF* r, uint8_t* c) {
if (r->fill_cnt <= 0)return -1; // ring buffer is empty, this should be atomic operation
r->fill_cnt--; // decrease filled slots count
*c = *r->p_r++; // get the character out
if (r->p_r >= r->p_o + r->size) // rollback if write pointer go pass
r->p_r = r->p_o; // the physical boundary
return 0;
}

@ -1,17 +0,0 @@
#ifndef _RING_BUF_H_
#define _RING_BUF_H_
#include <esp8266.h>
typedef struct {
uint8_t* p_o; /**< Original pointer */
uint8_t* volatile p_r; /**< Read pointer */
uint8_t* volatile p_w; /**< Write pointer */
volatile int32_t fill_cnt; /**< Number of filled slots */
int32_t size; /**< Buffer size */
} RINGBUF;
int16_t RINGBUF_Init(RINGBUF* r, uint8_t* buf, int32_t size);
int16_t RINGBUF_Put(RINGBUF* r, uint8_t c);
int16_t RINGBUF_Get(RINGBUF* r, uint8_t* c);
#endif

@ -154,12 +154,12 @@ rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) {
if(client->ip.addr == 0 && ipaddr->addr != 0) {
os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
//if(client->security){
// espconn_secure_connect(client->pCon);
//}
//else {
#ifdef CLIENT_SSL_ENABLE
if(client->security) {
espconn_secure_connect(client->pCon);
} else
#endif
espconn_connect(client->pCon);
//}
os_printf("REST: connecting...\n");
}
}
@ -368,6 +368,8 @@ REST_Request(CmdPacket *cmd) {
}
os_printf("\n");
//os_printf("REST request: %s", (char*)client->data);
os_printf("REST: pCon state=%d\n", client->pCon->state);
client->pCon->state = ESPCONN_NONE;
espconn_regist_connectcb(client->pCon, tcpclient_connect_cb);

@ -14,6 +14,7 @@
#include "serled.h"
#include "config.h"
#include "console.h"
#include "slip.h"
#include "cmd.h"
static struct espconn serbridgeConn;
@ -258,6 +259,19 @@ console_process(char *buf, short len) {
}
}
// callback with a buffer of characters that have arrived on the uart
void ICACHE_FLASH_ATTR
serbridgeUartCb(char *buf, short length) {
if (!flashConfig.slip_enable || slip_disabled > 0) {
//os_printf("SLIP: disabled got %d\n", length);
console_process(buf, length);
} else {
slip_parse_buf(buf, length);
}
serledFlash(50); // short blink on serial LED
}
//callback after the data are sent
static void ICACHE_FLASH_ATTR
serbridgeSentCb(void *arg) {
@ -273,6 +287,7 @@ serbridgeSentCb(void *arg) {
// Error callback (it's really poorly named, it's not a "connection reconnected" callback,
// it's really a "connection broken, please reconnect" callback)
// Note that there is no DisconCb after a ReconCb
static void ICACHE_FLASH_ATTR serbridgeReconCb(void *arg, sint8 err) {
serbridgeConnData *sbConn = serbridgeFindConnData(arg);
if (sbConn == NULL) return;

@ -6,4 +6,3 @@ void serledInit(void);
void makeGpio(uint8_t pin);
#endif

@ -4,11 +4,10 @@
#include "uart.h"
#include "crc16.h"
#include "serbridge.h"
#include "serled.h"
#include "console.h"
#include "cmd.h"
uint8_t slip_disabled; // disable slip to allow flashing of attached MCU
uint8_t slip_disabled; // temporarily disable slip to allow flashing of attached MCU
extern void ICACHE_FLASH_ATTR console_process(char *buf, short len);
@ -115,18 +114,7 @@ slip_parse_char(char c) {
// callback with a buffer of characters that have arrived on the uart
void ICACHE_FLASH_ATTR
serbridgeUartCb(char *buf, short length) {
if (slip_disabled > 0) {
//os_printf("SLIP: disabled got %d\n", length);
console_process(buf, length);
for (short i=0; i<length; i++)
if (buf[i] == SLIP_START) {
os_printf("SLIP: START while disabled=%d\n", slip_disabled);
break;
}
return;
}
slip_parse_buf(char *buf, short length) {
// do SLIP parsing
for (short i=0; i<length; i++)
slip_parse_char(buf[i]);
@ -136,6 +124,5 @@ serbridgeUartCb(char *buf, short length) {
slip_process();
slip_reset();
}
serledFlash(50); // short blink on serial LED
}

@ -0,0 +1,6 @@
#ifndef SLIP_H
#define SLIP_H
void slip_parse_buf(char *buf, short length);
#endif

@ -23,7 +23,7 @@
#include "user_interface.h"
#include "uart.h"
#define recvTaskPrio 0
#define recvTaskPrio 1
#define recvTaskQueueLen 64
// UartDev is defined and initialized in rom code.

@ -1,70 +1,87 @@
#include <esp8266.h>
//#include <mqtt.h>
//#include <cgiwifi.h>
#include "cgiwifi.h"
#include "mqtt.h"
//MQTT_Client mqttClient;
//
//void ICACHE_FLASH_ATTR
//mqttConnectedCb(uint32_t *args) {
MQTT_Client mqttClient;
static ETSTimer mqttTimer;
static int once = 0;
static void ICACHE_FLASH_ATTR mqttTimerCb(void *arg) {
if (once++ > 0) return;
MQTT_Init(&mqttClient, "h.voneicken.com", 1883, 0, 2, "test1", "", "", 10, 1);
MQTT_Connect(&mqttClient);
MQTT_Subscribe(&mqttClient, "system/time", 0);
}
void ICACHE_FLASH_ATTR
wifiStateChangeCb(uint8_t status)
{
if (status == wifiGotIP) {
os_timer_disarm(&mqttTimer);
os_timer_setfn(&mqttTimer, mqttTimerCb, NULL);
os_timer_arm(&mqttTimer, 15000, 0);
}
}
// initialize the custom stuff that goes beyond esp-link
void app_init() {
wifiAddStateChangeCb(wifiStateChangeCb);
}
#if 0
MQTT_Client mqttClient;
void ICACHE_FLASH_ATTR
mqttConnectedCb(uint32_t *args) {
MQTT_Client* client = (MQTT_Client*)args;
MQTT_Publish(client, "announce/all", "Hello World!", 0, 0);
}
void ICACHE_FLASH_ATTR
mqttDisconnectedCb(uint32_t *args) {
// MQTT_Client* client = (MQTT_Client*)args;
// MQTT_Publish(client, "announce/all", "Hello World!", 0, 0);
//}
//
//void ICACHE_FLASH_ATTR
//mqttDisconnectedCb(uint32_t *args) {
//// MQTT_Client* client = (MQTT_Client*)args;
// os_printf("MQTT Disconnected\n");
//}
//
//void ICACHE_FLASH_ATTR
//mqttTcpDisconnectedCb(uint32_t *args) {
//// MQTT_Client* client = (MQTT_Client*)args;
// os_printf("MQTT TCP Disconnected\n");
//}
//
//void ICACHE_FLASH_ATTR
//mqttPublishedCb(uint32_t *args) {
//// MQTT_Client* client = (MQTT_Client*)args;
// os_printf("MQTT Published\n");
//}
//
//void ICACHE_FLASH_ATTR
//mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) {
// char *topicBuf = (char*)os_zalloc(topic_len + 1);
// char *dataBuf = (char*)os_zalloc(data_len + 1);
//
//// MQTT_Client* client = (MQTT_Client*)args;
//
// os_memcpy(topicBuf, topic, topic_len);
// topicBuf[topic_len] = 0;
//
// os_memcpy(dataBuf, data, data_len);
// dataBuf[data_len] = 0;
//
// os_printf("Receive topic: %s, data: %s\n", topicBuf, dataBuf);
// os_free(topicBuf);
// os_free(dataBuf);
//}
//
//void ICACHE_FLASH_ATTR
//wifiStateChangeCb(uint8_t status)
//{
// if (status == wifiGotIP && mqttClient.connState != TCP_CONNECTING){
// MQTT_Connect(&mqttClient);
// }
// else if (status == wifiIsDisconnected && mqttClient.connState == TCP_CONNECTING){
// MQTT_Disconnect(&mqttClient);
// }
//}
void init() {
// wifiAddStateChangeCb(wifiStateChangeCb);
// MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, MQTT_SECURITY);
// MQTT_InitClient(&mqttClient, MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, MQTT_KEEPALIVE, MQTT_CLSESSION);
// MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
// MQTT_OnConnected(&mqttClient, mqttConnectedCb);
// MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
// MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb);
// MQTT_OnPublished(&mqttClient, mqttPublishedCb);
// MQTT_OnData(&mqttClient, mqttDataCb);
os_printf("MQTT Disconnected\n");
}
void ICACHE_FLASH_ATTR
mqttTcpDisconnectedCb(uint32_t *args) {
// MQTT_Client* client = (MQTT_Client*)args;
os_printf("MQTT TCP Disconnected\n");
}
void ICACHE_FLASH_ATTR
mqttPublishedCb(uint32_t *args) {
// MQTT_Client* client = (MQTT_Client*)args;
os_printf("MQTT Published\n");
}
void ICACHE_FLASH_ATTR
mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) {
char *topicBuf = (char*)os_zalloc(topic_len + 1);
char *dataBuf = (char*)os_zalloc(data_len + 1);
// MQTT_Client* client = (MQTT_Client*)args;
os_memcpy(topicBuf, topic, topic_len);
topicBuf[topic_len] = 0;
os_memcpy(dataBuf, data, data_len);
dataBuf[data_len] = 0;
os_printf("Receive topic: %s, data: %s\n", topicBuf, dataBuf);
os_free(topicBuf);
os_free(dataBuf);
}
MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, MQTT_SECURITY);
MQTT_InitClient(&mqttClient, MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, MQTT_KEEPALIVE, MQTT_CLSESSION);
MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
MQTT_OnConnected(&mqttClient, mqttConnectedCb);
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb);
MQTT_OnPublished(&mqttClient, mqttPublishedCb);
MQTT_OnData(&mqttClient, mqttDataCb);
#endif

Loading…
Cancel
Save