From f90bf5bb30d51e8f85c8e5a541c790c796d992d9 Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Fri, 28 Aug 2015 20:23:07 -0500 Subject: [PATCH 1/8] Started adding in mqtt module from tuan --- Makefile | 2 +- esp-link.vcxproj | 15 +- include/user_config.h | 38 +++ mqtt/include/mqtt.h | 140 +++++++++ mqtt/include/mqtt_msg.h | 129 ++++++++ mqtt/include/proto.h | 31 ++ mqtt/include/queue.h | 45 +++ mqtt/include/ringbuf.h | 18 ++ mqtt/include/typedef.h | 17 ++ mqtt/include/utils.h | 9 + mqtt/mqtt.c | 637 ++++++++++++++++++++++++++++++++++++++++ mqtt/mqtt_msg.c | 471 +++++++++++++++++++++++++++++ mqtt/proto.c | 128 ++++++++ mqtt/queue.c | 50 ++++ mqtt/ringbuf.c | 67 +++++ mqtt/utils.c | 144 +++++++++ 16 files changed, 1939 insertions(+), 2 deletions(-) create mode 100644 mqtt/include/mqtt.h create mode 100644 mqtt/include/mqtt_msg.h create mode 100644 mqtt/include/proto.h create mode 100644 mqtt/include/queue.h create mode 100644 mqtt/include/ringbuf.h create mode 100644 mqtt/include/typedef.h create mode 100644 mqtt/include/utils.h create mode 100644 mqtt/mqtt.c create mode 100644 mqtt/mqtt_msg.c create mode 100644 mqtt/proto.c create mode 100644 mqtt/queue.c create mode 100644 mqtt/ringbuf.c create mode 100644 mqtt/utils.c diff --git a/Makefile b/Makefile index a3df665..7969417 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ TARGET = httpd APPGEN_TOOL ?= gen_appbin.py # which modules (subdirectories) of the project to include in compiling -MODULES = espfs httpd user serial cmd +MODULES = espfs httpd user serial cmd mqtt EXTRA_INCDIR = include . # libraries used in this project, mainly provided by the SDK diff --git a/esp-link.vcxproj b/esp-link.vcxproj index c98faa5..eac1d5b 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -28,7 +28,7 @@ __ets__;_STDINT_H;ICACHE_FLASH;__MINGW32__;__WIN32__ - .\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include + .\mqtt\include;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include @@ -75,6 +75,12 @@ + + + + + + @@ -106,6 +112,13 @@ + + + + + + + diff --git a/include/user_config.h b/include/user_config.h index 8b13789..d38c637 100644 --- a/include/user_config.h +++ b/include/user_config.h @@ -1 +1,39 @@ +#ifndef _USER_CONFIG_H_ +#define _USER_CONFIG_H_ +/*DEFAULT CONFIGURATIONS*/ + +#define MQTT_HOST "mqtt.yourdomain.com" //or "mqtt.yourdomain.com" +#define MQTT_PORT 1883 +#define MQTT_BUF_SIZE 1024 +#define MQTT_KEEPALIVE 120 /*second*/ + +#define MQTT_CLIENT_ID "H_%08X" //Cuidar para não colocar valores execendentes da ESTRUTURA SYSCFG +#define MQTT_USER "DVES_USER" +#define MQTT_PASS "DVES_PASS" + +#define STA_SSID "TESTE" +#define STA_PASS "54545" +#define STA_TYPE AUTH_WPA2_PSK + +#define MQTT_RECONNECT_TIMEOUT 5 /*second*/ + +#define DEFAULT_SECURITY 0 +#define QUEUE_BUFFER_SIZE 2048 + +//#undef MCU_RESET_PIN +//#undef MCU_ISP_PIN +//#undef LED_CONN_PIN +//#undef LED_SERIAL_PIN +// +//#define MCU_RESET_PIN 2 +//#define MCU_ISP_PIN -1 +//#define LED_CONN_PIN -1 +//#define LED_SERIAL_PIN -1 + +//#define BAUD_RATE 9600 +//#define HOSTNAME "nodemcu\0 " + +#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/ +//PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/ +#endif \ No newline at end of file diff --git a/mqtt/include/mqtt.h b/mqtt/include/mqtt.h new file mode 100644 index 0000000..52d21fe --- /dev/null +++ b/mqtt/include/mqtt.h @@ -0,0 +1,140 @@ +/* mqtt.h +* +* Copyright (c) 2014-2015, Tuan PM +* 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_AT_MQTT_H_ +#define USER_AT_MQTT_H_ + +#include +#include "mqtt_msg.h" +#include "queue.h" +#include "utils.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; + +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 +} tConnState; + +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); + +typedef struct { + struct espconn *pCon; + uint8_t security; + uint8_t* host; + uint32_t port; + ip_addr_t ip; + mqtt_state_t mqtt_state; + mqtt_connect_info_t connect_info; + MqttCallback connectedCb; + MqttCallback disconnectedCb; + MqttCallback publishedCb; + MqttDataCallback dataCb; + ETSTimer mqttTimer; + uint32_t keepAliveTick; + uint32_t reconnectTick; + uint32_t sendTimeout; + tConnState connState; + QUEUE msgQueue; + void* user_data; +} MQTT_Client; + +#define SEC_NONSSL 0 +#define SEC_SSL 1 + +#define MQTT_FLAG_CONNECTED 1 +#define MQTT_FLAG_READY 2 +#define MQTT_FLAG_EXIT 4 + +#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 + +void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security); +void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession); +void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain); +void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb); +void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb); +void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb); +void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb); +bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos); +void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient); +void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient); +bool ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int qos, int retain); + +#endif /* USER_AT_MQTT_H_ */ diff --git a/mqtt/include/mqtt_msg.h b/mqtt/include/mqtt_msg.h new file mode 100644 index 0000000..f16bb80 --- /dev/null +++ b/mqtt/include/mqtt_msg.h @@ -0,0 +1,129 @@ +/* + * File: mqtt_msg.h + * Author: Minh Tuan + * + * Created on July 12, 2014, 1:05 PM + */ + +#ifndef MQTT_MSG_H +#define MQTT_MSG_H +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* +* Copyright (c) 2014, Stephen Robinson +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. 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. +* 3. Neither the name of the copyright holder 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 HOLDER 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. +* +*/ +/* 7 6 5 4 3 2 1 0*/ +/* | --- Message Type ---- | DUP Flag | QoS Level | Retain | Remaining Length | */ + + +enum mqtt_message_type +{ + MQTT_MSG_TYPE_CONNECT = 1, + MQTT_MSG_TYPE_CONNACK = 2, + MQTT_MSG_TYPE_PUBLISH = 3, + MQTT_MSG_TYPE_PUBACK = 4, + MQTT_MSG_TYPE_PUBREC = 5, + MQTT_MSG_TYPE_PUBREL = 6, + MQTT_MSG_TYPE_PUBCOMP = 7, + MQTT_MSG_TYPE_SUBSCRIBE = 8, + MQTT_MSG_TYPE_SUBACK = 9, + MQTT_MSG_TYPE_UNSUBSCRIBE = 10, + MQTT_MSG_TYPE_UNSUBACK = 11, + MQTT_MSG_TYPE_PINGREQ = 12, + MQTT_MSG_TYPE_PINGRESP = 13, + MQTT_MSG_TYPE_DISCONNECT = 14 +}; + +typedef struct mqtt_message +{ + uint8_t* data; + uint16_t length; + +} mqtt_message_t; + +typedef struct mqtt_connection +{ + mqtt_message_t message; + + uint16_t message_id; + uint8_t* buffer; + uint16_t buffer_length; + +} mqtt_connection_t; + +typedef struct mqtt_connect_info +{ + char* client_id; + char* username; + char* password; + char* will_topic; + char* will_message; + int keepalive; + int will_qos; + int will_retain; + int clean_session; + +} mqtt_connect_info_t; + + +static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; } +static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } +static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } +static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } + +void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); +int ICACHE_FLASH_ATTR 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); +const char* ICACHE_FLASH_ATTR 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_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); +mqtt_message_t* ICACHE_FLASH_ATTR 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* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection); + + +#ifdef __cplusplus +} +#endif + +#endif /* MQTT_MSG_H */ + diff --git a/mqtt/include/proto.h b/mqtt/include/proto.h new file mode 100644 index 0000000..73a4e8b --- /dev/null +++ b/mqtt/include/proto.h @@ -0,0 +1,31 @@ +/* + * File: proto.h + * Author: ThuHien + * + * Created on November 23, 2012, 8:57 AM + */ + +#ifndef _PROTO_H_ +#define _PROTO_H_ +#include +#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 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, uint8_t *buf, uint16_t bufSize); +int8_t ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, uint8_t *buf, uint16_t len); +int16_t ICACHE_FLASH_ATTR PROTO_Add(uint8_t *buf, const uint8_t *packet, int16_t bufSize); +int16_t ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const uint8_t *packet, int16_t len); +int8_t ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, uint8_t value); +int16_t ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, uint8_t *bufOut, uint16_t* len, uint16_t maxBufLen); +#endif + diff --git a/mqtt/include/queue.h b/mqtt/include/queue.h new file mode 100644 index 0000000..7a84480 --- /dev/null +++ b/mqtt/include/queue.h @@ -0,0 +1,45 @@ +/* str_queue.h -- +* +* Copyright (c) 2014-2015, Tuan PM +* 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 +#include "proto.h" +#include "ringbuf.h" +typedef struct { + uint8_t *buf; + RINGBUF rb; +} QUEUE; + +void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize); +int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len); +int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen); +bool ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue); +#endif /* USER_QUEUE_H_ */ diff --git a/mqtt/include/ringbuf.h b/mqtt/include/ringbuf.h new file mode 100644 index 0000000..03d780d --- /dev/null +++ b/mqtt/include/ringbuf.h @@ -0,0 +1,18 @@ +#ifndef _RING_BUF_H_ +#define _RING_BUF_H_ + +#include +#include "typedef.h" + +typedef struct{ + U8* p_o; /**< Original pointer */ + U8* volatile p_r; /**< Read pointer */ + U8* volatile p_w; /**< Write pointer */ + volatile I32 fill_cnt; /**< Number of filled slots */ + I32 size; /**< Buffer size */ +}RINGBUF; + +I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size); +I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c); +I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c); +#endif diff --git a/mqtt/include/typedef.h b/mqtt/include/typedef.h new file mode 100644 index 0000000..a4c69d6 --- /dev/null +++ b/mqtt/include/typedef.h @@ -0,0 +1,17 @@ +/** +* \file +* Standard Types definition +*/ + +#ifndef _TYPE_DEF_H_ +#define _TYPE_DEF_H_ + +typedef char I8; +typedef unsigned char U8; +typedef short I16; +typedef unsigned short U16; +typedef long I32; +typedef unsigned long U32; +typedef unsigned long long U64; + +#endif diff --git a/mqtt/include/utils.h b/mqtt/include/utils.h new file mode 100644 index 0000000..676501e --- /dev/null +++ b/mqtt/include/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include + +uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s); +uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip); +uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str); +#endif diff --git a/mqtt/mqtt.c b/mqtt/mqtt.c new file mode 100644 index 0000000..49ed507 --- /dev/null +++ b/mqtt/mqtt.c @@ -0,0 +1,637 @@ +/* mqtt.c +* Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html +* +* Copyright (c) 2014-2015, Tuan PM +* 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 "mqtt.h" + +#define MQTT_TASK_PRIO 0 +#define MQTT_TASK_QUEUE_SIZE 1 +#define MQTT_SEND_TIMOUT 5 + +#ifndef QUEUE_BUFFER_SIZE +#define QUEUE_BUFFER_SIZE 2048 +#endif + +unsigned char *default_certificate; +unsigned int default_certificate_len = 0; +unsigned char *default_private_key; +unsigned int default_private_key_len = 0; + +os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE]; + +LOCAL void ICACHE_FLASH_ATTR +mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) +{ + struct espconn *pConn = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pConn->reverse; + + + if (ipaddr == NULL) + { + os_printf("DNS: Found, but got no ip, try to reconnect\n"); + client->connState = TCP_RECONNECT_REQ; + return; + } + + os_printf("DNS: found ip %d.%d.%d.%d\n", + *((uint8 *)&ipaddr->addr), + *((uint8 *)&ipaddr->addr + 1), + *((uint8 *)&ipaddr->addr + 2), + *((uint8 *)&ipaddr->addr + 3)); + + if (client->ip.addr == 0 && ipaddr->addr != 0) + { + os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); +#ifdef CLIENT_SSL_ENABLE + if (client->security){ + espconn_secure_connect(client->pCon); + } + else +#endif + espconn_connect(client->pCon); + + client->connState = TCP_CONNECTING; + os_printf("MQTT-TCP: connecting...\n"); + } + + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + + + +LOCAL void ICACHE_FLASH_ATTR +deliver_publish(MQTT_Client* client, uint8_t* message, int length) +{ + mqtt_event_data_t event_data; + + event_data.topic_length = length; + event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length); + event_data.data_length = length; + event_data.data = mqtt_get_publish_data(message, &event_data.data_length); + + if (client->dataCb) + client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length); + +} + + +/** +* @brief Client received callback function. +* @param arg: contain the ip link information +* @param pdata: received data +* @param len: the lenght of received data +* @retval None +*/ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len) +{ + uint8_t msg_type; + uint8_t msg_qos; + uint16_t msg_id; + + struct espconn *pCon = (struct espconn*)arg; + MQTT_Client *client = (MQTT_Client *)pCon->reverse; + +READPACKET: + os_printf("MQTT-TCP: Data received %d bytes\n", len); + if (len < MQTT_BUF_SIZE && len > 0){ + os_memcpy(client->mqtt_state.in_buffer, pdata, len); + + msg_type = mqtt_get_type(client->mqtt_state.in_buffer); + msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); + msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); + if (client->connState == MQTT_CONNECT_SENDING) { + if (msg_type == MQTT_MSG_TYPE_CONNACK){ + if (client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT){ + os_printf("MQTT: Invalid packet\n"); +#ifdef CLIENT_SSL_ENABLE + if (client->security){ + espconn_secure_disconnect(client->pCon); + } + else +#endif + espconn_disconnect(client->pCon); + } + else { + os_printf("MQTT: Connected to %s:%ld\n", client->host, client->port); + client->connState = MQTT_DATA; + if (client->connectedCb) + client->connectedCb((uint32_t*)client); + } + } + } + else if (client->connState == MQTT_DATA) { + client->mqtt_state.message_length_read = len; + client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); + + + if (msg_type == MQTT_MSG_TYPE_SUBACK) { + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) + os_printf("MQTT: Subscribe successful\n"); + } + else if (msg_type == MQTT_MSG_TYPE_UNSUBACK){ + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) + os_printf("MQTT: UnSubscribe successful\n"); + } + else if (msg_type == MQTT_MSG_TYPE_PUBLISH) { + if (msg_qos == 1) + client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); + else if (msg_qos == 2) + client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); + if (msg_qos == 1 || msg_qos == 2){ + os_printf("MQTT: Queue response QoS: %d\n", msg_qos); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + os_printf("MQTT: Queue full\n"); + } + } + deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); + } + else if (msg_type == MQTT_MSG_TYPE_PUBACK) { + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){ + os_printf("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\n"); + } + } + else if (msg_type == MQTT_MSG_TYPE_PUBREC) { + client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + os_printf("MQTT: Queue full\n"); + } + } + else if (msg_type == MQTT_MSG_TYPE_PUBREL) { + client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + os_printf("MQTT: Queue full\n"); + } + } + else if (msg_type == MQTT_MSG_TYPE_PUBCOMP) { + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){ + os_printf("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\n"); + } + } + else if (msg_type == MQTT_MSG_TYPE_PINGREQ) { + client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + os_printf("MQTT: Queue full\n"); + } + } + + // NOTE: this is done down here and not in the switch case above + // because the PSOCK_READBUF_LEN() won't work inside a switch + // statement due to the way protothreads resume. + if (msg_type == MQTT_MSG_TYPE_PUBLISH) + { + len = client->mqtt_state.message_length_read; + + if (client->mqtt_state.message_length < client->mqtt_state.message_length_read) + { + //client->connState = MQTT_PUBLISH_RECV; + //Not Implement yet + len -= client->mqtt_state.message_length; + pdata += client->mqtt_state.message_length; + + os_printf("Get another published message\n"); + goto READPACKET; + } + } + } + } + else { + os_printf("ERROR: Message too long\n"); + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +/** +* @brief Client send over callback function. +* @param arg: contain the ip link information +* @retval None +*/ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_sent_cb(void *arg) +{ + struct espconn *pCon = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pCon->reverse; + os_printf("MQTT-TCP: Sent\n"); + client->sendTimeout = 0; + if (client->connState == MQTT_DATA && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH){ + if (client->publishedCb) + client->publishedCb((uint32_t*)client); + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +void ICACHE_FLASH_ATTR mqtt_timer(void *arg) +{ + MQTT_Client* client = (MQTT_Client*)arg; + + if (client->connState == MQTT_DATA){ + client->keepAliveTick++; + if (client->keepAliveTick > client->mqtt_state.connect_info->keepalive){ + + os_printf("\nMQTT: Send keepalive packet to %s:%ld!\n", client->host, client->port); + client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); + client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); + client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + + + client->sendTimeout = MQTT_SEND_TIMOUT; + os_printf("MQTT: Sending, type: %d, id: %04X\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); +#ifdef CLIENT_SSL_ENABLE + if (client->security){ + espconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + } + else +#endif + espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + + client->mqtt_state.outbound_message = NULL; + + client->keepAliveTick = 0; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + } + + } + else if (client->connState == TCP_RECONNECT_REQ){ + client->reconnectTick++; + if (client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { + client->reconnectTick = 0; + client->connState = TCP_RECONNECT; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + } + } + if (client->sendTimeout > 0) + client->sendTimeout--; +} + +void ICACHE_FLASH_ATTR +mqtt_tcpclient_discon_cb(void *arg) +{ + + struct espconn *pespconn = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pespconn->reverse; + os_printf("MQTT-TCP: Disconnected callback\n"); + client->connState = TCP_RECONNECT_REQ; + if (client->disconnectedCb) + client->disconnectedCb((uint32_t*)client); + + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +/** +* @brief Tcp client connect success callback function. +* @param arg: contain the ip link information +* @retval None +*/ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_connect_cb(void *arg) +{ + struct espconn *pCon = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pCon->reverse; + + espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); + espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);//////// + espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);/////// + os_printf("MQTT: Connected to broker %s:%ld\n", client->host, client->port); + + mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); + client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); + client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + + + client->sendTimeout = MQTT_SEND_TIMOUT; + os_printf("MQTT: Sending, type: %d, id: %04X\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); +#ifdef CLIENT_SSL_ENABLE + if (client->security){ + espconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + } + else +#endif + espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + + client->mqtt_state.outbound_message = NULL; + client->connState = MQTT_CONNECT_SENDING; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +/** +* @brief Tcp client connect repeat callback function. +* @param arg: contain the ip link information +* @retval None +*/ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_recon_cb(void *arg, sint8 errType) +{ + struct espconn *pCon = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pCon->reverse; + + os_printf("MQTT-TCP: Reconnect to %s:%ld\n", client->host, client->port); + + client->connState = TCP_RECONNECT_REQ; + + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +/** +* @brief MQTT publish function. +* @param client: MQTT_Client reference +* @param topic: string topic will publish to +* @param data: buffer data send point to +* @param data_length: length of data +* @param qos: qos +* @param retain: retain +* @retval TRUE if success queue +*/ +bool ICACHE_FLASH_ATTR +MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int qos, int retain) +{ + int data_length = os_strlen(data); + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, + topic, data, data_length, + qos, retain, + &client->mqtt_state.pending_msg_id); + if (client->mqtt_state.outbound_message->length == 0){ + os_printf("MQTT: Queuing Publish failed\n"); + return FALSE; + } + os_printf("MQTT: Queuing Publish, length: %d, queue size(%ld/%ld)\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size); + while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + os_printf("MQTT: Queue full\n"); + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { + os_printf("MQTT: Serious buffer error\n"); + return FALSE; + } + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + return TRUE; +} + +/** +* @brief MQTT subscibe function. +* @param client: MQTT_Client reference +* @param topic: string topic will subscribe +* @param qos: qos +* @retval TRUE if success queue +*/ +bool ICACHE_FLASH_ATTR +MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos) +{ + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + + client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection, + topic, 0, + &client->mqtt_state.pending_msg_id); + os_printf("MQTT: Queue Subscribe, topic: \"%s\", id: %d\n", topic, client->mqtt_state.pending_msg_id); + while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + os_printf("MQTT: Queue full\n"); + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { + os_printf("MQTT: Serious buffer error\n"); + return FALSE; + } + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + return TRUE; +} + +void ICACHE_FLASH_ATTR MQTT_Task(os_event_t *e) { + MQTT_Client* client = (MQTT_Client*)e->par; + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + if (e->par == 0) + return; + + if (client->connState == TCP_RECONNECT_REQ) { + return; + } + else if (client->connState == TCP_RECONNECT){ + MQTT_Connect(client); + os_printf("MQTT-TCP: Reconnect to: %s:%ld\n", client->host, client->port); + client->connState = TCP_CONNECTING; + } + else if (client->connState == MQTT_DATA) { + if (QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) + return; + + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0){ + client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer); + client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen); + client->sendTimeout = MQTT_SEND_TIMOUT; + os_printf("MQTT: Sending, type: %d, id: %04X\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); +#ifdef CLIENT_SSL_ENABLE + if (client->security){ + espconn_secure_sent(client->pCon, dataBuffer, dataLen); + } + else +#endif + espconn_sent(client->pCon, dataBuffer, dataLen); + + client->mqtt_state.outbound_message = NULL; + return; + } + return; + } +} + +/** +* @brief MQTT initialization connection function +* @param client: MQTT_Client reference +* @param host: Domain or IP string +* @param port: Port to connect +* @param security: 1 for ssl, 0 for none +* @retval None +*/ +void ICACHE_FLASH_ATTR +MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security) +{ + uint32_t temp; + os_printf("MQTT_InitConnection\n"); + os_memset(mqttClient, 0, sizeof(MQTT_Client)); + temp = sizeof((char*)host); + mqttClient->host = (uint8_t*)os_zalloc(temp + 1); + os_strcpy((char*)mqttClient->host, (char*)host); + mqttClient->host[temp] = 0; + mqttClient->port = port; + mqttClient->security = security; +} + +/** +* @brief MQTT initialization mqtt client function +* @param client: MQTT_Client reference +* @param clientid: MQTT client id +* @param client_user:MQTT client user +* @param client_pass:MQTT client password +* @param client_pass:MQTT keep alive timer, in second +* @retval None +*/ +void ICACHE_FLASH_ATTR +MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) +{ + uint32_t temp; + os_printf("MQTT_InitClient\n"); + + os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); + + temp = os_strlen((char*)client_id); + mqttClient->connect_info.client_id = (char*)os_zalloc(temp + 1); + os_strcpy((char*)mqttClient->connect_info.client_id, (char*)client_id); + mqttClient->connect_info.client_id[temp] = 0; + + temp = os_strlen((char*)client_user); + mqttClient->connect_info.username = (char*)os_zalloc(temp + 1); + os_strcpy((char*)mqttClient->connect_info.username, (char*)client_user); + mqttClient->connect_info.username[temp] = 0; + + temp = os_strlen((char*)client_pass); + mqttClient->connect_info.password = (char*)os_zalloc(temp + 1); + os_strcpy((char*)mqttClient->connect_info.password, (char*)client_pass); + mqttClient->connect_info.password[temp] = 0; + + + mqttClient->connect_info.keepalive = keepAliveTime; + mqttClient->connect_info.clean_session = cleanSession; + + mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); + mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; + mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); + mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; + mqttClient->mqtt_state.connect_info = &mqttClient->connect_info; + + mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length); + + QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE); + + system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE); + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); +} + +void ICACHE_FLASH_ATTR +MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain) +{ + uint32_t temp; + temp = os_strlen((char*)will_topic); + mqttClient->connect_info.will_topic = (char*)os_zalloc(temp + 1); + os_strcpy((char*)mqttClient->connect_info.will_topic, (char*)will_topic); + mqttClient->connect_info.will_topic[temp] = 0; + + temp = os_strlen((char*)will_msg); + mqttClient->connect_info.will_message = (char*)os_zalloc(temp + 1); + os_strcpy((char*)mqttClient->connect_info.will_message, (char*)will_msg); + mqttClient->connect_info.will_message[temp] = 0; + + + mqttClient->connect_info.will_qos = will_qos; + mqttClient->connect_info.will_retain = will_retain; +} + +/** +* @brief Begin connect to MQTT broker +* @param client: MQTT_Client reference +* @retval None +*/ +void ICACHE_FLASH_ATTR +MQTT_Connect(MQTT_Client *mqttClient) +{ + MQTT_Disconnect(mqttClient); + mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn)); + mqttClient->pCon->type = ESPCONN_TCP; + mqttClient->pCon->state = ESPCONN_NONE; + mqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + mqttClient->pCon->proto.tcp->local_port = espconn_port(); + mqttClient->pCon->proto.tcp->remote_port = mqttClient->port; + mqttClient->pCon->reverse = mqttClient; + espconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb); + espconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb); + + mqttClient->keepAliveTick = 0; + mqttClient->reconnectTick = 0; + + + os_timer_disarm(&mqttClient->mqttTimer); + os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient); + os_timer_arm(&mqttClient->mqttTimer, 1000, 1); + + if (UTILS_StrToIP((const int8_t *)mqttClient->host, (void*)&mqttClient->pCon->proto.tcp->remote_ip)) { + os_printf("MQTT-TCP: Connect to ip %s:%ld\n", mqttClient->host, mqttClient->port); +#ifdef CLIENT_SSL_ENABLE + if (mqttClient->security){ + espconn_secure_connect(mqttClient->pCon); + } + else +#endif + espconn_connect(mqttClient->pCon); + } + else { + os_printf("MQTT-TCP: Connect to domain %s:%ld\n", mqttClient->host, mqttClient->port); + espconn_gethostbyname(mqttClient->pCon, (const char *)mqttClient->host, &mqttClient->ip, mqtt_dns_found); + } + mqttClient->connState = TCP_CONNECTING; +} + +void ICACHE_FLASH_ATTR +MQTT_Disconnect(MQTT_Client *mqttClient) +{ + if (mqttClient->pCon){ + os_printf("Free memory\n"); + if (mqttClient->pCon->proto.tcp) + os_free(mqttClient->pCon->proto.tcp); + os_free(mqttClient->pCon); + mqttClient->pCon = NULL; + } + + os_timer_disarm(&mqttClient->mqttTimer); +} + +void ICACHE_FLASH_ATTR +MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb) +{ + mqttClient->connectedCb = connectedCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb) +{ + mqttClient->disconnectedCb = disconnectedCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb) +{ + mqttClient->dataCb = dataCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb) +{ + mqttClient->publishedCb = publishedCb; +} diff --git a/mqtt/mqtt_msg.c b/mqtt/mqtt_msg.c new file mode 100644 index 0000000..7e159c6 --- /dev/null +++ b/mqtt/mqtt_msg.c @@ -0,0 +1,471 @@ +/* +* Copyright (c) 2014, Stephen Robinson +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. 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. +* 3. Neither the name of the copyright holder 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 HOLDER 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 "mqtt_msg.h" +#define MQTT_MAX_FIXED_HEADER_SIZE 3 + +enum mqtt_connect_flag +{ + MQTT_CONNECT_FLAG_USERNAME = 1 << 7, + MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, + MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, + MQTT_CONNECT_FLAG_WILL = 1 << 2, + MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 +}; + +struct __attribute__((__packed__)) mqtt_connect_variable_header +{ + uint8_t lengthMsb; + uint8_t lengthLsb; +#if defined(PROTOCOL_NAMEv31) + uint8_t magic[6]; +#elif defined(PROTOCOL_NAMEv311) + uint8_t magic[4]; +#else +#error "Please define protocol name" +#endif + uint8_t version; + uint8_t flags; + uint8_t keepaliveMsb; + uint8_t keepaliveLsb; +}; + +static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len) +{ + if (connection->message.length + len + 2 > connection->buffer_length) + return -1; + + connection->buffer[connection->message.length++] = len >> 8; + connection->buffer[connection->message.length++] = len & 0xff; + memcpy(connection->buffer + connection->message.length, string, len); + connection->message.length += len; + + return len + 2; +} + +static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id) +{ + // If message_id is zero then we should assign one, otherwise + // we'll use the one supplied by the caller + while (message_id == 0) + message_id = ++connection->message_id; + + if (connection->message.length + 2 > connection->buffer_length) + return 0; + + connection->buffer[connection->message.length++] = message_id >> 8; + connection->buffer[connection->message.length++] = message_id & 0xff; + + return message_id; +} + +static int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection) +{ + connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; + return MQTT_MAX_FIXED_HEADER_SIZE; +} + +static mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection) +{ + connection->message.data = connection->buffer; + connection->message.length = 0; + return &connection->message; +} + +static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) +{ + int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; + + if (remaining_length > 127) + { + connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + connection->buffer[1] = 0x80 | (remaining_length % 128); + connection->buffer[2] = remaining_length / 128; + connection->message.length = remaining_length + 3; + connection->message.data = connection->buffer; + } + else + { + connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + connection->buffer[2] = remaining_length; + connection->message.length = remaining_length + 2; + connection->message.data = connection->buffer + 1; + } + + return &connection->message; +} + +void ICACHE_FLASH_ATTR +mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) { + memset(connection, 0, sizeof(connection)); + connection->buffer = buffer; + connection->buffer_length = buffer_length; +} + +int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length) +{ + int i; + int totlen = 0; + + for (i = 1; i < length; ++i) + { + totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); + if ((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + totlen += i; + + return totlen; +} + +const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) +{ + int i; + int totlen = 0; + int topiclen; + + for (i = 1; i < *length; ++i) + { + totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); + if ((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + totlen += i; + + if (i + 2 >= *length) + return NULL; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if (i + topiclen > *length) + return NULL; + + *length = topiclen; + return (const char*)(buffer + i); +} + +const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) +{ + int i; + int totlen = 0; + int topiclen; + + for (i = 1; i < *length; ++i) + { + totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); + if ((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + totlen += i; + + if (i + 2 >= *length) + return NULL; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if (i + topiclen >= *length){ + *length = 0; + return NULL; + } + i += topiclen; + + if (mqtt_get_qos(buffer) > 0) + { + if (i + 2 >= *length) + return NULL; + i += 2; + } + + if (totlen < i) + return NULL; + + if (totlen <= *length) + *length = totlen - i; + else + *length = *length - i; + return (const char*)(buffer + i); +} + +uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length) +{ + if (length < 1) + return 0; + + switch (mqtt_get_type(buffer)) + { + case MQTT_MSG_TYPE_PUBLISH: + { + int i; + int topiclen; + + for (i = 1; i < length; ++i) + { + if ((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + + if (i + 2 >= length) + return 0; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if (i + topiclen >= length) + return 0; + i += topiclen; + + if (mqtt_get_qos(buffer) > 0) + { + if (i + 2 >= length) + return 0; + //i += 2; + } + else { + return 0; + } + + return (buffer[i] << 8) | buffer[i + 1]; + } + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_SUBSCRIBE: + { + // This requires the remaining length to be encoded in 1 byte, + // which it should be. + if (length >= 4 && (buffer[1] & 0x80) == 0) + return (buffer[2] << 8) | buffer[3]; + else + return 0; + } + + default: + return 0; + } +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) +{ + struct mqtt_connect_variable_header* variable_header; + + init_message(connection); + + if (connection->message.length + sizeof(*variable_header) > connection->buffer_length) + return fail_message(connection); + variable_header = (void*)(connection->buffer + connection->message.length); + connection->message.length += sizeof(*variable_header); + + variable_header->lengthMsb = 0; +#if defined(PROTOCOL_NAMEv31) + variable_header->lengthLsb = 6; + memcpy(variable_header->magic, "MQIsdp", 6); + variable_header->version = 3; +#elif defined(PROTOCOL_NAMEv311) + variable_header->lengthLsb = 4; + memcpy(variable_header->magic, "MQTT", 4); + variable_header->version = 4; +#else +#error "Please define protocol name" +#endif + + variable_header->flags = 0; + variable_header->keepaliveMsb = info->keepalive >> 8; + variable_header->keepaliveLsb = info->keepalive & 0xff; + + if (info->clean_session) + variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; + + if (info->client_id != NULL && info->client_id[0] != '\0') + { + if (append_string(connection, info->client_id, strlen(info->client_id)) < 0) + return fail_message(connection); + } + else + return fail_message(connection); + + if (info->will_topic != NULL && info->will_topic[0] != '\0') + { + if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) + return fail_message(connection); + + if (append_string(connection, info->will_message, strlen(info->will_message)) < 0) + return fail_message(connection); + + variable_header->flags |= MQTT_CONNECT_FLAG_WILL; + if (info->will_retain) + variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; + variable_header->flags |= (info->will_qos & 3) << 3; + } + + if (info->username != NULL && info->username[0] != '\0') + { + if (append_string(connection, info->username, strlen(info->username)) < 0) + return fail_message(connection); + + variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; + } + + if (info->password != NULL && info->password[0] != '\0') + { + if (append_string(connection, info->password, strlen(info->password)) < 0) + return fail_message(connection); + + variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; + } + + return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) +{ + init_message(connection); + + if (topic == NULL || topic[0] == '\0') + return fail_message(connection); + + if (append_string(connection, topic, strlen(topic)) < 0) + return fail_message(connection); + + if (qos > 0) + { + if ((*message_id = append_message_id(connection, 0)) == 0) + return fail_message(connection); + } + else + *message_id = 0; + + if (connection->message.length + data_length > connection->buffer_length) + return fail_message(connection); + memcpy(connection->buffer + connection->message.length, data, data_length); + connection->message.length += data_length; + + return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) +{ + init_message(connection); + + if (topic == NULL || topic[0] == '\0') + return fail_message(connection); + + if ((*message_id = append_message_id(connection, 0)) == 0) + return fail_message(connection); + + if (append_string(connection, topic, strlen(topic)) < 0) + return fail_message(connection); + + if (connection->message.length + 1 > connection->buffer_length) + return fail_message(connection); + connection->buffer[connection->message.length++] = qos; + + return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) +{ + init_message(connection); + + if (topic == NULL || topic[0] == '\0') + return fail_message(connection); + + if ((*message_id = append_message_id(connection, 0)) == 0) + return fail_message(connection); + + if (append_string(connection, topic, strlen(topic)) < 0) + return fail_message(connection); + + return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection) +{ + init_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection) +{ + init_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection) +{ + init_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); +} diff --git a/mqtt/proto.c b/mqtt/proto.c new file mode 100644 index 0000000..3909b15 --- /dev/null +++ b/mqtt/proto.c @@ -0,0 +1,128 @@ +#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; +} + +int8_t ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, uint8_t *buf, uint16_t len) +{ + while(len--) + PROTO_ParseByte(parser, *buf++); + return 0; +} +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_Add(uint8_t *buf, const uint8_t *packet, int16_t bufSize) +{ + uint16_t i = 2; + uint16_t len = *(uint16_t*) packet; + + if (bufSize < 1) return -1; + + *buf++ = 0x7E; + bufSize--; + + while (len--) { + switch (*packet) { + case 0x7D: + case 0x7E: + case 0x7F: + if (bufSize < 2) return -1; + *buf++ = 0x7D; + *buf++ = *packet++ ^ 0x20; + i += 2; + bufSize -= 2; + break; + default: + if (bufSize < 1) return -1; + *buf++ = *packet++; + i++; + bufSize--; + break; + } + } + + if (bufSize < 1) return -1; + *buf++ = 0x7F; + + return i; +} + +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; +} + diff --git a/mqtt/queue.c b/mqtt/queue.c new file mode 100644 index 0000000..147015e --- /dev/null +++ b/mqtt/queue.c @@ -0,0 +1,50 @@ +/* str_queue.c +* +* Copyright (c) 2014-2015, Tuan PM +* 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; +} \ No newline at end of file diff --git a/mqtt/ringbuf.c b/mqtt/ringbuf.c new file mode 100644 index 0000000..5ac3d07 --- /dev/null +++ b/mqtt/ringbuf.c @@ -0,0 +1,67 @@ +/** +* \file +* Ring Buffer library +*/ + +#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 +*/ +I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 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 +*/ +I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 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 +*/ +I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* 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; +} diff --git a/mqtt/utils.c b/mqtt/utils.c new file mode 100644 index 0000000..5ece013 --- /dev/null +++ b/mqtt/utils.c @@ -0,0 +1,144 @@ +/* +* Copyright (c) 2014, Tuan PM +* Email: tuanpm@live.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: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. 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. +* 3. Neither the name of the copyright holder 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 HOLDER 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 "utils.h" + + +uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str) +{ + uint8_t segs = 0; /* Segment count. */ + uint8_t chcnt = 0; /* Character count within segment. */ + uint8_t accum = 0; /* Accumulator for segment. */ + /* Catch NULL pointer. */ + if (str == 0) + return 0; + /* Process every character in string. */ + + while (*str != '\0') { + /* Segment changeover. */ + + if (*str == '.') { + /* Must have some digits in segment. */ + if (chcnt == 0) + return 0; + /* Limit number of segments. */ + if (++segs == 4) + return 0; + /* Reset segment values and restart loop. */ + chcnt = accum = 0; + str++; + continue; + } + + /* Check numeric. */ + if ((*str < '0') || (*str > '9')) + return 0; + + /* Accumulate and check segment. */ + + if ((accum = accum * 10 + *str - '0') > 255) + return 0; + /* Advance other segment specific stuff and continue loop. */ + + chcnt++; + str++; + } + + /* Check enough segments and enough characters in last segment. */ + + if (segs != 3) + return 0; + if (chcnt == 0) + return 0; + /* Address okay. */ + + return 1; +} +uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* 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; + } + } + if (n >= 256) { + return 0; + } + ((uint8_t*)ip)[i] = n; + } + return 1; + +} +uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s) +{ + uint32_t value = 0, digit; + int8_t c; + + while((c = *s++)){ + if('0' <= c && c <= '9') + digit = c - '0'; + else if('A' <= c && c <= 'F') + digit = c - 'A' + 10; + else if('a' <= c && c<= 'f') + digit = c - 'a' + 10; + else break; + + value = (value << 4) | digit; + } + + return value; +} + From b3408a70228b429ec8b6d27f09cc0cc78227f109 Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Fri, 28 Aug 2015 20:33:59 -0500 Subject: [PATCH 2/8] all warnings fixed --- mqtt/mqtt_msg.c | 3 +- mqtt/utils.c | 194 ++++++++++++++++++++++++------------------------ 2 files changed, 99 insertions(+), 98 deletions(-) diff --git a/mqtt/mqtt_msg.c b/mqtt/mqtt_msg.c index 7e159c6..77c777e 100644 --- a/mqtt/mqtt_msg.c +++ b/mqtt/mqtt_msg.c @@ -125,7 +125,8 @@ static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connect void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) { - memset(connection, 0, sizeof(connection)); + uint8_t len = sizeof(connection); + memset(connection, '\0', len); connection->buffer = buffer; connection->buffer_length = buffer_length; } diff --git a/mqtt/utils.c b/mqtt/utils.c index 5ece013..173b573 100644 --- a/mqtt/utils.c +++ b/mqtt/utils.c @@ -32,113 +32,113 @@ */ #include "utils.h" - -uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str) +uint8_t ICACHE_FLASH_ATTR +UTILS_IsIPV4(int8_t *str) { - uint8_t segs = 0; /* Segment count. */ - uint8_t chcnt = 0; /* Character count within segment. */ - uint8_t accum = 0; /* Accumulator for segment. */ - /* Catch NULL pointer. */ - if (str == 0) - return 0; - /* Process every character in string. */ - - while (*str != '\0') { - /* Segment changeover. */ - - if (*str == '.') { - /* Must have some digits in segment. */ - if (chcnt == 0) - return 0; - /* Limit number of segments. */ - if (++segs == 4) - return 0; - /* Reset segment values and restart loop. */ - chcnt = accum = 0; - str++; - continue; - } - - /* Check numeric. */ - if ((*str < '0') || (*str > '9')) - return 0; - - /* Accumulate and check segment. */ - - if ((accum = accum * 10 + *str - '0') > 255) - return 0; - /* Advance other segment specific stuff and continue loop. */ - - chcnt++; - str++; - } + uint8_t segs = 0; /* Segment count. */ + uint8_t chcnt = 0; /* Character count within segment. */ + uint8_t accum = 0; /* Accumulator for segment. */ + /* Catch NULL pointer. */ + if (str == 0) + return 0; + /* Process every character in string. */ - /* Check enough segments and enough characters in last segment. */ + while (*str != '\0') { + /* Segment changeover. */ - if (segs != 3) + if (*str == '.') { + /* Must have some digits in segment. */ + if (chcnt == 0) return 0; - if (chcnt == 0) + /* Limit number of segments. */ + if (++segs == 4) return 0; - /* Address okay. */ + /* Reset segment values and restart loop. */ + chcnt = accum = 0; + str++; + continue; + } + + /* Check numeric. */ + if ((*str < '0') || (*str > '9')) + return 0; + + /* Accumulate and check segment. */ + + if ((accum = accum * 10 + *str - '0') > 255) + return 0; + /* Advance other segment specific stuff and continue loop. */ + + chcnt++; + str++; + } + + /* Check enough segments and enough characters in last segment. */ + + if (segs != 3) + return 0; + if (chcnt == 0) + return 0; + /* Address okay. */ - return 1; + return 1; } -uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* 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; - } - } - if (n >= 256) { - return 0; - } - ((uint8_t*)ip)[i] = n; - } - return 1; +uint8_t ICACHE_FLASH_ATTR +UTILS_StrToIP(const int8_t* str, void *ip) +{ + /* The count of the number of bytes processed. */ + int i; + /* A pointer to the next digit to process. */ + for (i = 0; i < 4; i++) { + /* The digit being processed. */ + char c; + /* The value of this byte. */ + int n = 0; + while (1) { + c = *(const char *)str; + (const char *)str++; + 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; + } + } + if (n >= 256) { + return 0; + } + ((uint8_t*)ip)[i] = n; + } + return 1; } -uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s) + +uint32_t ICACHE_FLASH_ATTR +UTILS_Atoh(const int8_t *s) { - uint32_t value = 0, digit; - int8_t c; - - while((c = *s++)){ - if('0' <= c && c <= '9') - digit = c - '0'; - else if('A' <= c && c <= 'F') - digit = c - 'A' + 10; - else if('a' <= c && c<= 'f') - digit = c - 'a' + 10; - else break; - - value = (value << 4) | digit; - } - - return value; + uint32_t value = 0, digit; + int8_t c; + + while ((c = *s++)){ + if ('0' <= c && c <= '9') + digit = c - '0'; + else if ('A' <= c && c <= 'F') + digit = c - 'A' + 10; + else if ('a' <= c && c <= 'f') + digit = c - 'a' + 10; + else break; + + value = (value << 4) | digit; + } + + return value; } From c2e60809f6155aa260eb1be58141cac8c382e195 Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Sat, 29 Aug 2015 11:29:40 -0500 Subject: [PATCH 3/8] more mqtt work --- cmd/handlers.c | 15 +- cmd/mqtt_cmd.c | 336 ++++++++++++++++++++++++++++++++++ cmd/mqtt_cmd.h | 22 +++ esp-link.vcxproj | 35 +++- include/esp8266.h | 4 +- mqtt/include/proto.h | 31 ---- mqtt/include/ringbuf.h | 18 -- mqtt/include/typedef.h | 17 -- mqtt/include/utils.h | 9 - mqtt/mqtt.c | 190 ++++++++++--------- mqtt/{include => }/mqtt.h | 112 ++++++------ mqtt/mqtt_msg.c | 217 ++++++++++------------ mqtt/{include => }/mqtt_msg.h | 66 +++---- mqtt/proto.c | 182 +++++++----------- mqtt/proto.h | 28 +++ mqtt/queue.c | 15 +- mqtt/{include => }/queue.h | 13 +- mqtt/ringbuf.c | 82 ++++----- mqtt/ringbuf.h | 17 ++ mqtt/utils.c | 18 +- mqtt/utils.h | 9 + user/user_main.c | 186 +++++++++---------- 22 files changed, 947 insertions(+), 675 deletions(-) create mode 100644 cmd/mqtt_cmd.c create mode 100644 cmd/mqtt_cmd.h delete mode 100644 mqtt/include/proto.h delete mode 100644 mqtt/include/ringbuf.h delete mode 100644 mqtt/include/typedef.h delete mode 100644 mqtt/include/utils.h rename mqtt/{include => }/mqtt.h (60%) rename mqtt/{include => }/mqtt_msg.h (86%) create mode 100644 mqtt/proto.h rename mqtt/{include => }/queue.h (86%) create mode 100644 mqtt/ringbuf.h create mode 100644 mqtt/utils.h diff --git a/cmd/handlers.c b/cmd/handlers.c index 28382dd..ae21bec 100644 --- a/cmd/handlers.c +++ b/cmd/handlers.c @@ -9,6 +9,7 @@ #include "serbridge.h" #include "uart.h" #include "cgiwifi.h" +#include "mqtt_cmd.h" static uint32_t ICACHE_FLASH_ATTR CMD_Null(CmdPacket *cmd); static uint32_t ICACHE_FLASH_ATTR CMD_IsReady(CmdPacket *cmd); @@ -24,14 +25,12 @@ const CmdList commands[] = { {CMD_IS_READY, CMD_IsReady}, {CMD_WIFI_CONNECT, CMD_WifiConnect}, -/* - {CMD_MQTT_SETUP, MQTTAPP_Setup}, - {CMD_MQTT_CONNECT, MQTTAPP_Connect}, - {CMD_MQTT_DISCONNECT, MQTTAPP_Disconnect}, - {CMD_MQTT_PUBLISH, MQTTAPP_Publish}, - {CMD_MQTT_SUBSCRIBE , MQTTAPP_Subscribe}, - {CMD_MQTT_LWT, MQTTAPP_Lwt}, - */ + {CMD_MQTT_SETUP, MQTTCMD_Setup}, + {CMD_MQTT_CONNECT, MQTTCMD_Connect}, + {CMD_MQTT_DISCONNECT, MQTTCMD_Disconnect}, + {CMD_MQTT_PUBLISH, MQTTCMD_Publish}, + {CMD_MQTT_SUBSCRIBE , MQTTCMD_Subscribe}, + {CMD_MQTT_LWT, MQTTCMD_Lwt}, {CMD_REST_SETUP, REST_Setup}, {CMD_REST_REQUEST, REST_Request}, diff --git a/cmd/mqtt_cmd.c b/cmd/mqtt_cmd.c new file mode 100644 index 0000000..d12ba21 --- /dev/null +++ b/cmd/mqtt_cmd.c @@ -0,0 +1,336 @@ +#include "mqtt_cmd.h" + +uint32_t connectedCb = 0, disconnectCb = 0, publishedCb = 0, dataCb = 0; + +void ICACHE_FLASH_ATTR +mqttConnectedCb(uint32_t* args) { + MQTT_Client* client = (MQTT_Client*)args; + MqttCmdCb* cb = (MqttCmdCb*)client->user_data; + os_printf("MQTT: Connected connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n", + (void*)cb->connectedCb, + (void*)cb->disconnectedCb, + (void*)cb->publishedCb, + (void*)cb->dataCb); + uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->connectedCb, 0, 0); + CMD_ResponseEnd(crc); +} + +void ICACHE_FLASH_ATTR +mqttTcpDisconnectedCb(uint32_t *args) { + MQTT_Client* client = (MQTT_Client*)args; + MqttCmdCb *cb = (MqttCmdCb*)client->user_data; + os_printf("MQTT: TCP Disconnected\n"); + uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0); + CMD_ResponseEnd(crc); +} + +void ICACHE_FLASH_ATTR +mqttDisconnectedCb(uint32_t* args) { + MQTT_Client* client = (MQTT_Client*)args; + MqttCmdCb* cb = (MqttCmdCb*)client->user_data; + os_printf("MQTT: Disconnected\n"); + uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0); + CMD_ResponseEnd(crc); +} + +void ICACHE_FLASH_ATTR +mqttPublishedCb(uint32_t* args) { + MQTT_Client* client = (MQTT_Client*)args; + MqttCmdCb* cb = (MqttCmdCb*)client->user_data; + os_printf("MQTT: Published\n"); + uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0); + CMD_ResponseEnd(crc); +} + +void ICACHE_FLASH_ATTR +mqttDataCb(uint32_t* args, const char* topic, uint32_t topic_len, const char* data, uint32_t data_len) { + uint16_t crc = 0; + MQTT_Client* client = (MQTT_Client*)args; + MqttCmdCb* cb = (MqttCmdCb*)client->user_data; + + crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->dataCb, 0, 2); + crc = CMD_ResponseBody(crc, (uint8_t*)topic, topic_len); + crc = CMD_ResponseBody(crc, (uint8_t*)data, data_len); + CMD_ResponseEnd(crc); +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Setup(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 9) + return 0; + + // create mqtt client + uint8_t clientLen = sizeof(MQTT_Client); + MQTT_Client* client = (MQTT_Client*)os_zalloc(clientLen); + if (client == NULL) + return 0; + os_memset(client, 0, clientLen); + + uint16_t len; + uint8_t *client_id, *user_data, *pass_data; + uint32_t keepalive, clean_session, cb_data; + + // get client id + len = CMD_ArgLen(&req); + if (len > 32) return 0; // safety check + client_id = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, client_id, len); + client_id[len] = 0; + + // get username + len = CMD_ArgLen(&req); + if (len > 32) return 0; // safety check + user_data = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, user_data, len); + user_data[len] = 0; + + // get password + len = CMD_ArgLen(&req); + if (len > 32) return 0; // safety check + pass_data = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, pass_data, len); + pass_data[len] = 0; + + // get keepalive + CMD_PopArg(&req, (uint8_t*)&keepalive, 4); + + // get clean session + CMD_PopArg(&req, (uint8_t*)&clean_session, 4); + + os_printf("MQTT: MQTTCMD_Setup clientid=%s, user=%s, pw=%s, keepalive=%ld, clean_session=%ld\n", client_id, user_data, pass_data, keepalive, clean_session); + + // init client + // TODO: why malloc these all here, pass to MQTT_InitClient to be malloc'd again? + MQTT_InitClient(client, client_id, user_data, pass_data, keepalive, clean_session); + + // create callback + MqttCmdCb* callback = (MqttCmdCb*)os_zalloc(sizeof(MqttCmdCb)); + + CMD_PopArg(&req, (uint8_t*)&cb_data, 4); + callback->connectedCb = cb_data; + CMD_PopArg(&req, (uint8_t*)&cb_data, 4); + callback->disconnectedCb = cb_data; + CMD_PopArg(&req, (uint8_t*)&cb_data, 4); + callback->publishedCb = cb_data; + CMD_PopArg(&req, (uint8_t*)&cb_data, 4); + callback->dataCb = cb_data; + + client->user_data = callback; + + client->cmdConnectedCb = mqttConnectedCb; + client->cmdDisconnectedCb = mqttDisconnectedCb; + client->cmdPublishedCb = mqttPublishedCb; + client->cmdDataCb = mqttDataCb; + + if (CMD_GetArgc(&req) == 10) { + CMD_PopArg(&req, (uint8_t*)&cb_data, 4); + callback->tcpDisconnectedCb = cb_data; + client->cmdTcpDisconnectedCb = mqttTcpDisconnectedCb; + } + + os_free(client_id); + os_free(user_data); + os_free(pass_data); + + return (uint32_t)client; +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Lwt(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 5) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); + MQTT_Client* client = (MQTT_Client*)client_ptr; + os_printf("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr); + + uint16_t len; + + // get topic + if (client->connect_info.will_topic) + os_free(client->connect_info.will_topic); + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + client->connect_info.will_topic = (char*)os_zalloc(len + 1); + CMD_PopArg(&req, client->connect_info.will_topic, len); + client->connect_info.will_topic[len] = 0; + + // get message + if (client->connect_info.will_message) + os_free(client->connect_info.will_message); + len = CMD_ArgLen(&req); + // TODO: safety check + client->connect_info.will_message = (char*)os_zalloc(len + 1); + CMD_PopArg(&req, client->connect_info.will_message, len); + client->connect_info.will_message[len] = 0; + + // get qos + CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_qos, 4); + + // get retain + CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); + + os_printf("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%ld, retain=%ld\n", + client->connect_info.will_topic, + client->connect_info.will_message, + client->connect_info.will_qos, + client->connect_info.will_retain); + return 1; +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Connect(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 4) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); + MQTT_Client* client = (MQTT_Client*)client_ptr; + os_printf("MQTT: MQTTCMD_Connect client ptr=%p\n", (void*)client_ptr); + + uint16_t len; + + // get host + if (client->host) + os_free(client->host); + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + client->host = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, client->host, len); + client->host[len] = 0; + + // get port + CMD_PopArg(&req, (uint8_t*)&client->port, 4); + + // get security + CMD_PopArg(&req, (uint8_t*)&client->security, 4); + + os_printf("MQTT: MQTTCMD_Connect host=%s, port=%ld, security=%ld\n", + client->host, + client->port, + client->security); + + MQTT_Connect(client); + return 1; +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Disconnect(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 1) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); + MQTT_Client* client = (MQTT_Client*)client_ptr; + os_printf("MQTT: MQTTCMD_Disconnect client ptr=%p\n", (void*)client_ptr); + + // disconnect + MQTT_Disconnect(client); + return 1; +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Publish(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 6) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); + MQTT_Client* client = (MQTT_Client*)client_ptr; + os_printf("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr); + + uint16_t len; + uint8_t *topic, *data; + uint32_t qos = 0, retain = 0, data_len; + + // get topic + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + topic = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, topic, len); + topic[len] = 0; + + // get data + len = CMD_ArgLen(&req); + // TODO: Safety check + // TODO: this was orignially zalloc len not len+1 + data = (uint8_t*)os_zalloc(len+1); + CMD_PopArg(&req, data, len); + // TODO: next line not originally present + data[len] = 0; + + // get data length + // TODO: this isn't used but we have to pull it off the stack + CMD_PopArg(&req, (uint8_t*)&data_len, 4); + + // get qos + CMD_PopArg(&req, (uint8_t*)&qos, 4); + + // get retain + CMD_PopArg(&req, (uint8_t*)&retain, 4); + + os_printf("MQTT: MQTTCMD_Publish topic=%s, data_len=%d, qos=%ld, retain=%ld\n", + topic, + os_strlen((char*)data), + qos, + retain); + + MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain); + os_free(topic); + os_free(data); + return 1; +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Subscribe(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 3) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); + MQTT_Client* client = (MQTT_Client*)client_ptr; + os_printf("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr); + + uint16_t len; + uint8_t* topic; + uint32_t qos = 0; + + // get topic + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + topic = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, topic, len); + topic[len] = 0; + + // get qos + CMD_PopArg(&req, (uint8_t*)&qos, 4); + + os_printf("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos); + MQTT_Subscribe(client, (char*)topic, (uint8_t)qos); + os_free(topic); + return 1; +} diff --git a/cmd/mqtt_cmd.h b/cmd/mqtt_cmd.h new file mode 100644 index 0000000..66fd8f6 --- /dev/null +++ b/cmd/mqtt_cmd.h @@ -0,0 +1,22 @@ +#ifndef MODULES_MQTT_CMD_H_ +#define MODULES_MQTT_CMD_H_ + +#include "cmd.h" +#include "mqtt.h" + +typedef struct { + uint32_t connectedCb; + uint32_t disconnectedCb; + uint32_t publishedCb; + uint32_t dataCb; + uint32_t tcpDisconnectedCb; +} MqttCmdCb; + +uint32_t ICACHE_FLASH_ATTR MQTTCMD_Connect(CmdPacket *cmd); +uint32_t ICACHE_FLASH_ATTR MQTTCMD_Disconnect(CmdPacket *cmd); +uint32_t ICACHE_FLASH_ATTR MQTTCMD_Setup(CmdPacket *cmd); +uint32_t ICACHE_FLASH_ATTR MQTTCMD_Publish(CmdPacket *cmd); +uint32_t ICACHE_FLASH_ATTR MQTTCMD_Subscribe(CmdPacket *cmd); +uint32_t ICACHE_FLASH_ATTR MQTTCMD_Lwt(CmdPacket *cmd); + +#endif /* MODULES_MQTT_CMD_H_ */ diff --git a/esp-link.vcxproj b/esp-link.vcxproj index eac1d5b..ce508d0 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -28,7 +28,7 @@ __ets__;_STDINT_H;ICACHE_FLASH;__MINGW32__;__WIN32__ - .\mqtt\include;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include + .\mqtt;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include @@ -65,6 +65,7 @@ + @@ -87,6 +88,15 @@ + + + + + + + + + @@ -95,10 +105,10 @@ - + @@ -112,18 +122,25 @@ - - - - - - - + + + + + + + + + + + + + + diff --git a/include/esp8266.h b/include/esp8266.h index 96a7364..535dfeb 100644 --- a/include/esp8266.h +++ b/include/esp8266.h @@ -1,5 +1,5 @@ // Combined include file for esp8266 - +#include #include #include #include @@ -17,6 +17,8 @@ #include "espmissingincludes.h" #include "uart_hw.h" +//void init(void); + #ifdef __WIN32__ #include <_mingw.h> #endif diff --git a/mqtt/include/proto.h b/mqtt/include/proto.h deleted file mode 100644 index 73a4e8b..0000000 --- a/mqtt/include/proto.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * File: proto.h - * Author: ThuHien - * - * Created on November 23, 2012, 8:57 AM - */ - -#ifndef _PROTO_H_ -#define _PROTO_H_ -#include -#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 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, uint8_t *buf, uint16_t bufSize); -int8_t ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, uint8_t *buf, uint16_t len); -int16_t ICACHE_FLASH_ATTR PROTO_Add(uint8_t *buf, const uint8_t *packet, int16_t bufSize); -int16_t ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const uint8_t *packet, int16_t len); -int8_t ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, uint8_t value); -int16_t ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, uint8_t *bufOut, uint16_t* len, uint16_t maxBufLen); -#endif - diff --git a/mqtt/include/ringbuf.h b/mqtt/include/ringbuf.h deleted file mode 100644 index 03d780d..0000000 --- a/mqtt/include/ringbuf.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _RING_BUF_H_ -#define _RING_BUF_H_ - -#include -#include "typedef.h" - -typedef struct{ - U8* p_o; /**< Original pointer */ - U8* volatile p_r; /**< Read pointer */ - U8* volatile p_w; /**< Write pointer */ - volatile I32 fill_cnt; /**< Number of filled slots */ - I32 size; /**< Buffer size */ -}RINGBUF; - -I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size); -I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c); -I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c); -#endif diff --git a/mqtt/include/typedef.h b/mqtt/include/typedef.h deleted file mode 100644 index a4c69d6..0000000 --- a/mqtt/include/typedef.h +++ /dev/null @@ -1,17 +0,0 @@ -/** -* \file -* Standard Types definition -*/ - -#ifndef _TYPE_DEF_H_ -#define _TYPE_DEF_H_ - -typedef char I8; -typedef unsigned char U8; -typedef short I16; -typedef unsigned short U16; -typedef long I32; -typedef unsigned long U32; -typedef unsigned long long U64; - -#endif diff --git a/mqtt/include/utils.h b/mqtt/include/utils.h deleted file mode 100644 index 676501e..0000000 --- a/mqtt/include/utils.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _UTILS_H_ -#define _UTILS_H_ - -#include - -uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s); -uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip); -uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str); -#endif diff --git a/mqtt/mqtt.c b/mqtt/mqtt.c index 49ed507..9d435c8 100644 --- a/mqtt/mqtt.c +++ b/mqtt/mqtt.c @@ -33,41 +33,38 @@ #define MQTT_TASK_PRIO 0 #define MQTT_TASK_QUEUE_SIZE 1 -#define MQTT_SEND_TIMOUT 5 +#define MQTT_SEND_TIMOUT 5 #ifndef QUEUE_BUFFER_SIZE #define QUEUE_BUFFER_SIZE 2048 #endif -unsigned char *default_certificate; +unsigned char* default_certificate; unsigned int default_certificate_len = 0; -unsigned char *default_private_key; +unsigned char* default_private_key; unsigned int default_private_key_len = 0; os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE]; LOCAL void ICACHE_FLASH_ATTR -mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) -{ - struct espconn *pConn = (struct espconn *)arg; +mqtt_dns_found(const char* name, ip_addr_t* ipaddr, void* arg) { + struct espconn* pConn = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pConn->reverse; - if (ipaddr == NULL) - { + if (ipaddr == NULL) { os_printf("DNS: Found, but got no ip, try to reconnect\n"); client->connState = TCP_RECONNECT_REQ; return; } os_printf("DNS: found ip %d.%d.%d.%d\n", - *((uint8 *)&ipaddr->addr), - *((uint8 *)&ipaddr->addr + 1), - *((uint8 *)&ipaddr->addr + 2), - *((uint8 *)&ipaddr->addr + 3)); + *((uint8 *)&ipaddr->addr), + *((uint8 *)&ipaddr->addr + 1), + *((uint8 *)&ipaddr->addr + 2), + *((uint8 *)&ipaddr->addr + 3)); - if (client->ip.addr == 0 && ipaddr->addr != 0) - { + if (client->ip.addr == 0 && ipaddr->addr != 0) { os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); #ifdef CLIENT_SSL_ENABLE if (client->security){ @@ -75,7 +72,7 @@ mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) } else #endif - espconn_connect(client->pCon); + espconn_connect(client->pCon); client->connState = TCP_CONNECTING; os_printf("MQTT-TCP: connecting...\n"); @@ -85,10 +82,8 @@ mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) } - LOCAL void ICACHE_FLASH_ATTR -deliver_publish(MQTT_Client* client, uint8_t* message, int length) -{ +deliver_publish(MQTT_Client* client, uint8_t* message, uint16_t length) { mqtt_event_data_t event_data; event_data.topic_length = length; @@ -99,8 +94,10 @@ deliver_publish(MQTT_Client* client, uint8_t* message, int length) if (client->dataCb) client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length); -} + if (client->cmdDataCb) + client->cmdDataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length); +} /** * @brief Client received callback function. @@ -110,26 +107,25 @@ deliver_publish(MQTT_Client* client, uint8_t* message, int length) * @retval None */ void ICACHE_FLASH_ATTR -mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len) -{ +mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { uint8_t msg_type; uint8_t msg_qos; uint16_t msg_id; - struct espconn *pCon = (struct espconn*)arg; - MQTT_Client *client = (MQTT_Client *)pCon->reverse; + struct espconn* pCon = (struct espconn*)arg; + MQTT_Client* client = (MQTT_Client *)pCon->reverse; READPACKET: os_printf("MQTT-TCP: Data received %d bytes\n", len); - if (len < MQTT_BUF_SIZE && len > 0){ + if (len < MQTT_BUF_SIZE && len > 0) { os_memcpy(client->mqtt_state.in_buffer, pdata, len); msg_type = mqtt_get_type(client->mqtt_state.in_buffer); msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); if (client->connState == MQTT_CONNECT_SENDING) { - if (msg_type == MQTT_MSG_TYPE_CONNACK){ - if (client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT){ + if (msg_type == MQTT_MSG_TYPE_CONNACK) { + if (client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT) { os_printf("MQTT: Invalid packet\n"); #ifdef CLIENT_SSL_ENABLE if (client->security){ @@ -137,13 +133,15 @@ READPACKET: } else #endif - espconn_disconnect(client->pCon); + espconn_disconnect(client->pCon); } else { os_printf("MQTT: Connected to %s:%ld\n", client->host, client->port); client->connState = MQTT_DATA; if (client->connectedCb) client->connectedCb((uint32_t*)client); + if (client->cmdConnectedCb) + client->cmdConnectedCb((uint32_t*)client); } } } @@ -154,50 +152,50 @@ READPACKET: if (msg_type == MQTT_MSG_TYPE_SUBACK) { if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) - os_printf("MQTT: Subscribe successful\n"); + os_printf("MQTT: Subscribe successful\n"); } - else if (msg_type == MQTT_MSG_TYPE_UNSUBACK){ + else if (msg_type == MQTT_MSG_TYPE_UNSUBACK) { if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) - os_printf("MQTT: UnSubscribe successful\n"); + os_printf("MQTT: UnSubscribe successful\n"); } else if (msg_type == MQTT_MSG_TYPE_PUBLISH) { if (msg_qos == 1) client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); else if (msg_qos == 2) client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); - if (msg_qos == 1 || msg_qos == 2){ + if (msg_qos == 1 || msg_qos == 2) { os_printf("MQTT: Queue response QoS: %d\n", msg_qos); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { os_printf("MQTT: Queue full\n"); } } deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); } else if (msg_type == MQTT_MSG_TYPE_PUBACK) { - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){ + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) { os_printf("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\n"); } } else if (msg_type == MQTT_MSG_TYPE_PUBREC) { client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { os_printf("MQTT: Queue full\n"); } } else if (msg_type == MQTT_MSG_TYPE_PUBREL) { client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { os_printf("MQTT: Queue full\n"); } } else if (msg_type == MQTT_MSG_TYPE_PUBCOMP) { - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){ + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) { os_printf("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\n"); } } else if (msg_type == MQTT_MSG_TYPE_PINGREQ) { client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { os_printf("MQTT: Queue full\n"); } } @@ -205,12 +203,10 @@ READPACKET: // NOTE: this is done down here and not in the switch case above // because the PSOCK_READBUF_LEN() won't work inside a switch // statement due to the way protothreads resume. - if (msg_type == MQTT_MSG_TYPE_PUBLISH) - { + if (msg_type == MQTT_MSG_TYPE_PUBLISH) { len = client->mqtt_state.message_length_read; - if (client->mqtt_state.message_length < client->mqtt_state.message_length_read) - { + if (client->mqtt_state.message_length < client->mqtt_state.message_length_read) { //client->connState = MQTT_PUBLISH_RECV; //Not Implement yet len -= client->mqtt_state.message_length; @@ -234,26 +230,27 @@ READPACKET: * @retval None */ void ICACHE_FLASH_ATTR -mqtt_tcpclient_sent_cb(void *arg) -{ - struct espconn *pCon = (struct espconn *)arg; +mqtt_tcpclient_sent_cb(void* arg) { + struct espconn* pCon = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pCon->reverse; os_printf("MQTT-TCP: Sent\n"); client->sendTimeout = 0; - if (client->connState == MQTT_DATA && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH){ + if (client->connState == MQTT_DATA && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH) { if (client->publishedCb) client->publishedCb((uint32_t*)client); + if (client->cmdPublishedCb) + client->cmdPublishedCb((uint32_t*)client); } system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } -void ICACHE_FLASH_ATTR mqtt_timer(void *arg) -{ +void ICACHE_FLASH_ATTR +mqtt_timer(void* arg) { MQTT_Client* client = (MQTT_Client*)arg; - if (client->connState == MQTT_DATA){ + if (client->connState == MQTT_DATA) { client->keepAliveTick++; - if (client->keepAliveTick > client->mqtt_state.connect_info->keepalive){ + if (client->keepAliveTick > client->mqtt_state.connect_info->keepalive) { os_printf("\nMQTT: Send keepalive packet to %s:%ld!\n", client->host, client->port); client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); @@ -270,7 +267,7 @@ void ICACHE_FLASH_ATTR mqtt_timer(void *arg) } else #endif - espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->mqtt_state.outbound_message = NULL; @@ -279,11 +276,15 @@ void ICACHE_FLASH_ATTR mqtt_timer(void *arg) } } - else if (client->connState == TCP_RECONNECT_REQ){ + else if (client->connState == TCP_RECONNECT_REQ) { client->reconnectTick++; if (client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { client->reconnectTick = 0; client->connState = TCP_RECONNECT; + if (client->tcpDisconnectedCb) + client->tcpDisconnectedCb((uint32_t*)client); + if (client->cmdTcpDisconnectedCb) + client->cmdTcpDisconnectedCb((uint32_t*)client); system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } } @@ -292,15 +293,16 @@ void ICACHE_FLASH_ATTR mqtt_timer(void *arg) } void ICACHE_FLASH_ATTR -mqtt_tcpclient_discon_cb(void *arg) -{ +mqtt_tcpclient_discon_cb(void* arg) { - struct espconn *pespconn = (struct espconn *)arg; + struct espconn* pespconn = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pespconn->reverse; os_printf("MQTT-TCP: Disconnected callback\n"); client->connState = TCP_RECONNECT_REQ; if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client); + if (client->cmdDisconnectedCb) + client->cmdDisconnectedCb((uint32_t*)client); system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } @@ -311,9 +313,8 @@ mqtt_tcpclient_discon_cb(void *arg) * @retval None */ void ICACHE_FLASH_ATTR -mqtt_tcpclient_connect_cb(void *arg) -{ - struct espconn *pCon = (struct espconn *)arg; +mqtt_tcpclient_connect_cb(void* arg) { + struct espconn* pCon = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pCon->reverse; espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); @@ -335,7 +336,7 @@ mqtt_tcpclient_connect_cb(void *arg) } else #endif - espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->mqtt_state.outbound_message = NULL; client->connState = MQTT_CONNECT_SENDING; @@ -348,9 +349,8 @@ mqtt_tcpclient_connect_cb(void *arg) * @retval None */ void ICACHE_FLASH_ATTR -mqtt_tcpclient_recon_cb(void *arg, sint8 errType) -{ - struct espconn *pCon = (struct espconn *)arg; +mqtt_tcpclient_recon_cb(void* arg, int8_t errType) { + struct espconn* pCon = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pCon->reverse; os_printf("MQTT-TCP: Reconnect to %s:%ld\n", client->host, client->port); @@ -371,21 +371,20 @@ mqtt_tcpclient_recon_cb(void *arg, sint8 errType) * @retval TRUE if success queue */ bool ICACHE_FLASH_ATTR -MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int qos, int retain) -{ +MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t qos, uint8_t retain) { int data_length = os_strlen(data); uint8_t dataBuffer[MQTT_BUF_SIZE]; uint16_t dataLen; client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, - topic, data, data_length, - qos, retain, - &client->mqtt_state.pending_msg_id); - if (client->mqtt_state.outbound_message->length == 0){ + topic, data, data_length, + qos, retain, + &client->mqtt_state.pending_msg_id); + if (client->mqtt_state.outbound_message->length == 0) { os_printf("MQTT: Queuing Publish failed\n"); return FALSE; } os_printf("MQTT: Queuing Publish, length: %d, queue size(%ld/%ld)\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size); - while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { os_printf("MQTT: Queue full\n"); if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { os_printf("MQTT: Serious buffer error\n"); @@ -404,16 +403,15 @@ MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int qos, * @retval TRUE if success queue */ bool ICACHE_FLASH_ATTR -MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos) -{ +MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos) { uint8_t dataBuffer[MQTT_BUF_SIZE]; uint16_t dataLen; client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection, - topic, 0, - &client->mqtt_state.pending_msg_id); + topic, 0, + &client->mqtt_state.pending_msg_id); os_printf("MQTT: Queue Subscribe, topic: \"%s\", id: %d\n", topic, client->mqtt_state.pending_msg_id); - while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { os_printf("MQTT: Queue full\n"); if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { os_printf("MQTT: Serious buffer error\n"); @@ -424,7 +422,8 @@ MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos) return TRUE; } -void ICACHE_FLASH_ATTR MQTT_Task(os_event_t *e) { +void ICACHE_FLASH_ATTR +MQTT_Task(os_event_t* e) { MQTT_Client* client = (MQTT_Client*)e->par; uint8_t dataBuffer[MQTT_BUF_SIZE]; uint16_t dataLen; @@ -434,7 +433,7 @@ void ICACHE_FLASH_ATTR MQTT_Task(os_event_t *e) { if (client->connState == TCP_RECONNECT_REQ) { return; } - else if (client->connState == TCP_RECONNECT){ + else if (client->connState == TCP_RECONNECT) { MQTT_Connect(client); os_printf("MQTT-TCP: Reconnect to: %s:%ld\n", client->host, client->port); client->connState = TCP_CONNECTING; @@ -443,7 +442,7 @@ void ICACHE_FLASH_ATTR MQTT_Task(os_event_t *e) { if (QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) return; - if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0){ + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0) { client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer); client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen); client->sendTimeout = MQTT_SEND_TIMOUT; @@ -454,7 +453,7 @@ void ICACHE_FLASH_ATTR MQTT_Task(os_event_t *e) { } else #endif - espconn_sent(client->pCon, dataBuffer, dataLen); + espconn_sent(client->pCon, dataBuffer, dataLen); client->mqtt_state.outbound_message = NULL; return; @@ -472,8 +471,7 @@ void ICACHE_FLASH_ATTR MQTT_Task(os_event_t *e) { * @retval None */ void ICACHE_FLASH_ATTR -MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security) -{ +MQTT_InitConnection(MQTT_Client* mqttClient, uint8_t* host, uint32 port, uint8_t security) { uint32_t temp; os_printf("MQTT_InitConnection\n"); os_memset(mqttClient, 0, sizeof(MQTT_Client)); @@ -495,8 +493,7 @@ MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t * @retval None */ void ICACHE_FLASH_ATTR -MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) -{ +MQTT_InitClient(MQTT_Client* mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint8_t keepAliveTime, uint8_t cleanSession) { uint32_t temp; os_printf("MQTT_InitClient\n"); @@ -536,8 +533,7 @@ MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_use } void ICACHE_FLASH_ATTR -MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain) -{ +MQTT_InitLWT(MQTT_Client* mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain) { uint32_t temp; temp = os_strlen((char*)will_topic); mqttClient->connect_info.will_topic = (char*)os_zalloc(temp + 1); @@ -560,8 +556,7 @@ MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, ui * @retval None */ void ICACHE_FLASH_ATTR -MQTT_Connect(MQTT_Client *mqttClient) -{ +MQTT_Connect(MQTT_Client* mqttClient) { MQTT_Disconnect(mqttClient); mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn)); mqttClient->pCon->type = ESPCONN_TCP; @@ -589,7 +584,7 @@ MQTT_Connect(MQTT_Client *mqttClient) } else #endif - espconn_connect(mqttClient->pCon); + espconn_connect(mqttClient->pCon); } else { os_printf("MQTT-TCP: Connect to domain %s:%ld\n", mqttClient->host, mqttClient->port); @@ -599,12 +594,11 @@ MQTT_Connect(MQTT_Client *mqttClient) } void ICACHE_FLASH_ATTR -MQTT_Disconnect(MQTT_Client *mqttClient) -{ - if (mqttClient->pCon){ +MQTT_Disconnect(MQTT_Client* mqttClient) { + if (mqttClient->pCon) { os_printf("Free memory\n"); if (mqttClient->pCon->proto.tcp) - os_free(mqttClient->pCon->proto.tcp); + os_free(mqttClient->pCon->proto.tcp); os_free(mqttClient->pCon); mqttClient->pCon = NULL; } @@ -613,25 +607,27 @@ MQTT_Disconnect(MQTT_Client *mqttClient) } void ICACHE_FLASH_ATTR -MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb) -{ +MQTT_OnConnected(MQTT_Client* mqttClient, MqttCallback connectedCb) { mqttClient->connectedCb = connectedCb; } void ICACHE_FLASH_ATTR -MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb) -{ +MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb) { mqttClient->disconnectedCb = disconnectedCb; } void ICACHE_FLASH_ATTR -MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb) +MQTT_OnTcpDisconnected(MQTT_Client *mqttClient, MqttCallback tcpDisconnectedCb) { + mqttClient->tcpDisconnectedCb = tcpDisconnectedCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb) { mqttClient->dataCb = dataCb; } void ICACHE_FLASH_ATTR -MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb) -{ +MQTT_OnPublished(MQTT_Client* mqttClient, MqttCallback publishedCb) { mqttClient->publishedCb = publishedCb; } diff --git a/mqtt/include/mqtt.h b/mqtt/mqtt.h similarity index 60% rename from mqtt/include/mqtt.h rename to mqtt/mqtt.h index 52d21fe..d0fdfb5 100644 --- a/mqtt/include/mqtt.h +++ b/mqtt/mqtt.h @@ -35,8 +35,7 @@ #include "queue.h" #include "utils.h" -typedef struct mqtt_event_data_t -{ +typedef struct mqtt_event_data_t { uint8_t type; const char* topic; const char* data; @@ -45,8 +44,7 @@ typedef struct mqtt_event_data_t uint16_t data_offset; } mqtt_event_data_t; -typedef struct mqtt_state_t -{ +typedef struct mqtt_state_t { uint16_t port; int auto_reconnect; mqtt_connect_info_t* connect_info; @@ -64,48 +62,54 @@ typedef struct mqtt_state_t } mqtt_state_t; 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 + 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 } tConnState; -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); +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); -typedef struct { - struct espconn *pCon; - uint8_t security; - uint8_t* host; - uint32_t port; - ip_addr_t ip; - mqtt_state_t mqtt_state; - mqtt_connect_info_t connect_info; - MqttCallback connectedCb; - MqttCallback disconnectedCb; - MqttCallback publishedCb; - MqttDataCallback dataCb; - ETSTimer mqttTimer; - uint32_t keepAliveTick; - uint32_t reconnectTick; - uint32_t sendTimeout; - tConnState connState; - QUEUE msgQueue; - void* user_data; +typedef struct { + struct espconn* pCon; + uint32_t security; + uint8_t* host; + uint32_t port; + ip_addr_t ip; + mqtt_state_t mqtt_state; + mqtt_connect_info_t connect_info; + MqttCallback connectedCb; + MqttCallback cmdConnectedCb; + MqttCallback disconnectedCb; + MqttCallback cmdDisconnectedCb; + MqttCallback tcpDisconnectedCb; + MqttCallback cmdTcpDisconnectedCb; + MqttCallback publishedCb; + MqttCallback cmdPublishedCb; + MqttDataCallback dataCb; + MqttDataCallback cmdDataCb; + ETSTimer mqttTimer; + uint32_t keepAliveTick; + uint32_t reconnectTick; + uint32_t sendTimeout; + tConnState connState; + QUEUE msgQueue; + void* user_data; } MQTT_Client; #define SEC_NONSSL 0 @@ -125,16 +129,16 @@ typedef struct { #define MQTT_EVENT_TYPE_EXITED 7 #define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8 -void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security); -void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession); -void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain); -void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb); -void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb); -void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb); -void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb); -bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos); -void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient); -void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient); -bool ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int qos, int retain); +void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client* mqttClient, uint8_t* host, uint32 port, uint8_t security); +void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client* mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint8_t keepAliveTime, uint8_t cleanSession); +void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client* mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain); +void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client* mqttClient, MqttCallback connectedCb); +void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb); +void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client* mqttClient, MqttCallback publishedCb); +void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb); +bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos); +void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client* mqttClient); +void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client* mqttClient); +bool ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t qos, uint8_t retain); #endif /* USER_AT_MQTT_H_ */ diff --git a/mqtt/mqtt_msg.c b/mqtt/mqtt_msg.c index 77c777e..03da28e 100644 --- a/mqtt/mqtt_msg.c +++ b/mqtt/mqtt_msg.c @@ -32,8 +32,7 @@ #include "mqtt_msg.h" #define MQTT_MAX_FIXED_HEADER_SIZE 3 -enum mqtt_connect_flag -{ +enum mqtt_connect_flag { MQTT_CONNECT_FLAG_USERNAME = 1 << 7, MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, @@ -41,8 +40,8 @@ enum mqtt_connect_flag MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 }; -struct __attribute__((__packed__)) mqtt_connect_variable_header -{ +struct + __attribute__((__packed__)) mqtt_connect_variable_header { uint8_t lengthMsb; uint8_t lengthLsb; #if defined(PROTOCOL_NAMEv31) @@ -58,8 +57,8 @@ struct __attribute__((__packed__)) mqtt_connect_variable_header uint8_t keepaliveLsb; }; -static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len) -{ +static int ICACHE_FLASH_ATTR +append_string(mqtt_connection_t* connection, const char* string, int len) { if (connection->message.length + len + 2 > connection->buffer_length) return -1; @@ -71,8 +70,8 @@ static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const return len + 2; } -static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id) -{ +static uint16_t ICACHE_FLASH_ATTR +append_message_id(mqtt_connection_t* connection, uint16_t message_id) { // If message_id is zero then we should assign one, otherwise // we'll use the one supplied by the caller while (message_id == 0) @@ -87,33 +86,31 @@ static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connectio return message_id; } -static int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection) -{ +static int ICACHE_FLASH_ATTR +init_message(mqtt_connection_t* connection) { connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; return MQTT_MAX_FIXED_HEADER_SIZE; } -static mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection) -{ +static mqtt_message_t* ICACHE_FLASH_ATTR +fail_message(mqtt_connection_t* connection) { connection->message.data = connection->buffer; connection->message.length = 0; return &connection->message; } -static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) -{ +static mqtt_message_t* ICACHE_FLASH_ATTR +fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) { int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; - if (remaining_length > 127) - { + if (remaining_length > 127) { connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); connection->buffer[1] = 0x80 | (remaining_length % 128); connection->buffer[2] = remaining_length / 128; connection->message.length = remaining_length + 3; connection->message.data = connection->buffer; } - else - { + else { connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); connection->buffer[2] = remaining_length; connection->message.length = remaining_length + 2; @@ -131,16 +128,14 @@ mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_le connection->buffer_length = buffer_length; } -int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length) -{ +int ICACHE_FLASH_ATTR +mqtt_get_total_length(uint8_t* buffer, uint16_t length) { int i; int totlen = 0; - for (i = 1; i < length; ++i) - { + for (i = 1; i < length; ++i) { totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { + if ((buffer[i] & 0x80) == 0) { ++i; break; } @@ -150,17 +145,15 @@ int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length) return totlen; } -const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) -{ +const char* ICACHE_FLASH_ATTR +mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) { int i; int totlen = 0; int topiclen; - for (i = 1; i < *length; ++i) - { + for (i = 1; i < *length; ++i) { totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { + if ((buffer[i] & 0x80) == 0) { ++i; break; } @@ -179,17 +172,15 @@ const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* return (const char*)(buffer + i); } -const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) -{ +const char* ICACHE_FLASH_ATTR +mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) { int i; int totlen = 0; int topiclen; - for (i = 1; i < *length; ++i) - { + for (i = 1; i < *length; ++i) { totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { + if ((buffer[i] & 0x80) == 0) { ++i; break; } @@ -201,14 +192,13 @@ const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* l topiclen = buffer[i++] << 8; topiclen |= buffer[i++]; - if (i + topiclen >= *length){ + if (i + topiclen >= *length) { *length = 0; return NULL; } i += topiclen; - if (mqtt_get_qos(buffer) > 0) - { + if (mqtt_get_qos(buffer) > 0) { if (i + 2 >= *length) return NULL; i += 2; @@ -224,71 +214,65 @@ const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* l return (const char*)(buffer + i); } -uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length) -{ +uint16_t ICACHE_FLASH_ATTR +mqtt_get_id(uint8_t* buffer, uint16_t length) { if (length < 1) return 0; - switch (mqtt_get_type(buffer)) - { - case MQTT_MSG_TYPE_PUBLISH: - { - int i; - int topiclen; - - for (i = 1; i < length; ++i) - { - if ((buffer[i] & 0x80) == 0) - { - ++i; - break; + switch (mqtt_get_type(buffer)) { + case MQTT_MSG_TYPE_PUBLISH: { + int i; + int topiclen; + + for (i = 1; i < length; ++i) { + if ((buffer[i] & 0x80) == 0) { + ++i; + break; + } } - } - if (i + 2 >= length) - return 0; - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; + if (i + 2 >= length) + return 0; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; - if (i + topiclen >= length) - return 0; - i += topiclen; + if (i + topiclen >= length) + return 0; + i += topiclen; - if (mqtt_get_qos(buffer) > 0) - { - if (i + 2 >= length) + if (mqtt_get_qos(buffer) > 0) { + if (i + 2 >= length) + return 0; + //i += 2; + } + else { return 0; - //i += 2; + } + + return (buffer[i] << 8) | buffer[i + 1]; } - else { - return 0; + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_SUBSCRIBE: { + // This requires the remaining length to be encoded in 1 byte, + // which it should be. + if (length >= 4 && (buffer[1] & 0x80) == 0) + return (buffer[2] << 8) | buffer[3]; + else + return 0; } - return (buffer[i] << 8) | buffer[i + 1]; - } - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_PUBCOMP: - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: - case MQTT_MSG_TYPE_SUBSCRIBE: - { - // This requires the remaining length to be encoded in 1 byte, - // which it should be. - if (length >= 4 && (buffer[1] & 0x80) == 0) - return (buffer[2] << 8) | buffer[3]; - else + default: return 0; } - - default: - return 0; - } } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) { struct mqtt_connect_variable_header* variable_header; init_message(connection); @@ -318,16 +302,14 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection if (info->clean_session) variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; - if (info->client_id != NULL && info->client_id[0] != '\0') - { + if (info->client_id != NULL && info->client_id[0] != '\0') { if (append_string(connection, info->client_id, strlen(info->client_id)) < 0) return fail_message(connection); } else return fail_message(connection); - if (info->will_topic != NULL && info->will_topic[0] != '\0') - { + if (info->will_topic != NULL && info->will_topic[0] != '\0') { if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) return fail_message(connection); @@ -340,16 +322,14 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection variable_header->flags |= (info->will_qos & 3) << 3; } - if (info->username != NULL && info->username[0] != '\0') - { + if (info->username != NULL && info->username[0] != '\0') { if (append_string(connection, info->username, strlen(info->username)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; } - if (info->password != NULL && info->password[0] != '\0') - { + if (info->password != NULL && info->password[0] != '\0') { if (append_string(connection, info->password, strlen(info->password)) < 0) return fail_message(connection); @@ -359,8 +339,8 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR 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* ICACHE_FLASH_ATTR +mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) { init_message(connection); if (topic == NULL || topic[0] == '\0') @@ -369,8 +349,7 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection if (append_string(connection, topic, strlen(topic)) < 0) return fail_message(connection); - if (qos > 0) - { + if (qos > 0) { if ((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); } @@ -385,40 +364,40 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) { init_message(connection); if (append_message_id(connection, message_id) == 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) { init_message(connection); if (append_message_id(connection, message_id) == 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) { init_message(connection); if (append_message_id(connection, message_id) == 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) { init_message(connection); if (append_message_id(connection, message_id) == 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) { init_message(connection); if (topic == NULL || topic[0] == '\0') @@ -437,8 +416,8 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connecti return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) { init_message(connection); if (topic == NULL || topic[0] == '\0') @@ -453,20 +432,20 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connec return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_pingreq(mqtt_connection_t* connection) { init_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_pingresp(mqtt_connection_t* connection) { init_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); } -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection) -{ +mqtt_message_t* ICACHE_FLASH_ATTR +mqtt_msg_disconnect(mqtt_connection_t* connection) { init_message(connection); return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); } diff --git a/mqtt/include/mqtt_msg.h b/mqtt/mqtt_msg.h similarity index 86% rename from mqtt/include/mqtt_msg.h rename to mqtt/mqtt_msg.h index f16bb80..ce840b7 100644 --- a/mqtt/include/mqtt_msg.h +++ b/mqtt/mqtt_msg.h @@ -1,18 +1,3 @@ -/* - * File: mqtt_msg.h - * Author: Minh Tuan - * - * Created on July 12, 2014, 1:05 PM - */ - -#ifndef MQTT_MSG_H -#define MQTT_MSG_H -#include - -#ifdef __cplusplus -extern "C" { -#endif - /* * Copyright (c) 2014, Stephen Robinson * All rights reserved. @@ -43,12 +28,12 @@ extern "C" { * POSSIBILITY OF SUCH DAMAGE. * */ -/* 7 6 5 4 3 2 1 0*/ -/* | --- Message Type ---- | DUP Flag | QoS Level | Retain | Remaining Length | */ +#ifndef MQTT_MSG_H +#define MQTT_MSG_H +#include -enum mqtt_message_type -{ +enum mqtt_message_type { MQTT_MSG_TYPE_CONNECT = 1, MQTT_MSG_TYPE_CONNACK = 2, MQTT_MSG_TYPE_PUBLISH = 3, @@ -65,15 +50,13 @@ enum mqtt_message_type MQTT_MSG_TYPE_DISCONNECT = 14 }; -typedef struct mqtt_message -{ +typedef struct mqtt_message { uint8_t* data; uint16_t length; } mqtt_message_t; -typedef struct mqtt_connection -{ +typedef struct mqtt_connection { mqtt_message_t message; uint16_t message_id; @@ -82,25 +65,35 @@ typedef struct mqtt_connection } mqtt_connection_t; -typedef struct mqtt_connect_info -{ +typedef struct mqtt_connect_info { char* client_id; char* username; char* password; char* will_topic; char* will_message; - int keepalive; - int will_qos; - int will_retain; - int clean_session; + uint32_t keepalive; + uint32_t will_qos; + uint32_t will_retain; + uint32_t clean_session; } mqtt_connect_info_t; -static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; } -static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } -static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } -static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } +static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { + return (buffer[0] & 0xf0) >> 4; +} + +static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { + return (buffer[0] & 0x08) >> 3; +} + +static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { + return (buffer[0] & 0x06) >> 1; +} + +static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { + return (buffer[0] & 0x01); +} void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length); @@ -120,10 +113,5 @@ mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection); mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection); - -#ifdef __cplusplus -} -#endif - -#endif /* MQTT_MSG_H */ +#endif // MQTT_MSG_H diff --git a/mqtt/proto.c b/mqtt/proto.c index 3909b15..69b5367 100644 --- a/mqtt/proto.c +++ b/mqtt/proto.c @@ -1,128 +1,86 @@ #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_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; -} +int8_t ICACHE_FLASH_ATTR +PROTO_ParseByte(PROTO_PARSER* parser, uint8_t value) { + switch (value) { + case 0x7D: + parser->isEsc = 1; + break; -int8_t ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, uint8_t *buf, uint16_t len) -{ - while(len--) - PROTO_ParseByte(parser, *buf++); - return 0; -} -int16_t ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, uint8_t *bufOut, uint16_t* len, uint16_t maxBufLen) -{ - uint8_t c; + case 0x7E: + parser->dataLen = 0; + parser->isEsc = 0; + parser->isBegin = 1; + break; - 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_Add(uint8_t *buf, const uint8_t *packet, int16_t bufSize) -{ - uint16_t i = 2; - uint16_t len = *(uint16_t*) packet; + case 0x7F: + if (parser->callback != NULL) + parser->callback(); + parser->isBegin = 0; + return 0; + break; - if (bufSize < 1) return -1; + default: + if (parser->isBegin == 0) break; - *buf++ = 0x7E; - bufSize--; + if (parser->isEsc) { + value ^= 0x20; + parser->isEsc = 0; + } - while (len--) { - switch (*packet) { - case 0x7D: - case 0x7E: - case 0x7F: - if (bufSize < 2) return -1; - *buf++ = 0x7D; - *buf++ = *packet++ ^ 0x20; - i += 2; - bufSize -= 2; - break; - default: - if (bufSize < 1) return -1; - *buf++ = *packet++; - i++; - bufSize--; - break; - } - } + if (parser->dataLen < parser->bufSize) + parser->buf[parser->dataLen++] = value; - if (bufSize < 1) return -1; - *buf++ = 0x7F; + break; + } + return -1; +} + +int16_t ICACHE_FLASH_ATTR +PROTO_ParseRb(RINGBUF* rb, uint8_t* bufOut, uint16_t* len, uint16_t maxBufLen) { + uint8_t c; - return i; + 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; - } +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; + } + if (RINGBUF_Put(rb, 0x7F) == -1) return -1; - return i; + return i; } - diff --git a/mqtt/proto.h b/mqtt/proto.h new file mode 100644 index 0000000..8d20832 --- /dev/null +++ b/mqtt/proto.h @@ -0,0 +1,28 @@ +/* + * File: proto.h + * Author: ThuHien + * + * Created on November 23, 2012, 8:57 AM + */ + +#ifndef _PROTO_H_ +#define _PROTO_H_ +#include +#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 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER* parser, PROTO_PARSE_CALLBACK* completeCallback, uint8_t* buf, uint16_t bufSize); +int16_t ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF* rb, const uint8_t* packet, int16_t len); +int8_t ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER* parser, uint8_t value); +int16_t ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, uint8_t* bufOut, uint16_t* len, uint16_t maxBufLen); +#endif diff --git a/mqtt/queue.c b/mqtt/queue.c index 147015e..39c4790 100644 --- a/mqtt/queue.c +++ b/mqtt/queue.c @@ -29,22 +29,25 @@ */ #include "queue.h" -void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize) { +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) { +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) { - +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) { +bool ICACHE_FLASH_ATTR +QUEUE_IsEmpty(QUEUE* queue) { if (queue->rb.fill_cnt <= 0) return TRUE; return FALSE; -} \ No newline at end of file +} diff --git a/mqtt/include/queue.h b/mqtt/queue.h similarity index 86% rename from mqtt/include/queue.h rename to mqtt/queue.h index 7a84480..78b7882 100644 --- a/mqtt/include/queue.h +++ b/mqtt/queue.h @@ -33,13 +33,14 @@ #include #include "proto.h" #include "ringbuf.h" + typedef struct { - uint8_t *buf; - RINGBUF rb; + uint8_t* buf; + RINGBUF rb; } QUEUE; -void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize); -int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len); -int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen); -bool ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue); +void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE* queue, int bufferSize); +int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE* queue, uint8_t* buffer, uint16_t len); +int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE* queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen); +bool ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE* queue); #endif /* USER_QUEUE_H_ */ diff --git a/mqtt/ringbuf.c b/mqtt/ringbuf.c index 5ac3d07..a0cc782 100644 --- a/mqtt/ringbuf.c +++ b/mqtt/ringbuf.c @@ -1,11 +1,5 @@ -/** -* \file -* Ring Buffer library -*/ - #include "ringbuf.h" - /** * \brief init a RINGBUF object * \param r pointer to a RINGBUF object @@ -13,55 +7,57 @@ * \param size size of buf * \return 0 if successfull, otherwise failed */ -I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 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; +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 */ -I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 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; +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 */ -I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* 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; +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; } diff --git a/mqtt/ringbuf.h b/mqtt/ringbuf.h new file mode 100644 index 0000000..7d9f8e9 --- /dev/null +++ b/mqtt/ringbuf.h @@ -0,0 +1,17 @@ +#ifndef _RING_BUF_H_ +#define _RING_BUF_H_ + +#include + +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 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF* r, uint8_t* buf, int32_t size); +int16_t ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF* r, uint8_t c); +int16_t ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF* r, uint8_t* c); +#endif diff --git a/mqtt/utils.c b/mqtt/utils.c index 173b573..86aff20 100644 --- a/mqtt/utils.c +++ b/mqtt/utils.c @@ -33,11 +33,10 @@ #include "utils.h" uint8_t ICACHE_FLASH_ATTR -UTILS_IsIPV4(int8_t *str) -{ - uint8_t segs = 0; /* Segment count. */ - uint8_t chcnt = 0; /* Character count within segment. */ - uint8_t accum = 0; /* Accumulator for segment. */ +UTILS_IsIPV4(int8_t* str) { + uint8_t segs = 0; /* Segment count. */ + uint8_t chcnt = 0; /* Character count within segment. */ + uint8_t accum = 0; /* Accumulator for segment. */ /* Catch NULL pointer. */ if (str == 0) return 0; @@ -85,8 +84,7 @@ UTILS_IsIPV4(int8_t *str) } uint8_t ICACHE_FLASH_ATTR -UTILS_StrToIP(const int8_t* str, void *ip) -{ +UTILS_StrToIP(const int8_t* str, void* ip) { /* The count of the number of bytes processed. */ int i; @@ -122,12 +120,11 @@ UTILS_StrToIP(const int8_t* str, void *ip) } uint32_t ICACHE_FLASH_ATTR -UTILS_Atoh(const int8_t *s) -{ +UTILS_Atoh(const int8_t* s) { uint32_t value = 0, digit; int8_t c; - while ((c = *s++)){ + while ((c = *s++)) { if ('0' <= c && c <= '9') digit = c - '0'; else if ('A' <= c && c <= 'F') @@ -141,4 +138,3 @@ UTILS_Atoh(const int8_t *s) return value; } - diff --git a/mqtt/utils.h b/mqtt/utils.h new file mode 100644 index 0000000..bc4d2af --- /dev/null +++ b/mqtt/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include + +uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t* s); +uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void* ip); +uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4(int8_t* str); +#endif diff --git a/user/user_main.c b/user/user_main.c index cf6d266..db5db0f 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -1,13 +1,13 @@ /* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - * Heavily modified and enhanced by Thorsten von Eicken in 2015 - * ---------------------------------------------------------------------------- - */ +* ---------------------------------------------------------------------------- +* "THE BEER-WARE LICENSE" (Revision 42): +* Jeroen Domburg wrote this file. As long as you retain +* this notice you can do whatever you want with this stuff. If we meet some day, +* and you think this stuff is worth it, you can buy me a beer in return. +* ---------------------------------------------------------------------------- +* Heavily modified and enhanced by Thorsten von Eicken in 2015 +* ---------------------------------------------------------------------------- +*/ #include @@ -35,19 +35,20 @@ //This is disabled in the default build; if you want to try it, enable the authBasic line in //the builtInUrls below. int myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { - if (no==0) { - os_strcpy(user, "admin"); - os_strcpy(pass, "s3cr3t"); - return 1; -//Add more users this way. Check against incrementing no for each user added. -// } else if (no==1) { -// os_strcpy(user, "user1"); -// os_strcpy(pass, "something"); -// return 1; - } - return 0; + if (no == 0) { + os_strcpy(user, "admin"); + os_strcpy(pass, "s3cr3t"); + return 1; + //Add more users this way. Check against incrementing no for each user added. + // } else if (no==1) { + // os_strcpy(user, "user1"); + // os_strcpy(pass, "something"); + // return 1; + } + return 0; } + /* This is the main url->function dispatching data struct. In short, it's a struct with various URLs plus their handlers. The handlers can @@ -58,115 +59,110 @@ handled top-down, so make sure to put more specific rules above the more general ones. Authorization things (like authBasic) act as a 'barrier' and should be placed above the URLs they protect. */ -HttpdBuiltInUrl builtInUrls[]={ - {"/", cgiRedirect, "/home.html"}, - {"/menu", cgiMenu, NULL}, - {"/flash/next", cgiGetFirmwareNext, NULL}, - {"/flash/upload", cgiUploadFirmware, NULL}, - {"/flash/reboot", cgiRebootFirmware, NULL}, - //{"/home.html", cgiEspFsHtml, NULL}, - //{"/log.html", cgiEspFsHtml, NULL}, - {"/log/text", ajaxLog, NULL}, - {"/log/dbg", ajaxLogDbg, NULL}, - //{"/console.html", cgiEspFsHtml, NULL}, - {"/console/reset", ajaxConsoleReset, NULL}, - {"/console/baud", ajaxConsoleBaud, NULL}, - {"/console/text", ajaxConsole, NULL}, - - //Routines to make the /wifi URL and everything beneath it work. - -//Enable the line below to protect the WiFi configuration with an username/password combo. -// {"/wifi/*", authBasic, myPassFn}, - - {"/wifi", cgiRedirect, "/wifi/wifi.html"}, - {"/wifi/", cgiRedirect, "/wifi/wifi.html"}, - //{"/wifi/wifi.html", cgiEspFsHtml, NULL}, - {"/wifi/info", cgiWifiInfo, NULL}, - {"/wifi/scan", cgiWiFiScan, NULL}, - {"/wifi/connect", cgiWiFiConnect, NULL}, - {"/wifi/connstatus", cgiWiFiConnStatus, NULL}, - {"/wifi/setmode", cgiWiFiSetMode, NULL}, - {"/wifi/special", cgiWiFiSpecial, NULL}, - {"/pins", cgiPins, NULL}, - {"/tcpclient", cgiTcp, NULL}, - - {"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem - {NULL, NULL, NULL} +HttpdBuiltInUrl builtInUrls[] = { + { "/", cgiRedirect, "/home.html" }, + { "/menu", cgiMenu, NULL }, + { "/flash/next", cgiGetFirmwareNext, NULL }, + { "/flash/upload", cgiUploadFirmware, NULL }, + { "/flash/reboot", cgiRebootFirmware, NULL }, + //{"/home.html", cgiEspFsHtml, NULL}, + //{"/log.html", cgiEspFsHtml, NULL}, + { "/log/text", ajaxLog, NULL }, + { "/log/dbg", ajaxLogDbg, NULL }, + //{"/console.html", cgiEspFsHtml, NULL}, + { "/console/reset", ajaxConsoleReset, NULL }, + { "/console/baud", ajaxConsoleBaud, NULL }, + { "/console/text", ajaxConsole, NULL }, + + //Routines to make the /wifi URL and everything beneath it work. + + //Enable the line below to protect the WiFi configuration with an username/password combo. + // {"/wifi/*", authBasic, myPassFn}, + + { "/wifi", cgiRedirect, "/wifi/wifi.html" }, + { "/wifi/", cgiRedirect, "/wifi/wifi.html" }, + //{"/wifi/wifi.html", cgiEspFsHtml, NULL}, + { "/wifi/info", cgiWifiInfo, NULL }, + { "/wifi/scan", cgiWiFiScan, NULL }, + { "/wifi/connect", cgiWiFiConnect, NULL }, + { "/wifi/connstatus", cgiWiFiConnStatus, NULL }, + { "/wifi/setmode", cgiWiFiSetMode, NULL }, + { "/wifi/special", cgiWiFiSpecial, NULL }, + { "/pins", cgiPins, NULL }, + { "/tcpclient", cgiTcp, NULL }, + + { "*", cgiEspFsHook, NULL }, //Catch-all cgi function for the filesystem + { NULL, NULL, NULL } }; + //#define SHOW_HEAP_USE #ifdef SHOW_HEAP_USE static ETSTimer prHeapTimer; static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { - os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); + os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); } #endif +void user_rf_pre_init(void) { +} + +// address of espfs binary blob +extern uint32_t _binary_espfs_img_start; + +static char *rst_codes[] = { + "normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "external", +}; + # define VERS_STR_STR(V) #V # define VERS_STR(V) VERS_STR_STR(V) char *esp_link_version = VERS_STR(VERSION); -void user_rf_pre_init(void) { +//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. +void user_init(void) { // get the flash config so we know how to init things - //configWipe(); // uncomment to reset the config for testing purposes + //configWipe(); // uncomment to reset the config for testing purposes bool restoreOk = configRestore(); - // init gpio pin registers gpio_init(); - // init 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); os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); - // Status LEDs statusInit(); serledInit(); - + // Wifi + wifiInit(); + // init the flash filesystem with the html stuff + espFsInit(&_binary_espfs_img_start); + //EspFsInitResult res = espFsInit(&_binary_espfs_img_start); + //os_printf("espFsInit %s\n", res?"ERR":"ok"); + // mount the http handlers + httpdInit(builtInUrls, 80); + // init the wifi-serial transparent bridge (port 23) + serbridgeInit(23); + uart_add_recv_cb(&serbridgeUartCb); #ifdef SHOW_HEAP_USE os_timer_disarm(&prHeapTimer); os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL); os_timer_arm(&prHeapTimer, 10000, 1); #endif -} -// address of espfs binary blob -extern uint32_t _binary_espfs_img_start; + struct rst_info *rst_info = system_get_rst_info(); + os_printf("Reset cause: %d=%s\n", rst_info->reason, rst_codes[rst_info->reason]); + os_printf("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x\n", + rst_info->exccause, rst_info->epc1, rst_info->epc2, rst_info->epc3, + rst_info->excvaddr, rst_info->depc); + os_printf("Flash map %d, chip %08X\n", system_get_flash_size_map(), spi_flash_get_id()); -static char *rst_codes[] = { - "normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "external", -}; + os_printf("** esp-link ready\n"); -//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. -void user_init(void) { - // Wifi - wifiInit(); - - // init the flash filesystem with the html stuff - espFsInit(&_binary_espfs_img_start); - - //EspFsInitResult res = espFsInit(&_binary_espfs_img_start); - //os_printf("espFsInit %s\n", res?"ERR":"ok"); - - // mount the http handlers - httpdInit(builtInUrls, 80); - - // init the wifi-serial transparent bridge (port 23) - serbridgeInit(23); - uart_add_recv_cb(&serbridgeUartCb); - - struct rst_info *rst_info = system_get_rst_info(); - os_printf("Reset cause: %d=%s\n", rst_info->reason, rst_codes[rst_info->reason]); - os_printf("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x\n", - rst_info->exccause, rst_info->epc1, rst_info->epc2, rst_info->epc3, - rst_info->excvaddr, rst_info->depc); - os_printf("Flash map %d, chip %08X\n", system_get_flash_size_map(), spi_flash_get_id()); - - os_printf("** esp-link ready\n"); -} + // call user_main init +// init(); +} \ No newline at end of file From a2bb08186fd2095788fbc64a5aac6ccd65c352d9 Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Sat, 29 Aug 2015 11:40:08 -0500 Subject: [PATCH 4/8] Setup user code area and moved esp-link to it's own module --- Makefile | 2 +- esp-link.vcxproj | 1 + {user => esp-link}/cgi.c | 0 {user => esp-link}/cgi.h | 0 {user => esp-link}/cgiflash.c | 0 {user => esp-link}/cgiflash.h | 0 {user => esp-link}/cgipins.c | 0 {user => esp-link}/cgipins.h | 0 {user => esp-link}/cgitcp.c | 0 {user => esp-link}/cgitcp.h | 0 {user => esp-link}/cgiwifi.c | 0 {user => esp-link}/cgiwifi.h | 0 {user => esp-link}/config.c | 0 {user => esp-link}/config.h | 0 {user => esp-link}/log.c | 0 {user => esp-link}/log.h | 0 esp-link/main.c | 168 ++++++++++++++++++++++++++++++++++ {user => esp-link}/status.c | 0 {user => esp-link}/status.h | 0 include/esp8266.h | 2 +- include/user_config.h | 1 + user/user_main.c | 167 +-------------------------------- 22 files changed, 174 insertions(+), 167 deletions(-) rename {user => esp-link}/cgi.c (100%) rename {user => esp-link}/cgi.h (100%) rename {user => esp-link}/cgiflash.c (100%) rename {user => esp-link}/cgiflash.h (100%) rename {user => esp-link}/cgipins.c (100%) rename {user => esp-link}/cgipins.h (100%) rename {user => esp-link}/cgitcp.c (100%) rename {user => esp-link}/cgitcp.h (100%) rename {user => esp-link}/cgiwifi.c (100%) rename {user => esp-link}/cgiwifi.h (100%) rename {user => esp-link}/config.c (100%) rename {user => esp-link}/config.h (100%) rename {user => esp-link}/log.c (100%) rename {user => esp-link}/log.h (100%) create mode 100644 esp-link/main.c rename {user => esp-link}/status.c (100%) rename {user => esp-link}/status.h (100%) diff --git a/Makefile b/Makefile index 7969417..070a1f5 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ TARGET = httpd APPGEN_TOOL ?= gen_appbin.py # which modules (subdirectories) of the project to include in compiling -MODULES = espfs httpd user serial cmd mqtt +MODULES = espfs httpd user serial cmd mqtt esp-link EXTRA_INCDIR = include . # libraries used in this project, mainly provided by the SDK diff --git a/esp-link.vcxproj b/esp-link.vcxproj index ce508d0..760a8ef 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -105,6 +105,7 @@ + diff --git a/user/cgi.c b/esp-link/cgi.c similarity index 100% rename from user/cgi.c rename to esp-link/cgi.c diff --git a/user/cgi.h b/esp-link/cgi.h similarity index 100% rename from user/cgi.h rename to esp-link/cgi.h diff --git a/user/cgiflash.c b/esp-link/cgiflash.c similarity index 100% rename from user/cgiflash.c rename to esp-link/cgiflash.c diff --git a/user/cgiflash.h b/esp-link/cgiflash.h similarity index 100% rename from user/cgiflash.h rename to esp-link/cgiflash.h diff --git a/user/cgipins.c b/esp-link/cgipins.c similarity index 100% rename from user/cgipins.c rename to esp-link/cgipins.c diff --git a/user/cgipins.h b/esp-link/cgipins.h similarity index 100% rename from user/cgipins.h rename to esp-link/cgipins.h diff --git a/user/cgitcp.c b/esp-link/cgitcp.c similarity index 100% rename from user/cgitcp.c rename to esp-link/cgitcp.c diff --git a/user/cgitcp.h b/esp-link/cgitcp.h similarity index 100% rename from user/cgitcp.h rename to esp-link/cgitcp.h diff --git a/user/cgiwifi.c b/esp-link/cgiwifi.c similarity index 100% rename from user/cgiwifi.c rename to esp-link/cgiwifi.c diff --git a/user/cgiwifi.h b/esp-link/cgiwifi.h similarity index 100% rename from user/cgiwifi.h rename to esp-link/cgiwifi.h diff --git a/user/config.c b/esp-link/config.c similarity index 100% rename from user/config.c rename to esp-link/config.c diff --git a/user/config.h b/esp-link/config.h similarity index 100% rename from user/config.h rename to esp-link/config.h diff --git a/user/log.c b/esp-link/log.c similarity index 100% rename from user/log.c rename to esp-link/log.c diff --git a/user/log.h b/esp-link/log.h similarity index 100% rename from user/log.h rename to esp-link/log.h diff --git a/esp-link/main.c b/esp-link/main.c new file mode 100644 index 0000000..417a1b2 --- /dev/null +++ b/esp-link/main.c @@ -0,0 +1,168 @@ +/* +* ---------------------------------------------------------------------------- +* "THE BEER-WARE LICENSE" (Revision 42): +* Jeroen Domburg wrote this file. As long as you retain +* this notice you can do whatever you want with this stuff. If we meet some day, +* and you think this stuff is worth it, you can buy me a beer in return. +* ---------------------------------------------------------------------------- +* Heavily modified and enhanced by Thorsten von Eicken in 2015 +* ---------------------------------------------------------------------------- +*/ + + +#include +#include "httpd.h" +#include "httpdespfs.h" +#include "cgi.h" +#include "cgiwifi.h" +#include "cgipins.h" +#include "cgitcp.h" +#include "cgiflash.h" +#include "auth.h" +#include "espfs.h" +#include "uart.h" +#include "serbridge.h" +#include "status.h" +#include "serled.h" +#include "console.h" +#include "config.h" +#include "log.h" +#include + +//#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 +//the builtInUrls below. +int myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { + if (no == 0) { + os_strcpy(user, "admin"); + os_strcpy(pass, "s3cr3t"); + return 1; + //Add more users this way. Check against incrementing no for each user added. + // } else if (no==1) { + // os_strcpy(user, "user1"); + // os_strcpy(pass, "something"); + // return 1; + } + return 0; +} + + +/* +This is the main url->function dispatching data struct. +In short, it's a struct with various URLs plus their handlers. The handlers can +be 'standard' CGI functions you wrote, or 'special' CGIs requiring an argument. +They can also be auth-functions. An asterisk will match any url starting with +everything before the asterisks; "*" matches everything. The list will be +handled top-down, so make sure to put more specific rules above the more +general ones. Authorization things (like authBasic) act as a 'barrier' and +should be placed above the URLs they protect. +*/ +HttpdBuiltInUrl builtInUrls[] = { + { "/", cgiRedirect, "/home.html" }, + { "/menu", cgiMenu, NULL }, + { "/flash/next", cgiGetFirmwareNext, NULL }, + { "/flash/upload", cgiUploadFirmware, NULL }, + { "/flash/reboot", cgiRebootFirmware, NULL }, + //{"/home.html", cgiEspFsHtml, NULL}, + //{"/log.html", cgiEspFsHtml, NULL}, + { "/log/text", ajaxLog, NULL }, + { "/log/dbg", ajaxLogDbg, NULL }, + //{"/console.html", cgiEspFsHtml, NULL}, + { "/console/reset", ajaxConsoleReset, NULL }, + { "/console/baud", ajaxConsoleBaud, NULL }, + { "/console/text", ajaxConsole, NULL }, + + //Routines to make the /wifi URL and everything beneath it work. + + //Enable the line below to protect the WiFi configuration with an username/password combo. + // {"/wifi/*", authBasic, myPassFn}, + + { "/wifi", cgiRedirect, "/wifi/wifi.html" }, + { "/wifi/", cgiRedirect, "/wifi/wifi.html" }, + //{"/wifi/wifi.html", cgiEspFsHtml, NULL}, + { "/wifi/info", cgiWifiInfo, NULL }, + { "/wifi/scan", cgiWiFiScan, NULL }, + { "/wifi/connect", cgiWiFiConnect, NULL }, + { "/wifi/connstatus", cgiWiFiConnStatus, NULL }, + { "/wifi/setmode", cgiWiFiSetMode, NULL }, + { "/wifi/special", cgiWiFiSpecial, NULL }, + { "/pins", cgiPins, NULL }, + { "/tcpclient", cgiTcp, NULL }, + + { "*", cgiEspFsHook, NULL }, //Catch-all cgi function for the filesystem + { NULL, NULL, NULL } +}; + + +//#define SHOW_HEAP_USE + +#ifdef SHOW_HEAP_USE +static ETSTimer prHeapTimer; + +static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { + os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); +} +#endif + +void user_rf_pre_init(void) { +} + +// address of espfs binary blob +extern uint32_t _binary_espfs_img_start; + +static char *rst_codes[] = { + "normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "external", +}; + +# define VERS_STR_STR(V) #V +# 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. +void user_init(void) { + // 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(); + // init 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); + os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); + // Status LEDs + statusInit(); + serledInit(); + // Wifi + wifiInit(); + // init the flash filesystem with the html stuff + espFsInit(&_binary_espfs_img_start); + //EspFsInitResult res = espFsInit(&_binary_espfs_img_start); + //os_printf("espFsInit %s\n", res?"ERR":"ok"); + // mount the http handlers + httpdInit(builtInUrls, 80); + // init the wifi-serial transparent bridge (port 23) + serbridgeInit(23); + uart_add_recv_cb(&serbridgeUartCb); +#ifdef SHOW_HEAP_USE + os_timer_disarm(&prHeapTimer); + os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL); + os_timer_arm(&prHeapTimer, 10000, 1); +#endif + + struct rst_info *rst_info = system_get_rst_info(); + os_printf("Reset cause: %d=%s\n", rst_info->reason, rst_codes[rst_info->reason]); + os_printf("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x\n", + rst_info->exccause, rst_info->epc1, rst_info->epc2, rst_info->epc3, + rst_info->excvaddr, rst_info->depc); + os_printf("Flash map %d, chip %08X\n", system_get_flash_size_map(), spi_flash_get_id()); + + os_printf("** esp-link ready\n"); + + // call user_main init + init(); +} \ No newline at end of file diff --git a/user/status.c b/esp-link/status.c similarity index 100% rename from user/status.c rename to esp-link/status.c diff --git a/user/status.h b/esp-link/status.h similarity index 100% rename from user/status.h rename to esp-link/status.h diff --git a/include/esp8266.h b/include/esp8266.h index 535dfeb..d1f5cc4 100644 --- a/include/esp8266.h +++ b/include/esp8266.h @@ -17,7 +17,7 @@ #include "espmissingincludes.h" #include "uart_hw.h" -//void init(void); +void ICACHE_FLASH_ATTR init(void); #ifdef __WIN32__ #include <_mingw.h> diff --git a/include/user_config.h b/include/user_config.h index d38c637..16f7f9c 100644 --- a/include/user_config.h +++ b/include/user_config.h @@ -36,4 +36,5 @@ #define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/ //PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/ + #endif \ No newline at end of file diff --git a/user/user_main.c b/user/user_main.c index db5db0f..31e62a1 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -1,168 +1,5 @@ -/* -* ---------------------------------------------------------------------------- -* "THE BEER-WARE LICENSE" (Revision 42): -* Jeroen Domburg wrote this file. As long as you retain -* this notice you can do whatever you want with this stuff. If we meet some day, -* and you think this stuff is worth it, you can buy me a beer in return. -* ---------------------------------------------------------------------------- -* Heavily modified and enhanced by Thorsten von Eicken in 2015 -* ---------------------------------------------------------------------------- -*/ - - #include -#include "httpd.h" -#include "httpdespfs.h" -#include "cgi.h" -#include "cgiwifi.h" -#include "cgipins.h" -#include "cgitcp.h" -#include "cgiflash.h" -#include "auth.h" -#include "espfs.h" -#include "uart.h" -#include "serbridge.h" -#include "status.h" -#include "serled.h" -#include "console.h" -#include "config.h" -#include "log.h" -#include - -//#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 -//the builtInUrls below. -int myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { - if (no == 0) { - os_strcpy(user, "admin"); - os_strcpy(pass, "s3cr3t"); - return 1; - //Add more users this way. Check against incrementing no for each user added. - // } else if (no==1) { - // os_strcpy(user, "user1"); - // os_strcpy(pass, "something"); - // return 1; - } - return 0; -} - - -/* -This is the main url->function dispatching data struct. -In short, it's a struct with various URLs plus their handlers. The handlers can -be 'standard' CGI functions you wrote, or 'special' CGIs requiring an argument. -They can also be auth-functions. An asterisk will match any url starting with -everything before the asterisks; "*" matches everything. The list will be -handled top-down, so make sure to put more specific rules above the more -general ones. Authorization things (like authBasic) act as a 'barrier' and -should be placed above the URLs they protect. -*/ -HttpdBuiltInUrl builtInUrls[] = { - { "/", cgiRedirect, "/home.html" }, - { "/menu", cgiMenu, NULL }, - { "/flash/next", cgiGetFirmwareNext, NULL }, - { "/flash/upload", cgiUploadFirmware, NULL }, - { "/flash/reboot", cgiRebootFirmware, NULL }, - //{"/home.html", cgiEspFsHtml, NULL}, - //{"/log.html", cgiEspFsHtml, NULL}, - { "/log/text", ajaxLog, NULL }, - { "/log/dbg", ajaxLogDbg, NULL }, - //{"/console.html", cgiEspFsHtml, NULL}, - { "/console/reset", ajaxConsoleReset, NULL }, - { "/console/baud", ajaxConsoleBaud, NULL }, - { "/console/text", ajaxConsole, NULL }, - - //Routines to make the /wifi URL and everything beneath it work. - - //Enable the line below to protect the WiFi configuration with an username/password combo. - // {"/wifi/*", authBasic, myPassFn}, - - { "/wifi", cgiRedirect, "/wifi/wifi.html" }, - { "/wifi/", cgiRedirect, "/wifi/wifi.html" }, - //{"/wifi/wifi.html", cgiEspFsHtml, NULL}, - { "/wifi/info", cgiWifiInfo, NULL }, - { "/wifi/scan", cgiWiFiScan, NULL }, - { "/wifi/connect", cgiWiFiConnect, NULL }, - { "/wifi/connstatus", cgiWiFiConnStatus, NULL }, - { "/wifi/setmode", cgiWiFiSetMode, NULL }, - { "/wifi/special", cgiWiFiSpecial, NULL }, - { "/pins", cgiPins, NULL }, - { "/tcpclient", cgiTcp, NULL }, - - { "*", cgiEspFsHook, NULL }, //Catch-all cgi function for the filesystem - { NULL, NULL, NULL } -}; - - -//#define SHOW_HEAP_USE - -#ifdef SHOW_HEAP_USE -static ETSTimer prHeapTimer; - -static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { - os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); -} -#endif - -void user_rf_pre_init(void) { -} - -// address of espfs binary blob -extern uint32_t _binary_espfs_img_start; - -static char *rst_codes[] = { - "normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "external", -}; - -# define VERS_STR_STR(V) #V -# 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. -void user_init(void) { - // 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(); - // init 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); - os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); - // Status LEDs - statusInit(); - serledInit(); - // Wifi - wifiInit(); - // init the flash filesystem with the html stuff - espFsInit(&_binary_espfs_img_start); - //EspFsInitResult res = espFsInit(&_binary_espfs_img_start); - //os_printf("espFsInit %s\n", res?"ERR":"ok"); - // mount the http handlers - httpdInit(builtInUrls, 80); - // init the wifi-serial transparent bridge (port 23) - serbridgeInit(23); - uart_add_recv_cb(&serbridgeUartCb); -#ifdef SHOW_HEAP_USE - os_timer_disarm(&prHeapTimer); - os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL); - os_timer_arm(&prHeapTimer, 10000, 1); -#endif - - struct rst_info *rst_info = system_get_rst_info(); - os_printf("Reset cause: %d=%s\n", rst_info->reason, rst_codes[rst_info->reason]); - os_printf("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x\n", - rst_info->exccause, rst_info->epc1, rst_info->epc2, rst_info->epc3, - rst_info->excvaddr, rst_info->depc); - os_printf("Flash map %d, chip %08X\n", system_get_flash_size_map(), spi_flash_get_id()); - - os_printf("** esp-link ready\n"); - // call user_main init -// init(); +void init() { + } \ No newline at end of file From 36303a2b67dd6fe78519b54719c8f015717593c6 Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Sat, 29 Aug 2015 15:48:51 -0500 Subject: [PATCH 5/8] finished mqtt --- cmd/handlers.c | 6 +- cmd/mqtt_cmd.c | 30 ++++----- cmd/mqtt_cmd.h | 12 ++-- cmd/rest.c | 2 - cmd/rest.h | 1 + esp-link.vcxproj | 4 +- esp-link/cgiwifi.h | 4 +- esp-link/main.c | 2 +- httpd/httpdespfs.c | 11 ++-- httpd/httpdespfs.h | 6 +- include/esp8266.h | 1 + include/user_config.h | 42 ++++--------- mqtt/mqtt.c | 32 +++++----- mqtt/mqtt.h | 28 ++++----- mqtt/mqtt_msg.h | 40 ++++++------ mqtt/proto.h | 15 ++--- mqtt/queue.h | 8 +-- mqtt/ringbuf.h | 6 +- mqtt/utils.c | 140 ------------------------------------------ mqtt/utils.h | 9 --- user/user_main.c | 67 +++++++++++++++++++- 21 files changed, 181 insertions(+), 285 deletions(-) delete mode 100644 mqtt/utils.c delete mode 100644 mqtt/utils.h diff --git a/cmd/handlers.c b/cmd/handlers.c index ae21bec..d5359cb 100644 --- a/cmd/handlers.c +++ b/cmd/handlers.c @@ -17,6 +17,7 @@ static uint32_t ICACHE_FLASH_ATTR CMD_WifiConnect(CmdPacket *cmd); static uint32_t ICACHE_FLASH_ATTR CMD_AddSensor(CmdPacket *cmd); static uint8_t lastWifiStatus = wifiIsDisconnected; +static bool wifiCbAdded = false; // Command dispatch table for serial -> ESP commands const CmdList commands[] = { @@ -127,7 +128,10 @@ CMD_WifiConnect(CmdPacket *cmd) { if(cmd->argc != 2 || cmd->callback == 0) return 0; - wifiStatusCb = CMD_WifiCb; // register our callback with wifi subsystem + if (!wifiCbAdded) { + wifiAddStateChangeCb(CMD_WifiCb); // register our callback with wifi subsystem + wifiCbAdded = true; + } CMD_AddCb("wifiCb", (uint32_t)cmd->callback); // save the MCU's callback lastWifiStatus = wifiIsDisconnected; CMD_WifiCb(wifiState); diff --git a/cmd/mqtt_cmd.c b/cmd/mqtt_cmd.c index d12ba21..358ad48 100644 --- a/cmd/mqtt_cmd.c +++ b/cmd/mqtt_cmd.c @@ -1,9 +1,9 @@ #include "mqtt_cmd.h" -uint32_t connectedCb = 0, disconnectCb = 0, publishedCb = 0, dataCb = 0; +uint32_t connectedCb = 0, disconnectCb = 0, tcpDisconnectedCb = 0, publishedCb = 0, dataCb = 0; void ICACHE_FLASH_ATTR -mqttConnectedCb(uint32_t* args) { +cmdMqttConnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; os_printf("MQTT: Connected connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n", @@ -16,7 +16,7 @@ mqttConnectedCb(uint32_t* args) { } void ICACHE_FLASH_ATTR -mqttTcpDisconnectedCb(uint32_t *args) { +cmdMqttTcpDisconnectedCb(uint32_t *args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb *cb = (MqttCmdCb*)client->user_data; os_printf("MQTT: TCP Disconnected\n"); @@ -25,7 +25,7 @@ mqttTcpDisconnectedCb(uint32_t *args) { } void ICACHE_FLASH_ATTR -mqttDisconnectedCb(uint32_t* args) { +cmdMqttDisconnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; os_printf("MQTT: Disconnected\n"); @@ -34,7 +34,7 @@ mqttDisconnectedCb(uint32_t* args) { } void ICACHE_FLASH_ATTR -mqttPublishedCb(uint32_t* args) { +cmdMqttPublishedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; os_printf("MQTT: Published\n"); @@ -43,7 +43,7 @@ mqttPublishedCb(uint32_t* args) { } void ICACHE_FLASH_ATTR -mqttDataCb(uint32_t* args, const char* topic, uint32_t topic_len, const char* data, uint32_t data_len) { +cmdMqttDataCb(uint32_t* args, const char* topic, uint32_t topic_len, const char* data, uint32_t data_len) { uint16_t crc = 0; MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; @@ -104,7 +104,7 @@ MQTTCMD_Setup(CmdPacket *cmd) { // init client // TODO: why malloc these all here, pass to MQTT_InitClient to be malloc'd again? - MQTT_InitClient(client, client_id, user_data, pass_data, keepalive, clean_session); + MQTT_InitClient(client, (char*)client_id, (char*)user_data, (char*)pass_data, keepalive, clean_session); // create callback MqttCmdCb* callback = (MqttCmdCb*)os_zalloc(sizeof(MqttCmdCb)); @@ -120,15 +120,15 @@ MQTTCMD_Setup(CmdPacket *cmd) { client->user_data = callback; - client->cmdConnectedCb = mqttConnectedCb; - client->cmdDisconnectedCb = mqttDisconnectedCb; - client->cmdPublishedCb = mqttPublishedCb; - client->cmdDataCb = mqttDataCb; + client->cmdConnectedCb = cmdMqttConnectedCb; + client->cmdDisconnectedCb = cmdMqttDisconnectedCb; + client->cmdPublishedCb = cmdMqttPublishedCb; + client->cmdDataCb = cmdMqttDataCb; if (CMD_GetArgc(&req) == 10) { CMD_PopArg(&req, (uint8_t*)&cb_data, 4); callback->tcpDisconnectedCb = cb_data; - client->cmdTcpDisconnectedCb = mqttTcpDisconnectedCb; + client->cmdTcpDisconnectedCb = cmdMqttTcpDisconnectedCb; } os_free(client_id); @@ -178,7 +178,7 @@ MQTTCMD_Lwt(CmdPacket *cmd) { // get retain CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); - os_printf("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%ld, retain=%ld\n", + os_printf("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%d, retain=%d\n", client->connect_info.will_topic, client->connect_info.will_message, client->connect_info.will_qos, @@ -207,7 +207,7 @@ MQTTCMD_Connect(CmdPacket *cmd) { os_free(client->host); len = CMD_ArgLen(&req); if (len > 128) return 0; // safety check - client->host = (uint8_t*)os_zalloc(len + 1); + client->host = (char*)os_zalloc(len + 1); CMD_PopArg(&req, client->host, len); client->host[len] = 0; @@ -217,7 +217,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=%ld\n", + os_printf("MQTT: MQTTCMD_Connect host=%s, port=%ld, security=%d\n", client->host, client->port, client->security); diff --git a/cmd/mqtt_cmd.h b/cmd/mqtt_cmd.h index 66fd8f6..9ccbd08 100644 --- a/cmd/mqtt_cmd.h +++ b/cmd/mqtt_cmd.h @@ -12,11 +12,11 @@ typedef struct { uint32_t tcpDisconnectedCb; } MqttCmdCb; -uint32_t ICACHE_FLASH_ATTR MQTTCMD_Connect(CmdPacket *cmd); -uint32_t ICACHE_FLASH_ATTR MQTTCMD_Disconnect(CmdPacket *cmd); -uint32_t ICACHE_FLASH_ATTR MQTTCMD_Setup(CmdPacket *cmd); -uint32_t ICACHE_FLASH_ATTR MQTTCMD_Publish(CmdPacket *cmd); -uint32_t ICACHE_FLASH_ATTR MQTTCMD_Subscribe(CmdPacket *cmd); -uint32_t ICACHE_FLASH_ATTR MQTTCMD_Lwt(CmdPacket *cmd); +uint32_t MQTTCMD_Connect(CmdPacket *cmd); +uint32_t MQTTCMD_Disconnect(CmdPacket *cmd); +uint32_t MQTTCMD_Setup(CmdPacket *cmd); +uint32_t MQTTCMD_Publish(CmdPacket *cmd); +uint32_t MQTTCMD_Subscribe(CmdPacket *cmd); +uint32_t MQTTCMD_Lwt(CmdPacket *cmd); #endif /* MODULES_MQTT_CMD_H_ */ diff --git a/cmd/rest.c b/cmd/rest.c index 75b5b0b..3ae6575 100644 --- a/cmd/rest.c +++ b/cmd/rest.c @@ -16,8 +16,6 @@ static RestClient restClient[MAX_REST]; static uint8_t restNum = 0xff; // index into restClient for next slot to allocate #define REST_CB 0xbeef0000 // fudge added to callback for arduino so we can detect problems -extern uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const char* str, void *ip); - static void ICACHE_FLASH_ATTR tcpclient_discon_cb(void *arg) { struct espconn *pespconn = (struct espconn *)arg; diff --git a/cmd/rest.h b/cmd/rest.h index 7161e1f..9c6cd5c 100644 --- a/cmd/rest.h +++ b/cmd/rest.h @@ -36,5 +36,6 @@ typedef struct { uint32_t REST_Setup(CmdPacket *cmd); uint32_t REST_Request(CmdPacket *cmd); uint32_t REST_SetHeader(CmdPacket *cmd); +uint8_t UTILS_StrToIP(const char* str, void *ip); #endif /* MODULES_INCLUDE_API_H_ */ diff --git a/esp-link.vcxproj b/esp-link.vcxproj index 760a8ef..f371f1a 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -28,7 +28,7 @@ __ets__;_STDINT_H;ICACHE_FLASH;__MINGW32__;__WIN32__ - .\mqtt;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include + .\esp-link;.\mqtt;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include @@ -81,7 +81,6 @@ - @@ -128,7 +127,6 @@ - diff --git a/esp-link/cgiwifi.h b/esp-link/cgiwifi.h index d73628e..3f7fe09 100644 --- a/esp-link/cgiwifi.h +++ b/esp-link/cgiwifi.h @@ -4,6 +4,7 @@ #include "httpd.h" enum { wifiIsDisconnected, wifiIsConnected, wifiGotIP }; +typedef void(*WifiStateChangeCb)(uint8_t wifiStatus); int cgiWiFiScan(HttpdConnData *connData); int cgiWifiInfo(HttpdConnData *connData); @@ -13,8 +14,9 @@ int cgiWiFiSetMode(HttpdConnData *connData); int cgiWiFiConnStatus(HttpdConnData *connData); int cgiWiFiSpecial(HttpdConnData *connData); void wifiInit(void); +void wifiAddStateChangeCb(WifiStateChangeCb cb); extern uint8_t wifiState; -extern void (*wifiStatusCb)(uint8_t); // callback when wifi status changes +//extern void (*wifiStatusCb)(uint8_t); // callback when wifi status changes #endif diff --git a/esp-link/main.c b/esp-link/main.c index 417a1b2..5febf87 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -118,7 +118,7 @@ static char *rst_codes[] = { # define VERS_STR_STR(V) #V # define VERS_STR(V) VERS_STR_STR(V) -char *esp_link_version = VERS_STR(VERSION); +char* esp_link_version = VERS_STR(VERSION); //Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. void user_init(void) { diff --git a/httpd/httpdespfs.c b/httpd/httpdespfs.c index b6853aa..c6f2c0c 100644 --- a/httpd/httpdespfs.c +++ b/httpd/httpdespfs.c @@ -12,12 +12,7 @@ Connector to let httpd use the espfs filesystem to serve the files in it. * Modified and enhanced by Thorsten von Eicken in 2015 * ---------------------------------------------------------------------------- */ - -#include #include "httpdespfs.h" -#include "espfs.h" -#include "espfsformat.h" -#include "cgi.h" // The static files marked with FLAG_GZIP are compressed and will be served with GZIP compression. // If the client does not advertise that he accepts GZIP send following warning message (telnet users for e.g.) @@ -27,7 +22,8 @@ static const char *gzipNonSupportedMessage = "HTTP/1.0 501 Not implemented\r\nSe //This is a catch-all cgi function. It takes the url passed to it, looks up the corresponding //path in the filesystem and if it exists, passes the file through. This simulates what a normal //webserver would do with static files. -int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) { +int ICACHE_FLASH_ATTR +cgiEspFsHook(HttpdConnData *connData) { EspFsFile *file=connData->cgiData; int len; char buff[1024]; @@ -93,7 +89,8 @@ int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) { #if 0 //cgiEspFsHtml is a simple HTML file that gets prefixed by head.tpl -int ICACHE_FLASH_ATTR cgiEspFsHtml(HttpdConnData *connData) { +int ICACHE_FLASH_ATTR +cgiEspFsHtml(HttpdConnData *connData) { EspFsFile *file = connData->cgiData; char buff[2048]; diff --git a/httpd/httpdespfs.h b/httpd/httpdespfs.h index fb07008..847a8b6 100644 --- a/httpd/httpdespfs.h +++ b/httpd/httpdespfs.h @@ -1,10 +1,14 @@ #ifndef HTTPDESPFS_H #define HTTPDESPFS_H +#include +#include "espfs.h" +#include "espfsformat.h" +#include "cgi.h" #include "httpd.h" int cgiEspFsHook(HttpdConnData *connData); -int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData); +//int cgiEspFsTemplate(HttpdConnData *connData); //int ICACHE_FLASH_ATTR cgiEspFsHtml(HttpdConnData *connData); #endif diff --git a/include/esp8266.h b/include/esp8266.h index d1f5cc4..c3d0c40 100644 --- a/include/esp8266.h +++ b/include/esp8266.h @@ -16,6 +16,7 @@ #include "espmissingincludes.h" #include "uart_hw.h" +extern char* esp_link_version; void ICACHE_FLASH_ATTR init(void); diff --git a/include/user_config.h b/include/user_config.h index 16f7f9c..7bdfd38 100644 --- a/include/user_config.h +++ b/include/user_config.h @@ -1,40 +1,20 @@ #ifndef _USER_CONFIG_H_ #define _USER_CONFIG_H_ -/*DEFAULT CONFIGURATIONS*/ - -#define MQTT_HOST "mqtt.yourdomain.com" //or "mqtt.yourdomain.com" -#define MQTT_PORT 1883 +#define MQTT_RECONNECT_TIMEOUT 5 // seconds #define MQTT_BUF_SIZE 1024 -#define MQTT_KEEPALIVE 120 /*second*/ - -#define MQTT_CLIENT_ID "H_%08X" //Cuidar para não colocar valores execendentes da ESTRUTURA SYSCFG -#define MQTT_USER "DVES_USER" -#define MQTT_PASS "DVES_PASS" - -#define STA_SSID "TESTE" -#define STA_PASS "54545" -#define STA_TYPE AUTH_WPA2_PSK -#define MQTT_RECONNECT_TIMEOUT 5 /*second*/ - -#define DEFAULT_SECURITY 0 -#define QUEUE_BUFFER_SIZE 2048 - -//#undef MCU_RESET_PIN -//#undef MCU_ISP_PIN -//#undef LED_CONN_PIN -//#undef LED_SERIAL_PIN -// -//#define MCU_RESET_PIN 2 -//#define MCU_ISP_PIN -1 -//#define LED_CONN_PIN -1 -//#define LED_SERIAL_PIN -1 +#define MQTT_HOST "10.0.0.220" // "mqtt.yourdomain.com" or ip "10.0.0.1" +#define MQTT_PORT 1883 +#define MQTT_SECURITY 0 -//#define BAUD_RATE 9600 -//#define HOSTNAME "nodemcu\0 " +#define MQTT_CLIENT_ID "esp-link" // "" +#define MQTT_USER "" +#define MQTT_PASS "" +#define MQTT_KEEPALIVE 120 // seconds +#define MQTT_CLSESSION true -#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/ -//PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/ +#define PROTOCOL_NAMEv31 // MQTT version 3.1 compatible with Mosquitto v0.15 +//PROTOCOL_NAMEv311 // MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/ #endif \ No newline at end of file diff --git a/mqtt/mqtt.c b/mqtt/mqtt.c index 9d435c8..12b9514 100644 --- a/mqtt/mqtt.c +++ b/mqtt/mqtt.c @@ -471,14 +471,16 @@ MQTT_Task(os_event_t* e) { * @retval None */ void ICACHE_FLASH_ATTR -MQTT_InitConnection(MQTT_Client* mqttClient, uint8_t* host, uint32 port, uint8_t security) { - uint32_t temp; +MQTT_InitConnection(MQTT_Client* mqttClient, char* host, uint32 port, uint8_t security) { os_printf("MQTT_InitConnection\n"); - os_memset(mqttClient, 0, sizeof(MQTT_Client)); - temp = sizeof((char*)host); - mqttClient->host = (uint8_t*)os_zalloc(temp + 1); - os_strcpy((char*)mqttClient->host, (char*)host); + uint8_t len = sizeof(MQTT_Client); + os_memset(mqttClient, 0, len); + + uint32_t temp = os_strlen(host); + mqttClient->host = (char*)os_zalloc(temp + 1); + os_strcpy(mqttClient->host, host); mqttClient->host[temp] = 0; + mqttClient->port = port; mqttClient->security = security; } @@ -493,25 +495,25 @@ MQTT_InitConnection(MQTT_Client* mqttClient, uint8_t* host, uint32 port, uint8_t * @retval None */ void ICACHE_FLASH_ATTR -MQTT_InitClient(MQTT_Client* mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint8_t keepAliveTime, uint8_t cleanSession) { +MQTT_InitClient(MQTT_Client* mqttClient, char* client_id, char* client_user, char* client_pass, uint8_t keepAliveTime, uint8_t cleanSession) { uint32_t temp; os_printf("MQTT_InitClient\n"); os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); - temp = os_strlen((char*)client_id); + temp = os_strlen(client_id); mqttClient->connect_info.client_id = (char*)os_zalloc(temp + 1); - os_strcpy((char*)mqttClient->connect_info.client_id, (char*)client_id); + os_strcpy(mqttClient->connect_info.client_id, client_id); mqttClient->connect_info.client_id[temp] = 0; - temp = os_strlen((char*)client_user); + temp = os_strlen(client_user); mqttClient->connect_info.username = (char*)os_zalloc(temp + 1); - os_strcpy((char*)mqttClient->connect_info.username, (char*)client_user); + os_strcpy(mqttClient->connect_info.username, client_user); mqttClient->connect_info.username[temp] = 0; - temp = os_strlen((char*)client_pass); + temp = os_strlen(client_pass); mqttClient->connect_info.password = (char*)os_zalloc(temp + 1); - os_strcpy((char*)mqttClient->connect_info.password, (char*)client_pass); + os_strcpy(mqttClient->connect_info.password, client_pass); mqttClient->connect_info.password[temp] = 0; @@ -533,7 +535,7 @@ MQTT_InitClient(MQTT_Client* mqttClient, uint8_t* client_id, uint8_t* client_use } void ICACHE_FLASH_ATTR -MQTT_InitLWT(MQTT_Client* mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain) { +MQTT_InitLWT(MQTT_Client* mqttClient, char* will_topic, char* will_msg, uint8_t will_qos, uint8_t will_retain) { uint32_t temp; temp = os_strlen((char*)will_topic); mqttClient->connect_info.will_topic = (char*)os_zalloc(temp + 1); @@ -576,7 +578,7 @@ MQTT_Connect(MQTT_Client* mqttClient) { os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient); os_timer_arm(&mqttClient->mqttTimer, 1000, 1); - if (UTILS_StrToIP((const int8_t *)mqttClient->host, (void*)&mqttClient->pCon->proto.tcp->remote_ip)) { + if (UTILS_StrToIP((const char *)mqttClient->host, (void*)&mqttClient->pCon->proto.tcp->remote_ip)) { os_printf("MQTT-TCP: Connect to ip %s:%ld\n", mqttClient->host, mqttClient->port); #ifdef CLIENT_SSL_ENABLE if (mqttClient->security){ diff --git a/mqtt/mqtt.h b/mqtt/mqtt.h index d0fdfb5..9ad6825 100644 --- a/mqtt/mqtt.h +++ b/mqtt/mqtt.h @@ -33,7 +33,7 @@ #include #include "mqtt_msg.h" #include "queue.h" -#include "utils.h" +#include typedef struct mqtt_event_data_t { uint8_t type; @@ -87,8 +87,8 @@ typedef void (*MqttDataCallback)(uint32_t* args, const char* topic, uint32_t top typedef struct { struct espconn* pCon; - uint32_t security; - uint8_t* host; + uint8_t security; + char* host; uint32_t port; ip_addr_t ip; mqtt_state_t mqtt_state; @@ -129,16 +129,16 @@ typedef struct { #define MQTT_EVENT_TYPE_EXITED 7 #define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8 -void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client* mqttClient, uint8_t* host, uint32 port, uint8_t security); -void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client* mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint8_t keepAliveTime, uint8_t cleanSession); -void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client* mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain); -void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client* mqttClient, MqttCallback connectedCb); -void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb); -void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client* mqttClient, MqttCallback publishedCb); -void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb); -bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos); -void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client* mqttClient); -void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client* mqttClient); -bool ICACHE_FLASH_ATTR 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); +void MQTT_OnConnected(MQTT_Client* mqttClient, MqttCallback connectedCb); +void MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb); +void MQTT_OnPublished(MQTT_Client* mqttClient, MqttCallback publishedCb); +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_ */ diff --git a/mqtt/mqtt_msg.h b/mqtt/mqtt_msg.h index ce840b7..bf305df 100644 --- a/mqtt/mqtt_msg.h +++ b/mqtt/mqtt_msg.h @@ -72,9 +72,9 @@ typedef struct mqtt_connect_info { char* will_topic; char* will_message; uint32_t keepalive; - uint32_t will_qos; - uint32_t will_retain; - uint32_t clean_session; + uint8_t will_qos; + uint8_t will_retain; + uint8_t clean_session; } mqtt_connect_info_t; @@ -95,23 +95,23 @@ static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } -void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); -int ICACHE_FLASH_ATTR 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); -const char* ICACHE_FLASH_ATTR 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_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); -mqtt_message_t* ICACHE_FLASH_ATTR 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* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection); +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); + +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); +mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); +mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); +mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection); +mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection); +mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection); #endif // MQTT_MSG_H diff --git a/mqtt/proto.h b/mqtt/proto.h index 8d20832..67b3e26 100644 --- a/mqtt/proto.h +++ b/mqtt/proto.h @@ -1,10 +1,3 @@ -/* - * File: proto.h - * Author: ThuHien - * - * Created on November 23, 2012, 8:57 AM - */ - #ifndef _PROTO_H_ #define _PROTO_H_ #include @@ -21,8 +14,8 @@ typedef struct { PROTO_PARSE_CALLBACK* callback; } PROTO_PARSER; -int8_t ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER* parser, PROTO_PARSE_CALLBACK* completeCallback, uint8_t* buf, uint16_t bufSize); -int16_t ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF* rb, const uint8_t* packet, int16_t len); -int8_t ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER* parser, uint8_t value); -int16_t ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, uint8_t* bufOut, uint16_t* len, uint16_t maxBufLen); +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 diff --git a/mqtt/queue.h b/mqtt/queue.h index 78b7882..bdbc503 100644 --- a/mqtt/queue.h +++ b/mqtt/queue.h @@ -39,8 +39,8 @@ typedef struct { RINGBUF rb; } QUEUE; -void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE* queue, int bufferSize); -int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE* queue, uint8_t* buffer, uint16_t len); -int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE* queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen); -bool ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE* 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_ */ diff --git a/mqtt/ringbuf.h b/mqtt/ringbuf.h index 7d9f8e9..d504d53 100644 --- a/mqtt/ringbuf.h +++ b/mqtt/ringbuf.h @@ -11,7 +11,7 @@ typedef struct { int32_t size; /**< Buffer size */ } RINGBUF; -int16_t ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF* r, uint8_t* buf, int32_t size); -int16_t ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF* r, uint8_t c); -int16_t ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF* r, uint8_t* c); +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 diff --git a/mqtt/utils.c b/mqtt/utils.c deleted file mode 100644 index 86aff20..0000000 --- a/mqtt/utils.c +++ /dev/null @@ -1,140 +0,0 @@ -/* -* Copyright (c) 2014, Tuan PM -* Email: tuanpm@live.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: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. 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. -* 3. Neither the name of the copyright holder 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 HOLDER 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 "utils.h" - -uint8_t ICACHE_FLASH_ATTR -UTILS_IsIPV4(int8_t* str) { - uint8_t segs = 0; /* Segment count. */ - uint8_t chcnt = 0; /* Character count within segment. */ - uint8_t accum = 0; /* Accumulator for segment. */ - /* Catch NULL pointer. */ - if (str == 0) - return 0; - /* Process every character in string. */ - - while (*str != '\0') { - /* Segment changeover. */ - - if (*str == '.') { - /* Must have some digits in segment. */ - if (chcnt == 0) - return 0; - /* Limit number of segments. */ - if (++segs == 4) - return 0; - /* Reset segment values and restart loop. */ - chcnt = accum = 0; - str++; - continue; - } - - /* Check numeric. */ - if ((*str < '0') || (*str > '9')) - return 0; - - /* Accumulate and check segment. */ - - if ((accum = accum * 10 + *str - '0') > 255) - return 0; - /* Advance other segment specific stuff and continue loop. */ - - chcnt++; - str++; - } - - /* Check enough segments and enough characters in last segment. */ - - if (segs != 3) - return 0; - if (chcnt == 0) - return 0; - /* Address okay. */ - - return 1; -} - -uint8_t ICACHE_FLASH_ATTR -UTILS_StrToIP(const int8_t* str, void* ip) { - - /* The count of the number of bytes processed. */ - int i; - /* A pointer to the next digit to process. */ - for (i = 0; i < 4; i++) { - /* The digit being processed. */ - char c; - /* The value of this byte. */ - int n = 0; - while (1) { - c = *(const char *)str; - (const char *)str++; - 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; - } - } - if (n >= 256) { - return 0; - } - ((uint8_t*)ip)[i] = n; - } - return 1; -} - -uint32_t ICACHE_FLASH_ATTR -UTILS_Atoh(const int8_t* s) { - uint32_t value = 0, digit; - int8_t c; - - while ((c = *s++)) { - if ('0' <= c && c <= '9') - digit = c - '0'; - else if ('A' <= c && c <= 'F') - digit = c - 'A' + 10; - else if ('a' <= c && c <= 'f') - digit = c - 'a' + 10; - else break; - - value = (value << 4) | digit; - } - - return value; -} diff --git a/mqtt/utils.h b/mqtt/utils.h deleted file mode 100644 index bc4d2af..0000000 --- a/mqtt/utils.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _UTILS_H_ -#define _UTILS_H_ - -#include - -uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t* s); -uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void* ip); -uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4(int8_t* str); -#endif diff --git a/user/user_main.c b/user/user_main.c index 31e62a1..5738807 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -1,5 +1,70 @@ #include +#include +#include + +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; + 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); } \ No newline at end of file From bc3856334d7f596d3aa433f69d8c6a8cc4b30c2e Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Sun, 30 Aug 2015 12:03:18 -0500 Subject: [PATCH 6/8] Made some modules optional --- Makefile | 29 +++++++-- cmd/cmd.h | 4 +- cmd/handlers.c | 37 ++++++----- esp-link.vcxproj | 8 +-- esp-link/cgi.c | 42 +++++++++++-- esp-link/cgi.h | 2 + include/esp8266.h | 8 ++- include/user_config.h | 10 +++ mqtt/mqtt.h | 1 - {cmd => mqtt}/mqtt_cmd.c | 0 {cmd => mqtt}/mqtt_cmd.h | 0 {cmd => rest}/rest.c | 39 ------------ {cmd => rest}/rest.h | 1 - user/user_main.c | 128 +++++++++++++++++++-------------------- 14 files changed, 166 insertions(+), 143 deletions(-) rename {cmd => mqtt}/mqtt_cmd.c (100%) rename {cmd => mqtt}/mqtt_cmd.h (100%) rename {cmd => rest}/rest.c (93%) rename {cmd => rest}/rest.h (93%) diff --git a/Makefile b/Makefile index 451d7f3..113944c 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ # # Makefile heavily adapted to esp-link and wireless flashing by Thorsten von Eicken # Original from esphttpd and others... +#VERBOSE=1 # --------------- toolchain configuration --------------- @@ -128,6 +129,8 @@ GZIP_COMPRESSION ?= yes COMPRESS_W_YUI ?= yes YUI-COMPRESSOR ?= yuicompressor-2.4.8.jar +# Optional Modules +MODULES ?= rest # -------------- End of config options ------------- @@ -142,15 +145,29 @@ TARGET = httpd # espressif tool to concatenate sections for OTA upload using bootloader v1.2+ APPGEN_TOOL ?= gen_appbin.py +CFLAGS= + +# set defines for optional modules +ifneq (,$(findstring mqtt,$(MODULES))) + CFLAGS += -DMQTT +endif + +ifneq (,$(findstring rest,$(MODULES))) + CFLAGS += -DREST +endif + # which modules (subdirectories) of the project to include in compiling -MODULES = espfs httpd user serial cmd mqtt esp-link +LIBRARIES_DIR = libraries +MODULES += espfs httpd user serial cmd esp-link +MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*)) +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 # compiler flags using during compilation of source files -CFLAGS = -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ +CFLAGS += -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ -nostdlib -mlongcalls -mtext-section-literals -ffunction-sections -fdata-sections \ -D__ets__ -DICACHE_FLASH -D_STDINT_H -Wno-address -DFIRMWARE_SIZE=$(ESP_FLASH_MAX) \ -DMCU_RESET_PIN=$(MCU_RESET_PIN) -DMCU_ISP_PIN=$(MCU_ISP_PIN) \ @@ -167,7 +184,7 @@ LD_SCRIPT2 := build/eagle.esphttpd2.v6.ld # various paths from the SDK used in this project SDK_LIBDIR = lib -SDK_LDDIR = ld +SDK_LDDIR = ld SDK_INCDIR = include include/json SDK_TOOLSDIR = tools @@ -175,8 +192,8 @@ SDK_TOOLSDIR = tools CC := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc AR := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-ar LD := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc -OBJCP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy -OBJDP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objdump +OBJCP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy +OBJDP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objdump #### @@ -214,7 +231,7 @@ CFLAGS += -DGZIP_COMPRESSION endif ifeq ("$(CHANGE_TO_STA)","yes") -CFLAGS += -DCHANGE_TO_STA +CFLAGS += -DCHANGE_TO_STA endif vpath %.c $(SRC_DIR) diff --git a/cmd/cmd.h b/cmd/cmd.h index 97c8236..2d07e1c 100644 --- a/cmd/cmd.h +++ b/cmd/cmd.h @@ -55,8 +55,8 @@ typedef enum { CMD_REST_REQUEST, CMD_REST_SETHEADER, CMD_REST_EVENTS, - CMD_ADD_CALLBACK, // 15 - CMD_SENSOR_EVENTS + CMD_CB_ADD, // 15 + CMD_CB_EVENTS } CmdName; typedef uint32_t (*cmdfunc_t)(CmdPacket *cmd); diff --git a/cmd/handlers.c b/cmd/handlers.c index b54773f..af6eab7 100644 --- a/cmd/handlers.c +++ b/cmd/handlers.c @@ -4,12 +4,13 @@ #include "esp8266.h" #include "cmd.h" -#include "rest.h" -#include "crc16.h" -#include "serbridge.h" -#include "uart.h" -#include "cgiwifi.h" -#include "mqtt_cmd.h" +#include +#ifdef MQTT +#include +#endif +#ifdef REST +#include +#endif static uint32_t CMD_Null(CmdPacket *cmd); static uint32_t CMD_IsReady(CmdPacket *cmd); @@ -27,22 +28,20 @@ const CmdList commands[] = { {CMD_RESET, CMD_Reset}, {CMD_IS_READY, CMD_IsReady}, {CMD_WIFI_CONNECT, CMD_WifiConnect}, - -/* - {CMD_MQTT_SETUP, MQTTAPP_Setup}, - {CMD_MQTT_CONNECT, MQTTAPP_Connect}, - {CMD_MQTT_DISCONNECT, MQTTAPP_Disconnect}, - {CMD_MQTT_PUBLISH, MQTTAPP_Publish}, - {CMD_MQTT_SUBSCRIBE , MQTTAPP_Subscribe}, - {CMD_MQTT_LWT, MQTTAPP_Lwt}, - */ - +#ifdef MQTT + {CMD_MQTT_SETUP, MQTTCMD_Setup}, + {CMD_MQTT_CONNECT, MQTTCMD_Connect}, + {CMD_MQTT_DISCONNECT, MQTTCMD_Disconnect}, + {CMD_MQTT_PUBLISH, MQTTCMD_Publish}, + {CMD_MQTT_SUBSCRIBE , MQTTCMD_Subscribe}, + {CMD_MQTT_LWT, MQTTCMD_Lwt}, +#endif +#ifdef REST {CMD_REST_SETUP, REST_Setup}, {CMD_REST_REQUEST, REST_Request}, {CMD_REST_SETHEADER, REST_SetHeader}, - - {CMD_ADD_CALLBACK, CMD_AddCallback }, - +#endif + { CMD_CB_ADD, CMD_AddCallback }, {CMD_NULL, NULL} }; diff --git a/esp-link.vcxproj b/esp-link.vcxproj index f371f1a..72b0ea6 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -65,8 +65,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + diff --git a/esp-link/cgi.c b/esp-link/cgi.c index 8f87d38..65cab94 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -12,11 +12,7 @@ Some random cgi routines. * Heavily modified and enhanced by Thorsten von Eicken in 2015 * ---------------------------------------------------------------------------- */ - - -#include #include "cgi.h" -#include "espfs.h" void ICACHE_FLASH_ATTR jsonHeader(HttpdConnData *connData, int code) { @@ -28,6 +24,44 @@ jsonHeader(HttpdConnData *connData, int code) { 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; + } + } + if (n >= 256) { + return 0; + } + ((uint8_t*)ip)[i] = n; + } + return 1; +} + #define TOKEN(x) (os_strcmp(token, x) == 0) #if 0 // Handle system information variables and print their value, returns the number of diff --git a/esp-link/cgi.h b/esp-link/cgi.h index b5690cf..200a176 100644 --- a/esp-link/cgi.h +++ b/esp-link/cgi.h @@ -1,9 +1,11 @@ #ifndef CGI_H #define CGI_H +#include #include "httpd.h" void jsonHeader(HttpdConnData *connData, int code); int cgiMenu(HttpdConnData *connData); +uint8_t UTILS_StrToIP(const char* str, void *ip); #endif diff --git a/include/esp8266.h b/include/esp8266.h index c3d0c40..3e7eeb9 100644 --- a/include/esp8266.h +++ b/include/esp8266.h @@ -1,4 +1,7 @@ // Combined include file for esp8266 +#ifndef _ESP8266_H_ +#define _ESP8266_H_ + #include #include #include @@ -16,10 +19,9 @@ #include "espmissingincludes.h" #include "uart_hw.h" -extern char* esp_link_version; - -void ICACHE_FLASH_ATTR init(void); #ifdef __WIN32__ #include <_mingw.h> #endif + +#endif // _ESP8266_H_ \ No newline at end of file diff --git a/include/user_config.h b/include/user_config.h index 7bdfd38..3be06f4 100644 --- a/include/user_config.h +++ b/include/user_config.h @@ -1,5 +1,9 @@ #ifndef _USER_CONFIG_H_ #define _USER_CONFIG_H_ +#include +#ifdef __WIN32__ +#include <_mingw.h> +#endif #define MQTT_RECONNECT_TIMEOUT 5 // seconds #define MQTT_BUF_SIZE 1024 @@ -17,4 +21,10 @@ #define PROTOCOL_NAMEv31 // MQTT version 3.1 compatible with Mosquitto v0.15 //PROTOCOL_NAMEv311 // MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/ +extern char* esp_link_version; + +extern uint8_t UTILS_StrToIP(const char* str, void *ip); + +extern void ICACHE_FLASH_ATTR init(void); + #endif \ No newline at end of file diff --git a/mqtt/mqtt.h b/mqtt/mqtt.h index 9ad6825..00c432a 100644 --- a/mqtt/mqtt.h +++ b/mqtt/mqtt.h @@ -33,7 +33,6 @@ #include #include "mqtt_msg.h" #include "queue.h" -#include typedef struct mqtt_event_data_t { uint8_t type; diff --git a/cmd/mqtt_cmd.c b/mqtt/mqtt_cmd.c similarity index 100% rename from cmd/mqtt_cmd.c rename to mqtt/mqtt_cmd.c diff --git a/cmd/mqtt_cmd.h b/mqtt/mqtt_cmd.h similarity index 100% rename from cmd/mqtt_cmd.h rename to mqtt/mqtt_cmd.h diff --git a/cmd/rest.c b/rest/rest.c similarity index 93% rename from cmd/rest.c rename to rest/rest.c index 3556681..a9cd298 100644 --- a/cmd/rest.c +++ b/rest/rest.c @@ -392,42 +392,3 @@ fail: os_printf("\n"); return 0; } - -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; - } - } - if (n >= 256) { - return 0; - } - ((uint8_t*)ip)[i] = n; - } - return 1; -} diff --git a/cmd/rest.h b/rest/rest.h similarity index 93% rename from cmd/rest.h rename to rest/rest.h index 9c6cd5c..7161e1f 100644 --- a/cmd/rest.h +++ b/rest/rest.h @@ -36,6 +36,5 @@ typedef struct { uint32_t REST_Setup(CmdPacket *cmd); uint32_t REST_Request(CmdPacket *cmd); uint32_t REST_SetHeader(CmdPacket *cmd); -uint8_t UTILS_StrToIP(const char* str, void *ip); #endif /* MODULES_INCLUDE_API_H_ */ diff --git a/user/user_main.c b/user/user_main.c index 5738807..e75876b 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -1,70 +1,70 @@ #include -#include -#include +//#include +//#include -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; - os_printf("MQTT Disconnected\n"); -} - -void ICACHE_FLASH_ATTR -mqttTcpDisconnectedCb(uint32_t *args) { +//MQTT_Client mqttClient; +// +//void ICACHE_FLASH_ATTR +//mqttConnectedCb(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); - } -} +// 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); +// 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); } \ No newline at end of file From b7dd0b180f8ff441a8cba513a488d3c612862082 Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Fri, 11 Sep 2015 15:56:51 -0500 Subject: [PATCH 7/8] lots of ifdef --- .gitignore | 1 + Makefile | 99 ++- cmd/cmd.c | 2 - cmd/cmd.h | 4 +- cmd/handlers.c | 22 +- esp-link.vcxproj | 11 +- esp-link/cgi.c | 12 +- esp-link/cgi.h | 1 - esp-link/cgiflash.c | 12 + esp-link/cgimqtt.c | 50 +- esp-link/cgipins.c | 3 +- esp-link/cgiwifi.c | 48 +- esp-link/config.c | 49 +- esp-link/config.h | 9 +- esp-link/log.c | 4 + esp-link/main.c | 5 +- esp-link/status.c | 15 +- espfs/espfs.c | 8 + html/console.js | 72 ++ html/favicon.ico | Bin 0 -> 498 bytes html/head- | 10 + html/home.html | 88 +- html/log.html | 49 +- html/mqtt.html | 23 +- html/pure.css | 1388 ++++++++++++++++++++++++++++++++ html/style.css | 5 + html/wifi/icons.png | Bin 0 -> 425 bytes html/wifi/wifi.html | 85 +- html/wifi/wifi.js | 200 +++++ httpd/httpd.c | 894 ++++++++++---------- include/user_config.h | 44 +- mqtt/mqtt.c | 78 +- mqtt/mqtt_cmd.c | 33 +- mqtt/pktbuf.c | 4 +- mqtt/pktbuf.h | 2 - rest/rest.c | 60 +- serial/serbridge.c | 41 +- serial/serled.c | 2 + serial/slip.c | 5 + {cmd => tcpclient}/tcpclient.c | 0 {cmd => tcpclient}/tcpclient.h | 0 user/latch_json.c | 64 ++ user/latch_json.h | 12 + user/user_funcs.c | 9 +- user/user_funcs.h | 1 + user/user_main.c | 76 +- 46 files changed, 2979 insertions(+), 621 deletions(-) create mode 100644 html/console.js create mode 100644 html/favicon.ico create mode 100644 html/pure.css create mode 100644 html/wifi/icons.png create mode 100644 html/wifi/wifi.js rename {cmd => tcpclient}/tcpclient.c (100%) rename {cmd => tcpclient}/tcpclient.h (100%) create mode 100644 user/latch_json.c create mode 100644 user/latch_json.h diff --git a/.gitignore b/.gitignore index 899b7c3..a541909 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ esp-link.opensdf esp-link.sdf espfs/mkespfsimage/mman-win32/libmman.a .localhistory/ +tools/ diff --git a/Makefile b/Makefile index 23e57be..4956590 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ ESPBAUD ?= 230400 # --------------- chipset configuration --------------- # Pick your flash size: "512KB", "1MB", or "4MB" -FLASH_SIZE ?= 512KB +FLASH_SIZE ?= 4MB ifeq ("$(FLASH_SIZE)","512KB") # Winbond 25Q40 512KB flash, typ for esp-01 thru esp-11 @@ -70,7 +70,7 @@ ET_BLANK ?= 0x3FE000 # where to flash blank.bin to erase wireless set endif # hostname or IP address for wifi flashing -ESP_HOSTNAME ?= esp-link +ESP_HOSTNAME ?= esp-nodemcu # The pin assignments below are used when the settings in flash are invalid, they # can be changed via the web interface @@ -122,15 +122,20 @@ CHANGE_TO_STA ?= yes #Static gzipping is disabled by default. GZIP_COMPRESSION ?= yes -# If COMPRESS_W_YUI is set to "yes" then the static css and js files will be compressed with -# yui-compressor. This option works only when GZIP_COMPRESSION is set to "yes". +# If COMPRESS_W_HTMLCOMPRESSOR is set to "yes" then the static css and js files will be compressed with +# htmlcompressor and yui-compressor. This option works only when GZIP_COMPRESSION is set to "yes". +# https://code.google.com/p/htmlcompressor/#For_Non-Java_Projects # http://yui.github.io/yuicompressor/ -#Disabled by default. -COMPRESS_W_YUI ?= yes +# enabled by default. +COMPRESS_W_HTMLCOMPRESSOR ?= yes +HTML-COMPRESSOR ?= htmlcompressor-1.5.3.jar YUI-COMPRESSOR ?= yuicompressor-2.4.8.jar +HTML_PATH = $(abspath ./html)/ +WIFI_PATH = $(HTML_PATH)wifi/ + # Optional Modules -MODULES ?= +MODULES ?= mqtt rest # -------------- End of config options ------------- @@ -144,7 +149,6 @@ TARGET = httpd # espressif tool to concatenate sections for OTA upload using bootloader v1.2+ APPGEN_TOOL ?= gen_appbin.py - CFLAGS= # set defines for optional modules @@ -156,19 +160,23 @@ ifneq (,$(findstring rest,$(MODULES))) CFLAGS += -DREST endif +ifneq (,$(findstring tcpclient,$(MODULES))) + CFLAGS += -DTCPCLIENT +endif + # which modules (subdirectories) of the project to include in compiling -LIBRARIES_DIR = libraries -MODULES = espfs httpd user serial cmd mqtt esp-link +LIBRARIES_DIR = libraries +MODULES += espfs httpd user serial cmd esp-link MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*)) -EXTRA_INCDIR = include . include/json +EXTRA_INCDIR = include . # libraries used in this project, mainly provided by the SDK -LIBS = c gcc hal phy pp net80211 wpa main lwip json +LIBS = c gcc hal phy pp net80211 wpa main lwip # compiler flags using during compilation of source files -CFLAGS += -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ +CFLAGS += -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ -nostdlib -mlongcalls -mtext-section-literals -ffunction-sections -fdata-sections \ - -Wno-unused-function \ + -Wno-unused-function -Wno-unused-variable \ -D__ets__ -DICACHE_FLASH -D_STDINT_H -Wno-address -DFIRMWARE_SIZE=$(ESP_FLASH_MAX) \ -DMCU_RESET_PIN=$(MCU_RESET_PIN) -DMCU_ISP_PIN=$(MCU_ISP_PIN) \ -DLED_CONN_PIN=$(LED_CONN_PIN) -DLED_SERIAL_PIN=$(LED_SERIAL_PIN) \ @@ -203,17 +211,17 @@ BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES)) SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR)) SDK_LDDIR := $(addprefix $(SDK_BASE)/,$(SDK_LDDIR)) SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR)) -SDK_TOOLS := $(addprefix $(SDK_BASE)/,$(SDK_TOOLSDIR)) +SDK_TOOLS := $(addprefix $(SDK_BASE)/,$(SDK_TOOLSDIR)) APPGEN_TOOL := $(addprefix $(SDK_TOOLS)/,$(APPGEN_TOOL)) -SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) -OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC)) $(BUILD_BASE)/espfs_img.o +SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) +OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC)) $(BUILD_BASE)/espfs_img.o LIBS := $(addprefix -l,$(LIBS)) APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a) USER1_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).user1.out) USER2_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).user2.out) -INCDIR := $(addprefix -I,$(SRC_DIR)) +INCDIR := $(addprefix -I,$(SRC_DIR)) EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR)) MODULE_INCDIR := $(addsuffix /include,$(INCDIR)) @@ -275,7 +283,7 @@ $(FW_BASE)/user1.bin: $(USER1_OUT) $(FW_BASE) $(Q) rm -f eagle.app.v6.*.bin $(Q) mv eagle.app.flash.bin $@ @echo "** user1.bin uses $$(stat -c '%s' $@) bytes of" $(ESP_FLASH_MAX) "available" - $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; false; fi + $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; true; fi $(FW_BASE)/user2.bin: $(USER2_OUT) $(FW_BASE) $(Q) $(OBJCP) --only-section .text -O binary $(USER2_OUT) eagle.app.v6.text.bin @@ -285,7 +293,7 @@ $(FW_BASE)/user2.bin: $(USER2_OUT) $(FW_BASE) $(Q) COMPILE=gcc PATH=$(XTENSA_TOOLS_ROOT):$(PATH) python $(APPGEN_TOOL) $(USER2_OUT) 2 $(ESP_FLASH_MODE) $(ESP_FLASH_FREQ_DIV) $(ESP_SPI_SIZE) $(Q) rm -f eagle.app.v6.*.bin $(Q) mv eagle.app.flash.bin $@ - $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; false; fi + $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; true; fi $(APP_AR): $(OBJ) $(vecho) "AR $@" @@ -306,35 +314,52 @@ flash: all $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash -fs $(ET_FS) -ff $(ET_FF) \ 0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \ $(ET_BLANK) $(SDK_BASE)/bin/blank.bin - -yui/$(YUI-COMPRESSOR): - $(Q) mkdir -p yui + +tools/$(HTML-COMPRESSOR): + $(Q) mkdir -p tools ifeq ($(OS),Windows_NT) - cd yui; wget --no-check-certificate https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) -O $(YUI-COMPRESSOR) + cd tools; wget --no-check-certificate https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) -O $(YUI-COMPRESSOR) + cd tools; wget --no-check-certificate https://htmlcompressor.googlecode.com/files/$(HTML-COMPRESSOR) -O $(HTML-COMPRESSOR) else - cd yui; wget https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) + cd tools; wget https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) + cd tools; wget https://htmlcompressor.googlecode.com/files/$(HTML-COMPRESSOR) endif -ifeq ("$(COMPRESS_W_YUI)","yes") -$(BUILD_BASE)/espfs_img.o: yui/$(YUI-COMPRESSOR) +ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") +$(BUILD_BASE)/espfs_img.o: tools/$(HTML-COMPRESSOR) endif $(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage - $(Q) rm -rf html_compressed; - $(Q) cp -r html html_compressed; - $(Q) for file in `find html_compressed -type f -name "*.htm*"`; do \ - cat html_compressed/head- $$file >$${file}-; \ - mv $$file- $$file; \ - done -ifeq ("$(COMPRESS_W_YUI)","yes") + $(Q) rm -rf html_compressed; mkdir html_compressed; mkdir html_compressed/wifi; + $(Q) cp -r html/*.ico html_compressed; + $(Q) cp -r html/*.css html_compressed; + $(Q) cp -r html/*.js html_compressed; + $(Q) cp -r html/wifi/*.png html_compressed/wifi; + $(Q) cp -r html/wifi/*.js html_compressed/wifi; +ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") + $(Q) echo "Compression assets with htmlcompressor. This may take a while..." + $(Q) java -jar tools/$(HTML-COMPRESSOR) \ + -t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \ + -o $(abspath ./html_compressed)/ \ + $(HTML_PATH)head- \ + $(HTML_PATH)*.html + $(Q) java -jar tools/$(HTML-COMPRESSOR) \ + -t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \ + -o $(abspath ./html_compressed)/wifi/ \ + $(WIFI_PATH)*.html $(Q) echo "Compression assets with yui-compressor. This may take a while..." $(Q) for file in `find html_compressed -type f -name "*.js"`; do \ - java -jar yui/$(YUI-COMPRESSOR) $$file --nomunge --line-break 40 -o $$file; \ + java -jar tools/$(YUI-COMPRESSOR) $$file -o $$file; \ done $(Q) for file in `find html_compressed -type f -name "*.css"`; do \ - java -jar yui/$(YUI-COMPRESSOR) $$file -o $$file; \ + java -jar tools/$(YUI-COMPRESSOR) $$file -o $$file; \ done endif + $(Q) for file in `find html_compressed -type f -name "*.htm*"`; do \ + cat html_compressed/head- $$file >$${file}-; \ + mv $$file- $$file; \ + done + $(Q) rm html_compressed/head- $(Q) cd html_compressed; find . \! -name \*- | ../espfs/mkespfsimage/mkespfsimage > ../build/espfs.img; cd ..; $(Q) ls -sl build/espfs.img $(Q) cd build; $(OBJCP) -I binary -O elf32-xtensa-le -B xtensa --rename-section .data=.espfs \ @@ -384,7 +409,7 @@ clean: $(Q) make -C espfs/mkespfsimage/ clean $(Q) rm -rf $(FW_BASE) $(Q) rm -f webpages.espfs -ifeq ("$(COMPRESS_W_YUI)","yes") +ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") $(Q) rm -rf html_compressed endif diff --git a/cmd/cmd.c b/cmd/cmd.c index 07a92a5..f3bcbba 100644 --- a/cmd/cmd.c +++ b/cmd/cmd.c @@ -2,10 +2,8 @@ // // Adapted from: github.com/tuanpmt/esp_bridge, Created on: Jan 9, 2015, Author: Minh -#include "esp8266.h" #include "cmd.h" #include "crc16.h" -#include "serbridge.h" #include "uart.h" extern const CmdList commands[]; diff --git a/cmd/cmd.h b/cmd/cmd.h index 97c8236..2d07e1c 100644 --- a/cmd/cmd.h +++ b/cmd/cmd.h @@ -55,8 +55,8 @@ typedef enum { CMD_REST_REQUEST, CMD_REST_SETHEADER, CMD_REST_EVENTS, - CMD_ADD_CALLBACK, // 15 - CMD_SENSOR_EVENTS + CMD_CB_ADD, // 15 + CMD_CB_EVENTS } CmdName; typedef uint32_t (*cmdfunc_t)(CmdPacket *cmd); diff --git a/cmd/handlers.c b/cmd/handlers.c index adf90b9..339c1dd 100644 --- a/cmd/handlers.c +++ b/cmd/handlers.c @@ -41,7 +41,7 @@ const CmdList commands[] = { {CMD_REST_REQUEST, REST_Request}, {CMD_REST_SETHEADER, REST_SetHeader}, #endif - { CMD_CB_ADD, CMD_AddCallback }, + {CMD_CB_ADD, CMD_AddCallback}, {CMD_NULL, NULL} }; @@ -52,14 +52,18 @@ cmdCallback callbacks[MAX_CALLBACKS]; // cleared in CMD_Reset // Command handler for IsReady (healthcheck) command static uint32_t ICACHE_FLASH_ATTR CMD_IsReady(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_IsReady: Check ready\n"); +#endif return 1; } // Command handler for Null command static uint32_t ICACHE_FLASH_ATTR CMD_Null(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_Null: NULL/unsupported command\n"); +#endif return 1; } @@ -68,7 +72,9 @@ CMD_Null(CmdPacket *cmd) { // uC. static uint32_t ICACHE_FLASH_ATTR CMD_Reset(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_Reset\n"); +#endif // clear callbacks table os_memset(callbacks, 0, sizeof(callbacks)); return 1; @@ -83,7 +89,9 @@ CMD_AddCb(char* name, uint32_t cb) { if (os_strcmp(callbacks[i].name, name) == 0 || callbacks[i].name[0] == '\0') { os_strncpy(callbacks[i].name, name, sizeof(callbacks[i].name)); callbacks[i].callback = cb; +#ifdef CMD_DBG os_printf("CMD_AddCb: cb %s added at index %d\n", callbacks[i].name, i); +#endif return 1; } } @@ -99,7 +107,9 @@ CMD_GetCbByName(char* name) { // (void *)callbacks[i].callback); // if callback doesn't exist or it's null if (os_strcmp(callbacks[i].name, checkname) == 0) { +#ifdef CMD_DBG os_printf("CMD_GetCbByName: cb %s found at index %d\n", callbacks[i].name, i); +#endif return &callbacks[i]; } } @@ -111,7 +121,9 @@ CMD_GetCbByName(char* name) { static void ICACHE_FLASH_ATTR CMD_WifiCb(uint8_t wifiStatus) { if (wifiStatus != lastWifiStatus){ +#ifdef CMD_DBG os_printf("CMD_WifiCb: wifiStatus=%d\n", wifiStatus); +#endif lastWifiStatus = wifiStatus; cmdCallback *wifiCb = CMD_GetCbByName("wifiCb"); if ((uint32_t)wifiCb->callback != -1) { @@ -128,7 +140,9 @@ static uint32_t ICACHE_FLASH_ATTR CMD_WifiConnect(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef CMD_DBG os_printf("CMD_WifiConnect: setup argc=%ld\n", CMD_GetArgc(&req)); +#endif if(cmd->argc != 2 || cmd->callback == 0) return 0; @@ -148,7 +162,9 @@ static uint32_t ICACHE_FLASH_ATTR CMD_AddCallback(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef CMD_DBG os_printf("CMD_AddCallback: setup argc=%ld\n", CMD_GetArgc(&req)); +#endif if (cmd->argc != 1 || cmd->callback == 0) return 0; @@ -157,11 +173,15 @@ CMD_AddCallback(CmdPacket *cmd) { // get the sensor name len = CMD_ArgLen(&req); +#ifdef CMD_DBG os_printf("CMD_AddCallback: name len=%d\n", len); +#endif if (len > 15) return 0; // max size of name is 15 characters if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0; name[len] = 0; +#ifdef CMD_DBG os_printf("CMD_AddCallback: name=%s\n", name); +#endif return CMD_AddCb(name, (uint32_t)cmd->callback); // save the sensor callback } diff --git a/esp-link.vcxproj b/esp-link.vcxproj index 029fbb7..6a17160 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -65,9 +65,11 @@ + + + - @@ -103,6 +105,7 @@ + @@ -111,9 +114,12 @@ + + + - + @@ -150,6 +156,7 @@ + diff --git a/esp-link/cgi.c b/esp-link/cgi.c index 2b814fe..c99bada 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -16,14 +16,6 @@ Some random cgi routines. #include #include "cgi.h" -static char* chipIdStr = ""; -char* ICACHE_FLASH_ATTR system_get_chip_id_str(){ - if (os_strlen(chipIdStr) == 0) { - chipIdStr = (char*)os_zalloc(9); - os_sprintf(chipIdStr, "%06x", system_get_chip_id()); - } - return chipIdStr; -} void noCacheHeaders(HttpdConnData *connData, int code) { httpdStartResponse(connData, code); @@ -44,7 +36,9 @@ errorResponse(HttpdConnData *connData, int code, char *message) { noCacheHeaders(connData, code); httpdEndHeaders(connData); httpdSend(connData, message, -1); +#ifdef CGI_DBG os_printf("HTTP %d error response: \"%s\"\n", code, message); +#endif } // look for the HTTP arg 'name' and store it at 'config' with max length 'max_len' (incl @@ -58,7 +52,7 @@ getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) { os_sprintf(buff, "Value for %s too long (%d > %d allowed)", name, len, max_len-1); errorResponse(connData, 400, buff); return -1; - } + } strcpy(config, buff); return 1; } diff --git a/esp-link/cgi.h b/esp-link/cgi.h index d1d73c6..aa124f1 100644 --- a/esp-link/cgi.h +++ b/esp-link/cgi.h @@ -10,6 +10,5 @@ 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); -char* system_get_chip_id_str(); #endif diff --git a/esp-link/cgiflash.c b/esp-link/cgiflash.c index e07443b..ccd6865 100644 --- a/esp-link/cgiflash.c +++ b/esp-link/cgiflash.c @@ -22,8 +22,10 @@ Some flash handling cgi routines. Used for reading the existing flash and updati // Check that the header of the firmware blob looks like actual firmware... static char* ICACHE_FLASH_ATTR check_header(void *buf) { uint8_t *cd = (uint8_t *)buf; +#ifdef CGIFLASH_DBG uint32_t *buf32 = buf; os_printf("%p: %08lX %08lX %08lX %08lX\n", buf, buf32[0], buf32[1], buf32[2], buf32[3]); +#endif if (cd[0] != 0xEA) return "IROM magic missing"; if (cd[1] != 4 || cd[2] > 3 || (cd[3]>>4) > 6) return "bad flash header"; if (((uint16_t *)buf)[3] != 0x4010) return "Invalid entry addr"; @@ -42,7 +44,9 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) { httpdEndHeaders(connData); char *next = id == 1 ? "user1.bin" : "user2.bin"; httpdSend(connData, next, -1); +#ifdef CGIFLASH_DBG os_printf("Next firmware: %s (got %d)\n", next, id); +#endif return HTTPD_CGI_DONE; } @@ -80,7 +84,9 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { // return an error if there is one if (err != NULL) { +#ifdef CGIFLASH_DBG os_printf("Error %d: %s\n", code, err); +#endif httpdStartResponse(connData, code); httpdHeader(connData, "Content-Type", "text/plain"); //httpdHeader(connData, "Content-Length", strlen(err)+2); @@ -99,7 +105,9 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { // erase next flash block if necessary if (address % SPI_FLASH_SEC_SIZE == 0){ +#ifdef CGIFLASH_DBG os_printf("Flashing 0x%05x (id=%d)\n", address, 2-id); +#endif spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE); } @@ -129,11 +137,15 @@ int ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) { int address = id == 1 ? 4*1024 // either start after 4KB boot partition : 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; // 4KB boot, fw1, 16KB user param, 4KB reserved uint32 buf[8]; +#ifdef CGIFLASH_DBG os_printf("Checking %p\n", (void *)address); +#endif spi_flash_read(address, buf, sizeof(buf)); char *err = check_header(buf); if (err != NULL) { +#ifdef CGIFLASH_DBG os_printf("Error %d: %s\n", 400, err); +#endif httpdStartResponse(connData, 400); httpdHeader(connData, "Content-Type", "text/plain"); //httpdHeader(connData, "Content-Length", strlen(err)+2); diff --git a/esp-link/cgimqtt.c b/esp-link/cgimqtt.c index cbf4c16..2c3c7b0 100644 --- a/esp-link/cgimqtt.c +++ b/esp-link/cgimqtt.c @@ -17,17 +17,29 @@ int ICACHE_FLASH_ATTR cgiMqttGet(HttpdConnData *connData) { "\"slip-enable\":%d, " "\"mqtt-enable\":%d, " "\"mqtt-status-enable\":%d, " + "\"mqtt-clean-session\":%d, " "\"mqtt-port\":%d, " + "\"mqtt-timeout\":%d, " + "\"mqtt-keepalive\":%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"); + flashConfig.slip_enable, + flashConfig.mqtt_enable, + flashConfig.mqtt_status_enable, + flashConfig.mqtt_clean_session, + flashConfig.mqtt_port, + flashConfig.mqtt_timeout, + flashConfig.mqtt_keepalive, + flashConfig.mqtt_host, + flashConfig.mqtt_clientid, + flashConfig.mqtt_username, + flashConfig.mqtt_password, + flashConfig.mqtt_status_topic, + "connected"); jsonHeader(connData, 200); httpdSend(connData, buff, len); @@ -41,22 +53,30 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) { // 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)); + flashConfig.mqtt_host, sizeof(flashConfig.mqtt_host)); if (mqtt_server < 0) return HTTPD_CGI_DONE; mqtt_server |= getStringArg(connData, "mqtt-client-id", - flashConfig.mqtt_client, sizeof(flashConfig.mqtt_client)); + flashConfig.mqtt_clientid, sizeof(flashConfig.mqtt_clientid)); + 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-clean-session", + &flashConfig.mqtt_clean_session); + if (mqtt_server < 0) return HTTPD_CGI_DONE; mqtt_server |= getBoolArg(connData, "mqtt-enable", &flashConfig.mqtt_enable); - // handle mqtt port + char buff[16]; + + // handle mqtt port if (httpdFindArg(connData->getArgs, "mqtt-port", buff, sizeof(buff)) > 0) { int32_t port = atoi(buff); if (port > 0 && port < 65536) { @@ -68,9 +88,23 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) { } } + // handle mqtt timeout + if (httpdFindArg(connData->getArgs, "mqtt-timeout", buff, sizeof(buff)) > 0) { + int32_t timeout = atoi(buff); + flashConfig.mqtt_timeout = timeout; + } + + // handle mqtt keepalive + if (httpdFindArg(connData->getArgs, "mqtt-keepalive", buff, sizeof(buff)) > 0) { + int32_t keepalive = atoi(buff); + flashConfig.mqtt_keepalive = keepalive; + } + // if server setting changed, we need to "make it so" if (mqtt_server) { +#ifdef CGIMQTT_DBG os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable); +#endif // TODO } @@ -85,9 +119,11 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) { // 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; +#ifdef CGIMQTT_DBG if (slip_update > 0) os_printf("SLIP-enable changed: %d\n", flashConfig.slip_enable); os_printf("Saving config\n"); +#endif if (configSave()) { httpdStartResponse(connData, 200); httpdEndHeaders(connData); diff --git a/esp-link/cgipins.c b/esp-link/cgipins.c index dabc1fd..80326df 100644 --- a/esp-link/cgipins.c +++ b/esp-link/cgipins.c @@ -85,8 +85,9 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) { jsonHeader(connData, 400); return HTTPD_CGI_DONE; } - +#ifdef CGIPINS_DBG os_printf("Switching pin map to %s (%d)\n", map_names[m], m); +#endif int8_t *map = map_asn[m]; flashConfig.reset_pin = map[0]; flashConfig.isp_pin = map[1]; diff --git a/esp-link/cgiwifi.c b/esp-link/cgiwifi.c index 69d59b4..7292447 100644 --- a/esp-link/cgiwifi.c +++ b/esp-link/cgiwifi.c @@ -55,36 +55,48 @@ static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) { case EVENT_STAMODE_CONNECTED: wifiState = wifiIsConnected; wifiReason = 0; +#ifdef CGIWIFI_DBG os_printf("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid, evt->event_info.connected.channel); +#endif statusWifiUpdate(wifiState); break; case EVENT_STAMODE_DISCONNECTED: wifiState = wifiIsDisconnected; wifiReason = evt->event_info.disconnected.reason; +#ifdef CGIWIFI_DBG os_printf("Wifi disconnected from ssid %s, reason %s (%d)\n", evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason); +#endif statusWifiUpdate(wifiState); break; case EVENT_STAMODE_AUTHMODE_CHANGE: +#ifdef CGIWIFI_DBG os_printf("Wifi auth mode: %d -> %d\n", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); +#endif break; case EVENT_STAMODE_GOT_IP: wifiState = wifiGotIP; wifiReason = 0; +#ifdef CGIWIFI_DBG os_printf("Wifi got ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.mask), IP2STR(&evt->event_info.got_ip.gw)); +#endif statusWifiUpdate(wifiState); break; case EVENT_SOFTAPMODE_STACONNECTED: +#ifdef CGIWIFI_DBG os_printf("Wifi AP: station " MACSTR " joined, AID = %d\n", MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); +#endif break; case EVENT_SOFTAPMODE_STADISCONNECTED: +#ifdef CGIWIFI_DBG os_printf("Wifi AP: station " MACSTR " left, AID = %d\n", MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); +#endif break; default: break; @@ -103,7 +115,9 @@ wifiAddStateChangeCb(WifiStateChangeCb cb) { return; } } +#ifdef CGIWIFI_DBG os_printf("WIFI: max state change cb count exceeded\n"); +#endif } // ===== wifi scanning @@ -132,7 +146,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { struct bss_info *bss_link = (struct bss_info *)arg; if (status!=OK) { +#ifdef CGIWIFI_DBG os_printf("wifiScanDoneCb status=%d\n", status); +#endif cgiWifiAps.scanInProgress=0; return; } @@ -152,7 +168,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { //Allocate memory for access point data cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n); cgiWifiAps.noAps=n; +#ifdef CGIWIFI_DBG os_printf("Scan done: found %d APs\n", n); +#endif //Copy access point data to the static struct n=0; @@ -161,7 +179,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { if (n>=cgiWifiAps.noAps) { //This means the bss_link changed under our nose. Shouldn't happen! //Break because otherwise we will write in unallocated memory. +#ifdef CGIWIFI_DBG os_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps); +#endif break; } //Save the ap data. @@ -169,7 +189,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { cgiWifiAps.apData[n]->rssi=bss_link->rssi; cgiWifiAps.apData[n]->enc=bss_link->authmode; strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); +#ifdef CGIWIFI_DBG os_printf("bss%d: %s (%d)\n", n+1, (char*)bss_link->ssid, bss_link->rssi); +#endif bss_link = bss_link->next.stqe_next; n++; @@ -180,7 +202,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { static ETSTimer scanTimer; static void ICACHE_FLASH_ATTR scanStartCb(void *arg) { +#ifdef CGIWIFI_DBG os_printf("Starting a scan\n"); +#endif wifi_station_scan(NULL, wifiScanDoneCb); } @@ -245,13 +269,17 @@ static ETSTimer resetTimer; static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { int x = wifi_station_get_connect_status(); int m = wifi_get_opmode() & 0x3; +#ifdef CGIWIFI_DBG os_printf("Wifi check: mode=%s status=%d\n", wifiMode[m], x); +#endif if (x == STATION_GOT_IP) { if (m != 1) { #ifdef CHANGE_TO_STA // We're happily connected, go to STA mode +#ifdef CGIWIFI_DBG os_printf("Wifi got IP. Going into STA mode..\n"); +#endif wifi_set_opmode(1); wifi_set_sleep_type(SLEEP_MODE); os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); @@ -261,11 +289,15 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { // no more resetTimer at this point, gotta use physical reset to recover if in trouble } else { if (m != 3) { +#ifdef CGIWIFI_DBG os_printf("Wifi connect failed. Going into STA+AP mode..\n"); +#endif wifi_set_opmode(3); } log_uart(true); +#ifdef CGIWIFI_DBG os_printf("Enabling/continuing uart log\n"); +#endif os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); } } @@ -277,7 +309,9 @@ static ETSTimer reassTimer; // Callback actually doing reassociation static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { +#ifdef CGIWIFI_DBG os_printf("Wifi changing association\n"); +#endif wifi_station_disconnect(); stconf.bssid_set = 0; wifi_station_set_config(&stconf); @@ -303,7 +337,9 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { //Set to 0 if you want to disable the actual reconnecting bit os_strncpy((char*)stconf.ssid, essid, 32); os_strncpy((char*)stconf.password, passwd, 64); +#ifdef CGIWIFI_DBG os_printf("Wifi try to connect to AP %s pw %s\n", essid, passwd); +#endif //Schedule disconnect/connect os_timer_disarm(&reassTimer); @@ -342,7 +378,6 @@ static bool parse_ip(char *buff, ip_addr_t *ip_ptr) { return false; } -#define DEBUGIP #ifdef DEBUGIP static void ICACHE_FLASH_ATTR debugIP() { struct ip_info info; @@ -365,7 +400,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() { if (wifi_station_dhcpc_status() == DHCP_STARTED) wifi_station_dhcpc_stop(); wifi_station_dhcpc_start(); +#ifdef CGIWIFI_DBG os_printf("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname); +#endif } else { // no DHCP, we got static network config! wifi_station_dhcpc_stop(); @@ -374,7 +411,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() { ipi.netmask.addr = flashConfig.netmask; ipi.gw.addr = flashConfig.gateway; wifi_set_ip_info(0, &ipi); +#ifdef CGIWIFI_DBG os_printf("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr)); +#endif } #ifdef DEBUGIP debugIP(); @@ -454,7 +493,9 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); if (len!=0) { int m = atoi(buff); +#ifdef CGIWIFI_DBG os_printf("Wifi switching to mode %d\n", m); +#endif wifi_set_opmode(m&3); if (m == 1) { wifi_set_sleep_type(SLEEP_MODE); @@ -557,8 +598,9 @@ int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { #endif len += os_sprintf(buff+len, "\"x\":0}\n"); - +#ifdef CGIWIFI_DBG os_printf(" -> %s\n", buff); +#endif httpdSend(connData, buff, len); return HTTPD_CGI_DONE; } @@ -582,8 +624,10 @@ int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) { // so we can revert to STA+AP mode if we can't connect. void ICACHE_FLASH_ATTR wifiInit() { wifi_set_phy_mode(2); +#ifdef CGIWIFI_DBG int x = wifi_get_opmode() & 0x3; os_printf("Wifi init, mode=%s\n", wifiMode[x]); +#endif configWifiIP(); wifi_set_event_handler_cb(wifiHandleEventCb); diff --git a/esp-link/config.c b/esp-link/config.c index 2f405e7..0ab4745 100644 --- a/esp-link/config.c +++ b/esp-link/config.c @@ -6,6 +6,7 @@ #include "config.h" #include "espfs.h" #include "crc16.h" +#include FlashConfig flashConfig; FlashConfig flashDefault = { @@ -19,8 +20,9 @@ FlashConfig flashDefault = { 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 + 2, 1, // mqtt_timeout, mqtt_clean_session + 1833, 600, // mqtt port, mqtt_keepalive + "\0", "\0", "\0", "\0", "\0", // mqtt host, client_id, user, password, status-topic }; typedef union { @@ -51,8 +53,8 @@ static void memDump(void *addr, int len) { bool ICACHE_FLASH_ATTR configSave(void) { FlashFull ff; - memset(&ff, 0, sizeof(ff)); - memcpy(&ff, &flashConfig, sizeof(FlashConfig)); + os_memset(&ff, 0, sizeof(ff)); + os_memcpy(&ff, &flashConfig, sizeof(FlashConfig)); uint32_t seq = ff.fc.seq+1; // erase secondary uint32_t addr = FLASH_ADDR + (1-flash_pri)*FLASH_SECT; @@ -104,19 +106,28 @@ bool ICACHE_FLASH_ATTR configRestore(void) { FlashFull ff0, ff1; // read both flash sectors if (spi_flash_read(FLASH_ADDR, (void *)&ff0, sizeof(ff0)) != SPI_FLASH_RESULT_OK) - memset(&ff0, 0, sizeof(ff0)); // clear in case of error + os_memset(&ff0, 0, sizeof(ff0)); // clear in case of error if (spi_flash_read(FLASH_ADDR+FLASH_SECT, (void *)&ff1, sizeof(ff1)) != SPI_FLASH_RESULT_OK) - memset(&ff1, 0, sizeof(ff1)); // clear in case of error + os_memset(&ff1, 0, sizeof(ff1)); // clear in case of error // figure out which one is good flash_pri = selectPrimary(&ff0, &ff1); // if neither is OK, we revert to defaults if (flash_pri < 0) { - memcpy(&flashConfig, &flashDefault, sizeof(FlashConfig)); + os_memcpy(&flashConfig, &flashDefault, sizeof(FlashConfig)); + char chipIdStr[6]; + os_sprintf(chipIdStr, "%06x", system_get_chip_id()); + os_memcpy(&flashConfig.mqtt_clientid, chipIdStr, os_strlen(chipIdStr)); +#ifdef CHIP_IN_HOSTNAME + char hostname[16]; + os_strcpy(hostname, "esp-link-"); + os_strcat(hostname, chipIdStr); + os_memcpy(&flashConfig.hostname, hostname, os_strlen(hostname)); +#endif flash_pri = 0; return false; } // copy good one into global var and return - memcpy(&flashConfig, flash_pri == 0 ? &ff0.fc : &ff1.fc, sizeof(FlashConfig)); + os_memcpy(&flashConfig, flash_pri == 0 ? &ff0.fc : &ff1.fc, sizeof(FlashConfig)); return true; } @@ -125,10 +136,14 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) { uint16_t crc = ff0->fc.crc; ff0->fc.crc = 0; 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", +#ifdef CONFIG_DBG + os_printf("FLASH chk=0x%04x crc=0x%04x full_sz=%d sz=%d chip_sz=%d\n", crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0), - crc, sizeof(FlashFull), sizeof(FlashConfig)); + crc, + sizeof(FlashFull), + sizeof(FlashConfig), + getFlashSize()); +#endif // check CRC of ff1 crc = ff1->fc.crc; @@ -144,3 +159,15 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) { else return ff1_crc_ok ? 1 : -1; } + +// returns the flash chip's size, in BYTES +const size_t ICACHE_FLASH_ATTR +getFlashSize() { + uint32_t id = spi_flash_get_id(); + uint8_t mfgr_id = id & 0xff; + uint8_t type_id = (id >> 8) & 0xff; // not relevant for size calculation + uint8_t size_id = (id >> 16) & 0xff; // lucky for us, WinBond ID's their chips as a form that lets us calculate the size + if (mfgr_id != 0xEF) // 0xEF is WinBond; that's all we care about (for now) + return 0; + return 1 << size_id; +} diff --git a/esp-link/config.h b/esp-link/config.h index 89287e6..5a67058 100644 --- a/esp-link/config.h +++ b/esp-link/config.h @@ -17,9 +17,11 @@ typedef struct { 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]; + mqtt_status_enable, // MQTT status reporting + mqtt_timeout, // MQTT send timeout + mqtt_clean_session; // MQTT clean session + uint16_t mqtt_port, mqtt_keepalive; // MQTT Host port, MQTT Keepalive timer + char mqtt_host[32], mqtt_clientid[48], mqtt_username[32], mqtt_password[32]; char mqtt_status_topic[32]; } FlashConfig; extern FlashConfig flashConfig; @@ -27,5 +29,6 @@ extern FlashConfig flashConfig; bool configSave(void); bool configRestore(void); void configWipe(void); +const size_t getFlashSize(); #endif diff --git a/esp-link/log.c b/esp-link/log.c index 9103a41..9a58b4d 100644 --- a/esp-link/log.c +++ b/esp-link/log.c @@ -25,14 +25,18 @@ log_uart(bool enable) { if (!enable && !log_no_uart && flashConfig.log_mode != LOG_MODE_ON) { // we're asked to turn uart off, and uart is on, and the flash setting isn't always-on #if 1 +#ifdef LOG_DBG os_printf("Turning OFF uart log\n"); +#endif os_delay_us(4*1000L); // time for uart to flush log_no_uart = !enable; #endif } else if (enable && log_no_uart && flashConfig.log_mode != LOG_MODE_OFF) { // we're asked to turn uart on, and uart is off, and the flash setting isn't always-off log_no_uart = !enable; +#ifdef LOG_DBG os_printf("Turning ON uart log\n"); +#endif } } diff --git a/esp-link/main.c b/esp-link/main.c index aed1c7f..27a50e5 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -30,7 +30,7 @@ #include "log.h" #include -#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 @@ -97,9 +97,6 @@ HttpdBuiltInUrl builtInUrls[] = { { NULL, NULL, NULL } }; - -//#define SHOW_HEAP_USE - #ifdef SHOW_HEAP_USE static ETSTimer prHeapTimer; diff --git a/esp-link/status.c b/esp-link/status.c index 4e0da55..2a8346f 100644 --- a/esp-link/status.c +++ b/esp-link/status.c @@ -4,8 +4,9 @@ #include "config.h" #include "serled.h" #include "cgiwifi.h" -#include "tcpclient.h" - +#ifdef TCPCLIENT +#include +#endif //===== "CONN" LED status indication static ETSTimer ledTimer; @@ -66,6 +67,8 @@ void ICACHE_FLASH_ATTR statusWifiUpdate(uint8_t state) { os_timer_arm(&ledTimer, 500, 0); } +#ifdef TCPCLIENT + //===== RSSI Status update sent to GroveStreams #define RSSI_INTERVAL (60*1000) @@ -112,6 +115,7 @@ static void ICACHE_FLASH_ATTR rssiTimerCb(void *v) { } tcpClientSendPush(chan); } +#endif // TCPCLIENT //===== Init status stuff @@ -120,15 +124,20 @@ void ICACHE_FLASH_ATTR statusInit(void) { makeGpio(flashConfig.conn_led_pin); setLed(1); } +#ifdef STATUS_DBG os_printf("CONN led=%d\n", flashConfig.conn_led_pin); +#endif os_timer_disarm(&ledTimer); os_timer_setfn(&ledTimer, ledTimerCb, NULL); os_timer_arm(&ledTimer, 2000, 0); - +#ifdef TCPCLIENT os_timer_disarm(&rssiTimer); os_timer_setfn(&rssiTimer, rssiTimerCb, NULL); os_timer_arm(&rssiTimer, RSSI_INTERVAL, 1); // recurring timer +#endif // TCPCLIENT } + + diff --git a/espfs/espfs.c b/espfs/espfs.c index 128ca29..f9942f3 100644 --- a/espfs/espfs.c +++ b/espfs/espfs.c @@ -109,7 +109,9 @@ void ICACHE_FLASH_ATTR memcpyAligned(char *dst, char *src, int len) { // Returns flags of opened file. int ICACHE_FLASH_ATTR espFsFlags(EspFsFile *fh) { if (fh == NULL) { +#ifdef ESPFS_DBG os_printf("File handle not ready\n"); +#endif return -1; } @@ -121,7 +123,9 @@ int ICACHE_FLASH_ATTR espFsFlags(EspFsFile *fh) { //Open a file and return a pointer to the file desc struct. EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { if (espFsData == NULL) { +#ifdef ESPFS_DBG os_printf("Call espFsInit first!\n"); +#endif return NULL; } char *p=espFsData; @@ -137,7 +141,9 @@ EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { //Grab the next file header. os_memcpy(&h, p, sizeof(EspFsHeader)); if (h.magic!=ESPFS_MAGIC) { +#ifdef ESPFS_DBG os_printf("Magic mismatch. EspFS image broken.\n"); +#endif return NULL; } if (h.flags&FLAG_LASTFILE) { @@ -163,7 +169,9 @@ EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { if (h.compression==COMPRESS_NONE) { r->decompData=NULL; } else { +#ifdef ESPFS_DBG os_printf("Invalid compression: %d\n", h.compression); +#endif return NULL; } return r; diff --git a/html/console.js b/html/console.js new file mode 100644 index 0000000..87f7d1a --- /dev/null +++ b/html/console.js @@ -0,0 +1,72 @@ +function fetchText(delay, repeat) { + var el = $("#console"); + if (el.textEnd == undefined) { + el.textEnd = 0; + el.innerHTML = ""; + } + window.setTimeout(function() { + ajaxJson('GET', console_url + "?start=" + el.textEnd, + function(resp) { + var dly = updateText(resp); + if (repeat) fetchText(dly, repeat); + }, + function() { retryLoad(repeat); }); + }, delay); +} + +function updateText(resp) { + var el = $("#console"); + + var delay = 3000; + if (resp != null && resp.len > 0) { + console.log("updateText got", resp.len, "chars at", resp.start); + if (resp.start > el.textEnd) { + el.innerHTML = el.innerHTML.concat("\r\n'+baud+'')); + + $("#"+baud+"-button").addEventListener("click", function(e) { + e.preventDefault(); + ajaxSpin('POST', "/console/baud?rate="+baud, + function(resp) { showNotification("" + baud + " baud set"); showRate(baud); }, + function(s, st) { showWarning("Error setting baud rate: " + st); } + ); + }); +} + +//===== Log page + +function showDbgMode(mode) { + var btns = $('.dbg-btn'); + for (var i=0; i < btns.length; i++) { + if (btns[i].id === "dbg-"+mode) + addClass(btns[i], "button-selected"); + else + removeClass(btns[i], "button-selected"); + } +} diff --git a/html/favicon.ico b/html/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..bf372a1ce1a5468add7ffb6c17f1f431adede77e GIT binary patch literal 498 zcmVae+Y6JjdoD4Rr-D+HzZfGc75b2lRF>jE1No=0LrkgEht=$M$z8 zIEYYa2w2l#V|S!@z&Q0M85DUa_CWa1=f@d@hdHUY$k%83c*EN1zyrBDs#)_27F(%0 zH##focdN(4$9{EI8xuH0*rc8*F>)OC9kI-njf&TFc$- zS=^M}9{ql!A%BEhzusyd0mcVRyyyuG$m>$MP0^UeOE}LRLx1CP#nK0a-bBP?_u%P* zxKHB7Kn_1XGq!Cc$vnEy^~#-#XjQ9YvwL2Ij62t5eCsvHeFc%9~e(22$hw>W6bsbk&!kJWNE1>BnkzvC0 olOZdJ3K`P(;0xG~Wxu9f+qP%iv32uKA^SJ%)xwJ#7f=8IJJEdaM*si- literal 0 HcmV?d00001 diff --git a/html/head- b/html/head- index e69de29..514ff53 100644 --- a/html/head- +++ b/html/head- @@ -0,0 +1,10 @@ + + + esp-link + + + + + + +
diff --git a/html/home.html b/html/home.html index 2677264..46a984d 100644 --- a/html/home.html +++ b/html/home.html @@ -1 +1,87 @@ - +
+
+
JEELABS
+

esp-link

+

+
+ +
+
+
+

The JeeLabs esp-link firmware bridges the ESP8266 serial port to Wifi and can + program microcontrollers over the serial port, in particular Arduinos, AVRs, and + NXP's LPC800 and other ARM processors.

+

Program an Arduino/AVR using avrdude using a command + line similar to:

+
/home/arduino-1.0.5/hardware/tools/avrdude \
+   -DV -patmega328p -Pnet:esp-link.local:23 -carduino -b115200 -U \
+   -C /home/arduino-1.0.5/hardware/tools/avrdude.conf flash:w:my_sketch.hex:i +
+

where -Pnet:esp-link.local:23 tells avrdude to connect to port 23 of esp-link. + You can substitute the IP address of your esp-link for esp-link.local if necessary.

+

Please refer to + the online README + for up-to-date help and to the forthcoming + JeeLabs blog for an intro to the codebase.

+
+
+
+
+
+

Wifi summary

+
+ + + + + + + + +
+
+

TCP client

+
+ TCP client support in esp-link +
+ + +
+
+ Grovestreams data push +
+ + +
+
+ + +
+ +
+
+
+
+

Pin assignment

+ Select one of the following signal/pin assignments to match your hardware +
+
+
+
+
+
+
+
+
+
+ + + diff --git a/html/log.html b/html/log.html index 7bec267..46ec785 100644 --- a/html/log.html +++ b/html/log.html @@ -1 +1,48 @@ - +
+
+

Debug Log

+
+ +
+

The debug log shows the most recent characters printed by the esp-link software itself to + its own debug log.

+
+

+ Refresh +

+

+ UART debug log: + auto + off + on +

+
+

+    
+
+ + + + + + diff --git a/html/mqtt.html b/html/mqtt.html index 257c137..edddb88 100644 --- a/html/mqtt.html +++ b/html/mqtt.html @@ -28,27 +28,30 @@
+ + +
+
+

Special Settings

+
+ Special settings, use with care! +
+ + +
+
+ + +
+
+ + + + + + +
+ +
+
+
+ + + + + + + + diff --git a/html/wifi/wifi.js b/html/wifi/wifi.js new file mode 100644 index 0000000..0024248 --- /dev/null +++ b/html/wifi/wifi.js @@ -0,0 +1,200 @@ +var currAp = ""; +var blockScan = 0; + +function createInputForAp(ap) { + if (ap.essid=="" && ap.rssi==0) return; + + var input = e("input"); + input.type = "radio"; + input.name = "essid"; + input.value=ap.essid; + input.id = "opt-" + ap.essid; + if (currAp == ap.essid) input.checked = "1"; + + var bars = e("div"); + var rssiVal = -Math.floor(ap.rssi/51)*32; + bars.className = "lock-icon"; + bars.style.backgroundPosition = "0px "+rssiVal+"px"; + + var rssi = e("div"); + rssi.innerHTML = "" + ap.rssi +"dB"; + + var encrypt = e("div"); + var encVal = "-64"; //assume wpa/wpa2 + if (ap.enc == "0") encVal = "0"; //open + if (ap.enc == "1") encVal = "-32"; //wep + encrypt.className = "lock-icon"; + encrypt.style.backgroundPosition = "-32px "+encVal+"px"; + + var label = e("div"); + label.innerHTML = ap.essid; + + var div = m('').childNodes[0]; + div.appendChild(input); + div.appendChild(encrypt); + div.appendChild(bars); + div.appendChild(rssi); + div.appendChild(label); + return div; +} + +function getSelectedEssid() { + var e = document.forms.wifiform.elements; + for (var i=0; i 60) { + return scanAPs(); + } + scanReqCnt += 1; + ajaxJson('GET', "scan", function(data) { + currAp = getSelectedEssid(); + if (data.result.inProgress == "0" && data.result.APs.length > 1) { + $("#aps").innerHTML = ""; + var n = 0; + for (var i=0; i"+data.ip+", else connect to network "+data.ssid+" first."; + } else { + blockScan = 0; + showWarning("Connection failed: " + data.status + ", " + data.reason); + $("#aps").innerHTML = + "Check password and selected AP. Go Back"; + } + }, function(s, st) { + //showWarning("Can't get status: " + st); + window.setTimeout(getStatus, 2000); + }); +} + +function changeWifiMode(m) { + blockScan = 1; + hideWarning(); + ajaxSpin("POST", "setmode?mode=" + m, function(resp) { + showNotification("Mode changed"); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }, function(s, st) { + showWarning("Error changing mode: " + st); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }); +} + +function changeWifiAp(e) { + e.preventDefault(); + var passwd = $("#wifi-passwd").value; + var essid = getSelectedEssid(); + showNotification("Connecting to " + essid); + var url = "connect?essid="+encodeURIComponent(essid)+"&passwd="+encodeURIComponent(passwd); + + hideWarning(); + $("#reconnect").setAttribute("hidden", ""); + $("#wifi-passwd").value = ""; + var cb = $("#connect-button"); + var cn = cb.className; + cb.className += ' pure-button-disabled'; + blockScan = 1; + ajaxSpin("POST", url, function(resp) { + $("#spinner").removeAttribute('hidden'); // hack + showNotification("Waiting for network change..."); + window.scrollTo(0, 0); + window.setTimeout(getStatus, 2000); + }, function(s, st) { + showWarning("Error switching network: "+st); + cb.className = cn; + window.setTimeout(scanAPs, 1000); + }); +} + +function changeSpecial(e) { + e.preventDefault(); + var url = "special"; + url += "?dhcp=" + document.querySelector('input[name="dhcp"]:checked').value; + url += "&hostname=" + encodeURIComponent($("#wifi-hostname").value); + url += "&staticip=" + encodeURIComponent($("#wifi-staticip").value); + url += "&netmask=" + encodeURIComponent($("#wifi-netmask").value); + url += "&gateway=" + encodeURIComponent($("#wifi-gateway").value); + + hideWarning(); + var cb = $("#special-button"); + addClass(cb, 'pure-button-disabled'); + ajaxSpin("POST", url, function(resp) { + removeClass(cb, 'pure-button-disabled'); + getWifiInfo(); + }, function(s, st) { + showWarning("Error: "+st); + removeClass(cb, 'pure-button-disabled'); + getWifiInfo(); + }); +} + +function doDhcp() { + $('#dhcp-on').removeAttribute('hidden'); + $('#dhcp-off').setAttribute('hidden', ''); +} + +function doStatic() { + $('#dhcp-off').removeAttribute('hidden'); + $('#dhcp-on').setAttribute('hidden', ''); +} diff --git a/httpd/httpd.c b/httpd/httpd.c index bccbbb0..2db8051 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -3,15 +3,15 @@ Esp8266 http server - core routines */ /* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - * Modified and enhanced by Thorsten von Eicken in 2015 - * ---------------------------------------------------------------------------- - */ +* ---------------------------------------------------------------------------- +* "THE BEER-WARE LICENSE" (Revision 42): +* Jeroen Domburg wrote this file. As long as you retain +* this notice you can do whatever you want with this stuff. If we meet some day, +* and you think this stuff is worth it, you can buy me a beer in return. +* ---------------------------------------------------------------------------- +* Modified and enhanced by Thorsten von Eicken in 2015 +* ---------------------------------------------------------------------------- +*/ #include @@ -33,10 +33,10 @@ static HttpdBuiltInUrl *builtInUrls; //Private data for http connection struct HttpdPriv { - char head[MAX_HEAD_LEN]; - int headPos; - char *sendBuff; - int sendBuffLen; + char head[MAX_HEAD_LEN]; + int headPos; + char *sendBuff; + int sendBuffLen; }; //Connection pool @@ -50,36 +50,36 @@ static esp_tcp httpdTcp; //Struct to keep extension->mime data in typedef struct { - const char *ext; - const char *mimetype; + const char *ext; + const char *mimetype; } MimeMap; //The mappings from file extensions to mime types. If you need an extra mime type, //add it here. -static const MimeMap mimeTypes[]={ - {"htm", "text/htm"}, - {"html", "text/html; charset=UTF-8"}, - {"css", "text/css"}, - {"js", "text/javascript"}, - {"txt", "text/plain"}, - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - {"png", "image/png"}, - {"tpl", "text/html; charset=UTF-8"}, - {NULL, "text/html"}, //default value +static const MimeMap mimeTypes[] = { + { "htm", "text/htm" }, + { "html", "text/html; charset=UTF-8" }, + { "css", "text/css" }, + { "js", "text/javascript" }, + { "txt", "text/plain" }, + { "jpg", "image/jpeg" }, + { "jpeg", "image/jpeg" }, + { "png", "image/png" }, + { "tpl", "text/html; charset=UTF-8" }, + { NULL, "text/html" }, //default value }; //Returns a static char* to a mime type for a given url to a file. const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { - int i=0; - //Go find the extension - char *ext=url+(strlen(url)-1); - while (ext!=url && *ext!='.') ext--; - if (*ext=='.') ext++; - - //ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here... - while (mimeTypes[i].ext!=NULL && os_strcmp(ext, mimeTypes[i].ext)!=0) i++; - return mimeTypes[i].mimetype; + int i = 0; + //Go find the extension + char *ext = url + (strlen(url) - 1); + while (ext != url && *ext != '.') ext--; + if (*ext == '.') ext++; + + //ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here... + while (mimeTypes[i].ext != NULL && os_strcmp(ext, mimeTypes[i].ext) != 0) i++; + return mimeTypes[i].mimetype; } // debug string to identify connection (ip address & port) @@ -87,59 +87,65 @@ const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { static char connStr[24]; static void debugConn(void *arg, char *what) { - struct espconn *espconn = arg; - esp_tcp *tcp = espconn->proto.tcp; - os_sprintf(connStr, "%d.%d.%d.%d:%d", - tcp->remote_ip[0], tcp->remote_ip[1], tcp->remote_ip[2], tcp->remote_ip[3], - tcp->remote_port); - //os_printf("%s %s\n", connStr, what); + struct espconn *espconn = arg; + esp_tcp *tcp = espconn->proto.tcp; + os_sprintf(connStr, "%d.%d.%d.%d:%d", + tcp->remote_ip[0], tcp->remote_ip[1], tcp->remote_ip[2], tcp->remote_ip[3], + tcp->remote_port); + //os_printf("%s %s\n", connStr, what); } //Looks up the connData info for a specific esp connection static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { - struct espconn *espconn = arg; - for (int i=0; iproto.tcp->remote_port && - os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0) - { + struct espconn *espconn = arg; + for (int i = 0; iproto.tcp->remote_port && + os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0) + { #if 0 - os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]); - if (arg == connData[i].conn) os_printf("\n"); - else os_printf(" *** was 0x%p\n", connData[i].conn); +#ifdef HTTPD_DBG + os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]); + if (arg == connData[i].conn) os_printf("\n"); + else os_printf(" *** was 0x%p\n", connData[i].conn); +#endif #endif - if (arg != connData[i].conn) connData[i].conn = arg; // yes, this happens!? - return &connData[i]; - } - } - //Shouldn't happen. - os_printf("%s *** Unknown connection 0x%p\n", connStr, arg); - return NULL; + if (arg != connData[i].conn) connData[i].conn = arg; // yes, this happens!? + return &connData[i]; + } + } + //Shouldn't happen. +#ifdef HTTPD_DBG + os_printf("%s *** Unknown connection 0x%p\n", connStr, arg); +#endif + return NULL; } //Retires a connection for re-use static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) { - conn->conn = NULL; // don't try to send anything, the SDK crashes... - if (conn->cgi != NULL) conn->cgi(conn); // free cgi data - if (conn->post->buff != NULL) { - os_free(conn->post->buff); - } - conn->cgi=NULL; - conn->post->buff=NULL; - conn->remote_port = 0; - conn->remote_ip[0] = 0; - - uint32 dt = conn->startTime; - if (dt > 0) dt = (system_get_time() - dt)/1000; - os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt, - (unsigned long)system_get_free_heap_size()); + conn->conn = NULL; // don't try to send anything, the SDK crashes... + if (conn->cgi != NULL) conn->cgi(conn); // free cgi data + if (conn->post->buff != NULL) { + os_free(conn->post->buff); + } + conn->cgi = NULL; + conn->post->buff = NULL; + conn->remote_port = 0; + conn->remote_ip[0] = 0; + + uint32 dt = conn->startTime; + if (dt > 0) dt = (system_get_time() - dt) / 1000; +#ifdef HTTPD_DBG + os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt, + (unsigned long)system_get_free_heap_size()); +#endif } //Stupid li'l helper function that returns the value of a hex char. static int httpdHexVal(char c) { - if (c>='0' && c<='9') return c-'0'; - if (c>='A' && c<='F') return c-'A'+10; - if (c>='a' && c<='f') return c-'a'+10; - return 0; + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + return 0; } //Decode a percent-encoded value. @@ -147,27 +153,31 @@ static int httpdHexVal(char c) { //are stored in the ret buffer. Returns the actual amount of bytes used in ret. Also //zero-terminates the ret buffer. int httpdUrlDecode(char *val, int valLen, char *ret, int retLen) { - int s=0, d=0; - int esced=0, escVal=0; - while (s1) { - *ret++=*p++; - retLen--; - } - //Zero-terminate string - *ret=0; - //All done :) - return 1; - } - p+=strlen(p)+1; //Skip past end of string and \0 terminator - } - return 0; + char *p = conn->priv->head; + p = p + strlen(p) + 1; //skip GET/POST part + p = p + strlen(p) + 1; //skip HTTP part + while (p<(conn->priv->head + conn->priv->headPos)) { + while (*p <= 32 && *p != 0) p++; //skip crap at start + //See if this is the header + if (os_strncmp(p, header, strlen(header)) == 0 && p[strlen(header)] == ':') { + //Skip 'key:' bit of header line + p = p + strlen(header) + 1; + //Skip past spaces after the colon + while (*p == ' ') p++; + //Copy from p to end + while (*p != 0 && *p != '\r' && *p != '\n' && retLen>1) { + *ret++ = *p++; + retLen--; + } + //Zero-terminate string + *ret = 0; + //All done :) + return 1; + } + p += strlen(p) + 1; //Skip past end of string and \0 terminator + } + return 0; } //Start the response headers. void ICACHE_FLASH_ATTR httpdStartResponse(HttpdConnData *conn, int code) { - char buff[128]; - int l; - char *status = code < 400 ? "OK" : "ERROR"; - l = os_sprintf(buff, "HTTP/1.0 %d %s\r\nServer: esp-link\r\nConnection: close\r\n", code, status); - httpdSend(conn, buff, l); + char buff[128]; + int l; + char *status = code < 400 ? "OK" : "ERROR"; + l = os_sprintf(buff, "HTTP/1.0 %d %s\r\nServer: esp-link\r\nConnection: close\r\n", code, status); + httpdSend(conn, buff, l); } //Send a http header. void ICACHE_FLASH_ATTR httpdHeader(HttpdConnData *conn, const char *field, const char *val) { - char buff[256]; - int l; + char buff[256]; + int l; - l=os_sprintf(buff, "%s: %s\r\n", field, val); - httpdSend(conn, buff, l); + l = os_sprintf(buff, "%s: %s\r\n", field, val); + httpdSend(conn, buff, l); } //Finish the headers. void ICACHE_FLASH_ATTR httpdEndHeaders(HttpdConnData *conn) { - httpdSend(conn, "\r\n", -1); + httpdSend(conn, "\r\n", -1); } //ToDo: sprintf->snprintf everywhere... esp doesn't have snprintf tho' :/ //Redirect to the given URL. void ICACHE_FLASH_ATTR httpdRedirect(HttpdConnData *conn, char *newUrl) { - char buff[1024]; - int l; - l=os_sprintf(buff, "HTTP/1.0 302 Found\r\nServer: esp8266-link\r\nConnection: close\r\nLocation: %s\r\n\r\nRedirecting to %s\r\n", newUrl, newUrl); - httpdSend(conn, buff, l); + char buff[1024]; + int l; + l = os_sprintf(buff, "HTTP/1.0 302 Found\r\nServer: esp8266-link\r\nConnection: close\r\nLocation: %s\r\n\r\nRedirecting to %s\r\n", newUrl, newUrl); + httpdSend(conn, buff, l); } //Use this as a cgi function to redirect one url to another. int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - httpdRedirect(connData, (char*)connData->cgiArg); - return HTTPD_CGI_DONE; + if (connData->conn == NULL) { + //Connection aborted. Clean up. + return HTTPD_CGI_DONE; + } + httpdRedirect(connData, (char*)connData->cgiArg); + return HTTPD_CGI_DONE; } @@ -270,321 +280,349 @@ int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { //the data is seen as a C-string. //Returns 1 for success, 0 for out-of-memory. int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) { - if (len<0) len=strlen(data); - if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) { - os_printf("%s ERROR! httpdSend full (%d of %d)\n", - connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); - return 0; - } - os_memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len); - conn->priv->sendBuffLen+=len; - return 1; + if (len<0) len = strlen(data); + if (conn->priv->sendBuffLen + len>MAX_SENDBUFF_LEN) { +#ifdef HTTPD_DBG + os_printf("%s ERROR! httpdSend full (%d of %d)\n", + connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); +#endif + return 0; + } + os_memcpy(conn->priv->sendBuff + conn->priv->sendBuffLen, data, len); + conn->priv->sendBuffLen += len; + return 1; } //Helper function to send any data in conn->priv->sendBuff static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) { - if (conn->priv->sendBuffLen!=0) { - sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); - if (status != 0) { - os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status); - } - conn->priv->sendBuffLen=0; - } + if (conn->priv->sendBuffLen != 0) { + sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); + if (status != 0) { +#ifdef HTTPD_DBG + os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status); +#endif + } + conn->priv->sendBuffLen = 0; + } } //Callback called when the data on a socket has been successfully sent. static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { - debugConn(arg, "httpdSentCb"); - int r; - HttpdConnData *conn=httpdFindConnData(arg); - char sendBuff[MAX_SENDBUFF_LEN]; - - if (conn==NULL) return; - conn->priv->sendBuff=sendBuff; - conn->priv->sendBuffLen=0; - - if (conn->cgi==NULL) { //Marked for destruction? - //os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); - espconn_disconnect(conn->conn); // we will get a disconnect callback - return; //No need to call xmitSendBuff. - } - - r=conn->cgi(conn); //Execute cgi fn. - if (r==HTTPD_CGI_DONE) { - conn->cgi=NULL; //mark for destruction. - } - if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { - os_printf("%s ERROR! Bad CGI code %d\n", connStr, r); - conn->cgi=NULL; //mark for destruction. - } - xmitSendBuff(conn); + debugConn(arg, "httpdSentCb"); + int r; + HttpdConnData *conn = httpdFindConnData(arg); + char sendBuff[MAX_SENDBUFF_LEN]; + + if (conn == NULL) return; + conn->priv->sendBuff = sendBuff; + conn->priv->sendBuffLen = 0; + + if (conn->cgi == NULL) { //Marked for destruction? + //os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); + espconn_disconnect(conn->conn); // we will get a disconnect callback + return; //No need to call xmitSendBuff. + } + + r = conn->cgi(conn); //Execute cgi fn. + if (r == HTTPD_CGI_DONE) { + conn->cgi = NULL; //mark for destruction. + } + if (r == HTTPD_CGI_NOTFOUND || r == HTTPD_CGI_AUTHENTICATED) { +#ifdef HTTPD_DBG + os_printf("%s ERROR! Bad CGI code %d\n", connStr, r); +#endif + conn->cgi = NULL; //mark for destruction. + } + xmitSendBuff(conn); } -static const char *httpNotFoundHeader="HTTP/1.0 404 Not Found\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nNot Found.\r\n"; +static const char *httpNotFoundHeader = "HTTP/1.0 404 Not Found\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nNot Found.\r\n"; //This is called when the headers have been received and the connection is ready to send //the result headers and data. //We need to find the CGI function to call, call it, and dependent on what it returns either //find the next cgi function, wait till the cgi data is sent or close up the connection. static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { - int r; - int i=0; - if (conn->url==NULL) { - os_printf("%s WtF? url = NULL\n", connStr); - return; //Shouldn't happen - } - //See if we can find a CGI that's happy to handle the request. - while (1) { - //Look up URL in the built-in URL table. - while (builtInUrls[i].url!=NULL) { - int match=0; - //See if there's a literal match - if (os_strcmp(builtInUrls[i].url, conn->url)==0) match=1; - //See if there's a wildcard match - if (builtInUrls[i].url[os_strlen(builtInUrls[i].url)-1]=='*' && - os_strncmp(builtInUrls[i].url, conn->url, os_strlen(builtInUrls[i].url)-1)==0) match=1; - if (match) { - //os_printf("Is url index %d\n", i); - conn->cgiData=NULL; - conn->cgi=builtInUrls[i].cgiCb; - conn->cgiArg=builtInUrls[i].cgiArg; - break; - } - i++; - } - if (builtInUrls[i].url==NULL) { - //Drat, we're at the end of the URL table. This usually shouldn't happen. Well, just - //generate a built-in 404 to handle this. - os_printf("%s %s not found. 404!\n", connStr, conn->url); - httpdSend(conn, httpNotFoundHeader, -1); - xmitSendBuff(conn); - conn->cgi=NULL; //mark for destruction - return; - } - - //Okay, we have a CGI function that matches the URL. See if it wants to handle the - //particular URL we're supposed to handle. - r=conn->cgi(conn); - if (r==HTTPD_CGI_MORE) { - //Yep, it's happy to do so and has more data to send. - xmitSendBuff(conn); - return; - } else if (r==HTTPD_CGI_DONE) { - //Yep, it's happy to do so and already is done sending data. - xmitSendBuff(conn); - conn->cgi=NULL; //mark conn for destruction - return; - } else if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { - //URL doesn't want to handle the request: either the data isn't found or there's no - //need to generate a login screen. - i++; //look at next url the next iteration of the loop. - } - } + int r; + int i = 0; + if (conn->url == NULL) { +#ifdef HTTPD_DBG + os_printf("%s WtF? url = NULL\n", connStr); +#endif + return; //Shouldn't happen + } + //See if we can find a CGI that's happy to handle the request. + while (1) { + //Look up URL in the built-in URL table. + while (builtInUrls[i].url != NULL) { + int match = 0; + //See if there's a literal match + if (os_strcmp(builtInUrls[i].url, conn->url) == 0) match = 1; + //See if there's a wildcard match + if (builtInUrls[i].url[os_strlen(builtInUrls[i].url) - 1] == '*' && + os_strncmp(builtInUrls[i].url, conn->url, os_strlen(builtInUrls[i].url) - 1) == 0) match = 1; + if (match) { + //os_printf("Is url index %d\n", i); + conn->cgiData = NULL; + conn->cgi = builtInUrls[i].cgiCb; + conn->cgiArg = builtInUrls[i].cgiArg; + break; + } + i++; + } + if (builtInUrls[i].url == NULL) { + //Drat, we're at the end of the URL table. This usually shouldn't happen. Well, just + //generate a built-in 404 to handle this. +#ifdef HTTPD_DBG + os_printf("%s %s not found. 404!\n", connStr, conn->url); +#endif + httpdSend(conn, httpNotFoundHeader, -1); + xmitSendBuff(conn); + conn->cgi = NULL; //mark for destruction + return; + } + + //Okay, we have a CGI function that matches the URL. See if it wants to handle the + //particular URL we're supposed to handle. + r = conn->cgi(conn); + if (r == HTTPD_CGI_MORE) { + //Yep, it's happy to do so and has more data to send. + xmitSendBuff(conn); + return; + } + else if (r == HTTPD_CGI_DONE) { + //Yep, it's happy to do so and already is done sending data. + xmitSendBuff(conn); + conn->cgi = NULL; //mark conn for destruction + return; + } + else if (r == HTTPD_CGI_NOTFOUND || r == HTTPD_CGI_AUTHENTICATED) { + //URL doesn't want to handle the request: either the data isn't found or there's no + //need to generate a login screen. + i++; //look at next url the next iteration of the loop. + } + } } //Parse a line of header data and modify the connection data accordingly. static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { - int i; - char first_line = false; - - if (os_strncmp(h, "GET ", 4)==0) { - conn->requestType = HTTPD_METHOD_GET; - first_line = true; - } else if (os_strncmp(h, "POST ", 5)==0) { - conn->requestType = HTTPD_METHOD_POST; - first_line = true; - } - - if (first_line) { - char *e; - - //Skip past the space after POST/GET - i=0; - while (h[i]!=' ') i++; - conn->url=h+i+1; - - //Figure out end of url. - e=(char*)os_strstr(conn->url, " "); - if (e==NULL) return; //wtf? - *e=0; //terminate url part - - // Count number of open connections - int open = 0; - for (int j=0; jrequestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open); - //Parse out the URL part before the GET parameters. - conn->getArgs=(char*)os_strstr(conn->url, "?"); - if (conn->getArgs!=0) { - *conn->getArgs=0; - conn->getArgs++; - os_printf("%s args = %s\n", connStr, conn->getArgs); - } else { - conn->getArgs=NULL; - } - - } else if (os_strncmp(h, "Content-Length:", 15)==0) { - i=15; - //Skip trailing spaces - while (h[i]==' ') i++; - //Get POST data length - conn->post->len=atoi(h+i); - - // Allocate the buffer - if (conn->post->len > MAX_POST) { - // we'll stream this in in chunks - conn->post->buffSize = MAX_POST; - } else { - conn->post->buffSize = conn->post->len; - } - //os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); - conn->post->buff=(char*)os_malloc(conn->post->buffSize + 1); - conn->post->buffLen=0; - } else if (os_strncmp(h, "Content-Type: ", 14)==0) { - if (os_strstr(h, "multipart/form-data")) { - // It's multipart form data so let's pull out the boundary for future use - char *b; - if ((b = os_strstr(h, "boundary=")) != NULL) { - conn->post->multipartBoundary = b + 7; // move the pointer 2 chars before boundary then fill them with dashes - conn->post->multipartBoundary[0] = '-'; - conn->post->multipartBoundary[1] = '-'; - //os_printf("boundary = %s\n", conn->post->multipartBoundary); - } - } - } + int i; + char first_line = false; + + if (os_strncmp(h, "GET ", 4) == 0) { + conn->requestType = HTTPD_METHOD_GET; + first_line = true; + } + else if (os_strncmp(h, "POST ", 5) == 0) { + conn->requestType = HTTPD_METHOD_POST; + first_line = true; + } + + if (first_line) { + char *e; + + //Skip past the space after POST/GET + i = 0; + while (h[i] != ' ') i++; + conn->url = h + i + 1; + + //Figure out end of url. + e = (char*)os_strstr(conn->url, " "); + if (e == NULL) return; //wtf? + *e = 0; //terminate url part + + // Count number of open connections + int open = 0; + for (int j = 0; jrequestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open); +#endif + //Parse out the URL part before the GET parameters. + conn->getArgs = (char*)os_strstr(conn->url, "?"); + if (conn->getArgs != 0) { + *conn->getArgs = 0; + conn->getArgs++; +#ifdef HTTPD_DBG + os_printf("%s args = %s\n", connStr, conn->getArgs); +#endif + } + else { + conn->getArgs = NULL; + } + + } + else if (os_strncmp(h, "Content-Length:", 15) == 0) { + i = 15; + //Skip trailing spaces + while (h[i] == ' ') i++; + //Get POST data length + conn->post->len = atoi(h + i); + + // Allocate the buffer + if (conn->post->len > MAX_POST) { + // we'll stream this in in chunks + conn->post->buffSize = MAX_POST; + } + else { + conn->post->buffSize = conn->post->len; + } + //os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); + conn->post->buff = (char*)os_malloc(conn->post->buffSize + 1); + conn->post->buffLen = 0; + } + else if (os_strncmp(h, "Content-Type: ", 14) == 0) { + if (os_strstr(h, "multipart/form-data")) { + // It's multipart form data so let's pull out the boundary for future use + char *b; + if ((b = os_strstr(h, "boundary=")) != NULL) { + conn->post->multipartBoundary = b + 7; // move the pointer 2 chars before boundary then fill them with dashes + conn->post->multipartBoundary[0] = '-'; + conn->post->multipartBoundary[1] = '-'; + //os_printf("boundary = %s\n", conn->post->multipartBoundary); + } + } + } } //Callback called when there's data available on a socket. static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short len) { - debugConn(arg, "httpdRecvCb"); - int x; - char *p, *e; - char sendBuff[MAX_SENDBUFF_LEN]; - HttpdConnData *conn=httpdFindConnData(arg); - if (conn==NULL) return; - conn->priv->sendBuff=sendBuff; - conn->priv->sendBuffLen=0; - - //This is slightly evil/dirty: we abuse conn->post->len as a state variable for where in the http communications we are: - //<0 (-1): Post len unknown because we're still receiving headers - //==0: No post data - //>0: Need to receive post data - //ToDo: See if we can use something more elegant for this. - - for (x=0; xpost->len<0) { - //This byte is a header byte. - if (conn->priv->headPos!=MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++]=data[x]; - conn->priv->head[conn->priv->headPos]=0; - //Scan for /r/n/r/n. Receiving this indicate the headers end. - if (data[x]=='\n' && (char *)os_strstr(conn->priv->head, "\r\n\r\n")!=NULL) { - //Indicate we're done with the headers. - conn->post->len=0; - //Reset url data - conn->url=NULL; - //Iterate over all received headers and parse them. - p=conn->priv->head; - while(p<(&conn->priv->head[conn->priv->headPos-4])) { - e=(char *)os_strstr(p, "\r\n"); //Find end of header line - if (e==NULL) break; //Shouldn't happen. - e[0]=0; //Zero-terminate header - httpdParseHeader(p, conn); //and parse it. - p=e+2; //Skip /r/n (now /0/n) - } - //If we don't need to receive post data, we can send the response now. - if (conn->post->len==0) { - httpdProcessRequest(conn); - } - } - } else if (conn->post->len!=0) { - //This byte is a POST byte. - conn->post->buff[conn->post->buffLen++]=data[x]; - conn->post->received++; - if (conn->post->buffLen >= conn->post->buffSize || conn->post->received == conn->post->len) { - //Received a chunk of post data - conn->post->buff[conn->post->buffLen]=0; //zero-terminate, in case the cgi handler knows it can use strings - //Send the response. - httpdProcessRequest(conn); - conn->post->buffLen = 0; - } - } - } + debugConn(arg, "httpdRecvCb"); + int x; + char *p, *e; + char sendBuff[MAX_SENDBUFF_LEN]; + HttpdConnData *conn = httpdFindConnData(arg); + if (conn == NULL) return; + conn->priv->sendBuff = sendBuff; + conn->priv->sendBuffLen = 0; + + //This is slightly evil/dirty: we abuse conn->post->len as a state variable for where in the http communications we are: + //<0 (-1): Post len unknown because we're still receiving headers + //==0: No post data + //>0: Need to receive post data + //ToDo: See if we can use something more elegant for this. + + for (x = 0; xpost->len<0) { + //This byte is a header byte. + if (conn->priv->headPos != MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++] = data[x]; + conn->priv->head[conn->priv->headPos] = 0; + //Scan for /r/n/r/n. Receiving this indicate the headers end. + if (data[x] == '\n' && (char *)os_strstr(conn->priv->head, "\r\n\r\n") != NULL) { + //Indicate we're done with the headers. + conn->post->len = 0; + //Reset url data + conn->url = NULL; + //Iterate over all received headers and parse them. + p = conn->priv->head; + while (p<(&conn->priv->head[conn->priv->headPos - 4])) { + e = (char *)os_strstr(p, "\r\n"); //Find end of header line + if (e == NULL) break; //Shouldn't happen. + e[0] = 0; //Zero-terminate header + httpdParseHeader(p, conn); //and parse it. + p = e + 2; //Skip /r/n (now /0/n) + } + //If we don't need to receive post data, we can send the response now. + if (conn->post->len == 0) { + httpdProcessRequest(conn); + } + } + } + else if (conn->post->len != 0) { + //This byte is a POST byte. + conn->post->buff[conn->post->buffLen++] = data[x]; + conn->post->received++; + if (conn->post->buffLen >= conn->post->buffSize || conn->post->received == conn->post->len) { + //Received a chunk of post data + conn->post->buff[conn->post->buffLen] = 0; //zero-terminate, in case the cgi handler knows it can use strings + //Send the response. + httpdProcessRequest(conn); + conn->post->buffLen = 0; + } + } + } } static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) { - debugConn(arg, "httpdDisconCb"); - HttpdConnData *conn = httpdFindConnData(arg); - if (conn == NULL) return; - httpdRetireConn(conn); + debugConn(arg, "httpdDisconCb"); + HttpdConnData *conn = httpdFindConnData(arg); + if (conn == NULL) return; + httpdRetireConn(conn); } // 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 DisconCb after ReconCb static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) { - debugConn(arg, "httpdReconCb"); - HttpdConnData *conn = httpdFindConnData(arg); - os_printf("%s ***** reset, err=%d\n", connStr, err); - if (conn == NULL) return; - httpdRetireConn(conn); + debugConn(arg, "httpdReconCb"); + HttpdConnData *conn = httpdFindConnData(arg); +#ifdef HTTPD_DBG + os_printf("%s ***** reset, err=%d\n", connStr, err); +#endif + if (conn == NULL) return; + httpdRetireConn(conn); } static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) { - debugConn(arg, "httpdConnectCb"); - struct espconn *conn=arg; - int i; - //Find empty conndata in pool - for (i=0; iproto.tcp->remote_port; - os_memcpy(connData[i].remote_ip, conn->proto.tcp->remote_ip, 4); - connData[i].priv->headPos=0; - connData[i].post=&connPostData[i]; - connData[i].post->buff=NULL; - connData[i].post->buffLen=0; - connData[i].post->received=0; - connData[i].post->len=-1; - connData[i].startTime = system_get_time(); - - espconn_regist_recvcb(conn, httpdRecvCb); - espconn_regist_reconcb(conn, httpdReconCb); - espconn_regist_disconcb(conn, httpdDisconCb); - espconn_regist_sentcb(conn, httpdSentCb); - - espconn_set_opt(conn, ESPCONN_REUSEADDR|ESPCONN_NODELAY); + connData[i].priv = &connPrivData[i]; + connData[i].conn = conn; + connData[i].remote_port = conn->proto.tcp->remote_port; + os_memcpy(connData[i].remote_ip, conn->proto.tcp->remote_ip, 4); + connData[i].priv->headPos = 0; + connData[i].post = &connPostData[i]; + connData[i].post->buff = NULL; + connData[i].post->buffLen = 0; + connData[i].post->received = 0; + connData[i].post->len = -1; + connData[i].startTime = system_get_time(); + + espconn_regist_recvcb(conn, httpdRecvCb); + espconn_regist_reconcb(conn, httpdReconCb); + espconn_regist_disconcb(conn, httpdDisconCb); + espconn_regist_sentcb(conn, httpdSentCb); + + espconn_set_opt(conn, ESPCONN_REUSEADDR | ESPCONN_NODELAY); } //Httpd initialization routine. Call this to kick off webserver functionality. void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) { - int i; - - for (i=0; i #endif -//#define CMD_DBG -#define MQTT_RECONNECT_TIMEOUT 5 // seconds -#define MQTT_BUF_SIZE 512 -#define QUEUE_BUFFER_SIZE 512 -#define MQTT_HOST "10.0.0.220" // "mqtt.yourdomain.com" or ip "10.0.0.1" -#define MQTT_PORT 1883 -#define MQTT_SECURITY 0 - -#define MQTT_CLIENT_ID system_get_chip_id_str() // "esp-link" -#define MQTT_USER "" -#define MQTT_PASS "" -#define MQTT_KEEPALIVE 120 // seconds -#define MQTT_CLSESSION true - -#define PROTOCOL_NAMEv31 // MQTT version 3.1 compatible with Mosquitto v0.15/ -//PROTOCOL_NAMEv311 // MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/ +#define CMD_DBG +#define ESPFS_DBG +#define CGI_DBG +#define CGIFLASH_DBG +#define CGIMQTT_DBG +#define CGIPINS_DBG +#define CGIWIFI_DBG +#define CONFIG_DBG +#define LOG_DBG +#define STATUS_DBG +#define HTTPD_DBG +#define MQTT_DBG +#define MQTTCMD_DBG +#define PKTBUF_DBG +#define REST_DBG +#define RESTCMD_DBG +#define SERBR_DBG +#define SERLED_DBG +#define SLIP_DBG +#define UART_DBG +#define CHIP_IN_HOSTNAME + +//#define REST extern char* esp_link_version; - extern uint8_t UTILS_StrToIP(const char* str, void *ip); -extern void ICACHE_FLASH_ATTR init(void); - -extern char* ICACHE_FLASH_ATTR system_get_chip_id_str(); - #endif \ No newline at end of file diff --git a/mqtt/mqtt.c b/mqtt/mqtt.c index ba81b00..d65870b 100644 --- a/mqtt/mqtt.c +++ b/mqtt/mqtt.c @@ -57,10 +57,12 @@ sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length) // max message size for sending (except publish) #define MQTT_MAX_SHORT_MESSAGE 128 +#ifdef MQTT_DBG static char* mqtt_msg_type[] = { "NULL", "TYPE_CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT", "RESV", }; +#endif // forward declarations static void mqtt_enq_message(MQTT_Client *client, const uint8_t *data, uint16_t len); @@ -125,7 +127,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { if (msg_len > client->in_buffer_size) { // oops, too long a message for us to digest, disconnect and hope for a miracle +#ifdef MQTT_DBG os_printf("MQTT: Too long a message (%d bytes)\n", msg_len); +#endif mqtt_doAbort(client); return; } @@ -135,7 +139,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { if (client->connState != MQTT_CONNECTED) { // why are we receiving something?? +#ifdef MQTT_DBG os_printf("MQTT ERROR: recv in invalid state %d\n", client->connState); +#endif mqtt_doAbort(client); return; } @@ -147,13 +153,16 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { pending_msg_type = mqtt_get_type(client->pending_buffer->data); pending_msg_id = mqtt_get_id(client->pending_buffer->data, client->pending_buffer->filled); } - +#ifdef MQTT_DBG os_printf("MQTT: Recv type=%s id=%04X len=%d; Pend type=%s id=%02X\n", mqtt_msg_type[msg_type], msg_id, msg_len, mqtt_msg_type[pending_msg_type], pending_msg_id); +#endif switch (msg_type) { case MQTT_MSG_TYPE_CONNACK: +#ifdef MQTT_DBG os_printf("MQTT: Connect successful\n"); +#endif // callbacks for internal and external clients if (client->connectedCb) client->connectedCb((uint32_t*)client); if (client->cmdConnectedCb) client->cmdConnectedCb((uint32_t*)client); @@ -161,28 +170,36 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_SUBACK: if (pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: Subscribe successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_UNSUBACK: if (pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: Unsubscribe successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_PUBACK: // ack for a publish we sent if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: QoS1 Publish successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_PUBREC: // rec for a publish we sent if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: QoS2 publish cont\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); // we need to send PUBREL mqtt_msg_pubrel(&client->mqtt_connection, msg_id); @@ -193,7 +210,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_PUBCOMP: // comp for a pubrel we sent (originally publish we sent) if (pending_msg_type == MQTT_MSG_TYPE_PUBREL && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: QoS2 Publish successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; @@ -201,9 +220,11 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_PUBLISH: { // incoming publish // we may need to ACK the publish uint8_t msg_qos = mqtt_get_qos(client->in_buffer); +#ifdef MQTT_DBG uint16_t topic_length = msg_len; os_printf("MQTT: Recv PUBLISH qos=%d %s\n", msg_qos, mqtt_get_publish_topic(client->in_buffer, &topic_length)); +#endif if (msg_qos == 1) mqtt_msg_puback(&client->mqtt_connection, msg_id); if (msg_qos == 2) mqtt_msg_pubrec(&client->mqtt_connection, msg_id); if (msg_qos == 1 || msg_qos == 2) { @@ -217,7 +238,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_PUBREL: // rel for a rec we sent (originally publish received) if (pending_msg_type == MQTT_MSG_TYPE_PUBREC && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: Cont QoS2 recv\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); // we need to send PUBCOMP mqtt_msg_pubcomp(&client->mqtt_connection, msg_id); @@ -294,7 +317,9 @@ mqtt_timer(void* arg) { // check whether our last keep-alive timed out if (client->keepAliveAckTick > 0 && --client->keepAliveAckTick == 0) { +#ifdef MQTT_DBG os_printf("\nMQTT ERROR: Keep-alive timed out\n"); +#endif mqtt_doAbort(client); return; } @@ -337,15 +362,17 @@ void ICACHE_FLASH_ATTR mqtt_tcpclient_discon_cb(void* arg) { struct espconn* pespconn = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pespconn->reverse; - +#ifdef MQTT_DBG os_printf("MQTT: Disconnect CB, freeing espconn %p\n", arg); +#endif if (pespconn->proto.tcp) os_free(pespconn->proto.tcp); os_free(pespconn); // if this is an aborted connection we're done if (client == NULL) return; - +#ifdef MQTT_DBG os_printf("MQTT: Disconnected from %s:%d\n", client->host, client->port); +#endif if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client); if (client->cmdDisconnectedCb) client->cmdDisconnectedCb((uint32_t*)client); @@ -364,12 +391,14 @@ static void ICACHE_FLASH_ATTR mqtt_tcpclient_recon_cb(void* arg, int8_t err) { struct espconn* pespconn = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pespconn->reverse; - +#ifdef MQTT_DBG os_printf("MQTT: Reset CB, freeing espconn %p (err=%d)\n", arg, err); +#endif if (pespconn->proto.tcp) os_free(pespconn->proto.tcp); os_free(pespconn); - +#ifdef MQTT_DBG os_printf("MQTT: Connection reset from %s:%d\n", client->host, client->port); +#endif if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client); if (client->cmdDisconnectedCb) client->cmdDisconnectedCb((uint32_t*)client); @@ -394,7 +423,9 @@ mqtt_tcpclient_connect_cb(void* arg) { espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv); espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb); +#ifdef MQTT_DBG os_printf("MQTT: TCP connected to %s:%d\n", client->host, client->port); +#endif // send MQTT connect message to broker mqtt_msg_connect(&client->mqtt_connection, &client->connect_info); @@ -435,8 +466,9 @@ mqtt_send_message(MQTT_Client* client) { // get some details about the message uint16_t msg_type = mqtt_get_type(buf->data); uint8_t msg_id = mqtt_get_id(buf->data, buf->filled); + msg_id = msg_id; +#ifdef MQTT_DBG os_printf("MQTT: Send type=%s id=%04X len=%d\n", mqtt_msg_type[msg_type], msg_id, buf->filled); -#if 0 for (int i=0; ifilled; i++) { if (buf->data[i] >= ' ' && buf->data[i] <= '~') os_printf("%c", buf->data[i]); else os_printf("\\x%02X", buf->data[i]); @@ -481,17 +513,20 @@ mqtt_dns_found(const char* name, ip_addr_t* ipaddr, void* arg) { MQTT_Client* client = (MQTT_Client *)pConn->reverse; if (ipaddr == NULL) { +#ifdef MQTT_DBG os_printf("MQTT DNS: Got no ip, try to reconnect\n"); +#endif client->timeoutTick = 10; client->connState = TCP_RECONNECT_REQ; // the timer will kick-off a reconnection return; } - +#ifdef MQTT_DBG os_printf("MQTT DNS: found ip %d.%d.%d.%d\n", *((uint8 *)&ipaddr->addr), *((uint8 *)&ipaddr->addr + 1), *((uint8 *)&ipaddr->addr + 2), *((uint8 *)&ipaddr->addr + 3)); +#endif if (client->ip.addr == 0 && ipaddr->addr != 0) { os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); @@ -501,11 +536,15 @@ mqtt_dns_found(const char* name, ip_addr_t* ipaddr, void* arg) { else err = espconn_connect(client->pCon); if (err != 0) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Failed to connect\n"); +#endif client->connState = TCP_RECONNECT_REQ; client->timeoutTick = 10; } else { +#ifdef MQTT_DBG os_printf("MQTT: connecting...\n"); +#endif } } } @@ -539,7 +578,9 @@ MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t q uint16_t buf_len = 3 + 2 + 2 + topic_length + data_length + 16; PktBuf *buf = PktBuf_New(buf_len); if (buf == NULL) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Cannot allocate buffer for %d byte publish\n", buf_len); +#endif return FALSE; } // use a temporary mqtt_message_t pointing to our buffer, this is a bit of a mess because we @@ -548,13 +589,16 @@ MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t q msg_conn_init(&msg, &client->mqtt_connection, buf->data, buf_len); uint16_t msg_id; if (!mqtt_msg_publish(&msg, topic, data, data_length, qos, retain, &msg_id)){ +#ifdef MQTT_DBG os_printf("MQTT ERROR: Queuing Publish failed\n"); +#endif os_free(buf); return FALSE; } client->mqtt_connection.message_id = msg.message_id; - +#ifdef MQTT_DBG os_printf("MQTT: Publish, topic: \"%s\", length: %d\n", topic, msg.message.length); +#endif client->msgQueue = PktBuf_Push(client->msgQueue, buf); if (!client->sending && client->pending_buffer == NULL) { @@ -574,10 +618,14 @@ bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos) { uint16_t msg_id; if (!mqtt_msg_subscribe(&client->mqtt_connection, topic, 0, &msg_id)) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Queuing Subscribe failed (too long)\n"); +#endif return FALSE; } +#ifdef MQTT_DBG os_printf("MQTT: Subscribe, topic: \"%s\"\n", topic); +#endif mqtt_enq_message(client, client->mqtt_connection.message.data, client->mqtt_connection.message.length); return TRUE; @@ -595,14 +643,20 @@ MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos) { * @param client_user: MQTT client user * @param client_pass: MQTT client password * @param keepAliveTime: MQTT keep alive timer, in second -* @param cleanSession: MQTT ... +* @param cleanSession: On connection, a client sets the "clean session" flag, which is sometimes also known as the "clean start" flag. +* If clean session is set to false, then the connection is treated as durable. This means that when the client +* disconnects, any subscriptions it has will remain and any subsequent QoS 1 or 2 messages will be stored until +* it connects again in the future. If clean session is true, then all subscriptions will be removed for the client +* when it disconnects. * @retval None */ void ICACHE_FLASH_ATTR 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) { +#ifdef MQTT_DBG os_printf("MQTT_Init\n"); +#endif os_memset(mqttClient, 0, sizeof(MQTT_Client)); @@ -679,7 +733,9 @@ MQTT_Connect(MQTT_Client* mqttClient) { os_timer_arm(&mqttClient->mqttTimer, 1000, 1); // initiate the TCP connection or DNS lookup +#ifdef MQTT_DBG os_printf("MQTT: Connect to %s:%d %p\n", mqttClient->host, mqttClient->port, mqttClient->pCon); +#endif if (UTILS_StrToIP((const char *)mqttClient->host, (void*)&mqttClient->pCon->proto.tcp->remote_ip)) { uint8_t err; @@ -688,7 +744,9 @@ MQTT_Connect(MQTT_Client* mqttClient) { else err = espconn_connect(mqttClient->pCon); if (err != 0) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Failed to connect\n"); +#endif os_free(mqttClient->pCon->proto.tcp); os_free(mqttClient->pCon); mqttClient->pCon = NULL; @@ -707,7 +765,9 @@ MQTT_Connect(MQTT_Client* mqttClient) { static void ICACHE_FLASH_ATTR mqtt_doAbort(MQTT_Client* client) { +#ifdef MQTT_DBG os_printf("MQTT: Disconnecting from %s:%d (%p)\n", client->host, client->port, client->pCon); +#endif client->pCon->reverse = NULL; // ensure we jettison this pCon... if (client->security) espconn_secure_disconnect(client->pCon); diff --git a/mqtt/mqtt_cmd.c b/mqtt/mqtt_cmd.c index d2a01e2..ed2eb68 100644 --- a/mqtt/mqtt_cmd.c +++ b/mqtt/mqtt_cmd.c @@ -8,11 +8,13 @@ void ICACHE_FLASH_ATTR cmdMqttConnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: Connected connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n", (void*)cb->connectedCb, (void*)cb->disconnectedCb, (void*)cb->publishedCb, (void*)cb->dataCb); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->connectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -21,7 +23,9 @@ void ICACHE_FLASH_ATTR cmdMqttTcpDisconnectedCb(uint32_t *args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb *cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: TCP Disconnected\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -30,7 +34,9 @@ void ICACHE_FLASH_ATTR cmdMqttDisconnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: Disconnected\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -39,7 +45,9 @@ void ICACHE_FLASH_ATTR cmdMqttPublishedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: Published\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -103,8 +111,9 @@ MQTTCMD_Setup(CmdPacket *cmd) { // get clean session CMD_PopArg(&req, (uint8_t*)&clean_session, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Setup clientid=%s, user=%s, pw=%s, keepalive=%ld, clean_session=%ld\n", client_id, user_data, pass_data, keepalive, clean_session); +#endif // init client // TODO: why malloc these all here, pass to MQTT_InitClient to be malloc'd again? @@ -155,7 +164,9 @@ MQTTCMD_Lwt(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; @@ -182,12 +193,13 @@ MQTTCMD_Lwt(CmdPacket *cmd) { // get retain CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%d, retain=%d\n", client->connect_info.will_topic, client->connect_info.will_message, client->connect_info.will_qos, client->connect_info.will_retain); +#endif return 1; } @@ -203,7 +215,9 @@ MQTTCMD_Connect(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Connect client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; @@ -221,11 +235,12 @@ MQTTCMD_Connect(CmdPacket *cmd) { // get security CMD_PopArg(&req, (uint8_t*)&client->security, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Connect host=%s, port=%d, security=%d\n", client->host, client->port, client->security); +#endif MQTT_Connect(client); return 1; @@ -243,7 +258,9 @@ MQTTCMD_Disconnect(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Disconnect client ptr=%p\n", (void*)client_ptr); +#endif // disconnect MQTT_Disconnect(client); @@ -262,7 +279,9 @@ MQTTCMD_Publish(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; uint8_t *topic, *data; @@ -293,12 +312,13 @@ MQTTCMD_Publish(CmdPacket *cmd) { // get retain CMD_PopArg(&req, (uint8_t*)&retain, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Publish topic=%s, data_len=%d, qos=%ld, retain=%ld\n", topic, os_strlen((char*)data), qos, retain); +#endif MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain); os_free(topic); @@ -318,7 +338,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; uint8_t* topic; @@ -333,8 +355,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) { // get qos CMD_PopArg(&req, (uint8_t*)&qos, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos); +#endif MQTT_Subscribe(client, (char*)topic, (uint8_t)qos); os_free(topic); return 1; diff --git a/mqtt/pktbuf.c b/mqtt/pktbuf.c index 2984fb4..a3ac7af 100644 --- a/mqtt/pktbuf.c +++ b/mqtt/pktbuf.c @@ -3,7 +3,8 @@ #include #include "pktbuf.h" -void ICACHE_FLASH_ATTR +#ifdef PKTBUF_DBG +static void ICACHE_FLASH_ATTR PktBuf_Print(PktBuf *buf) { os_printf("PktBuf:"); for (int i=-16; i<0; i++) @@ -15,6 +16,7 @@ PktBuf_Print(PktBuf *buf) { os_printf("PktBuf: next=%p len=0x%04x\n", ((void**)buf)[-4], ((uint16_t*)buf)[-6]); } +#endif PktBuf * ICACHE_FLASH_ATTR diff --git a/mqtt/pktbuf.h b/mqtt/pktbuf.h index 0c8ff2c..bccd60a 100644 --- a/mqtt/pktbuf.h +++ b/mqtt/pktbuf.h @@ -24,6 +24,4 @@ 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 diff --git a/rest/rest.c b/rest/rest.c index 40b62de..fbbd358 100644 --- a/rest/rest.c +++ b/rest/rest.c @@ -73,16 +73,20 @@ tcpclient_recv(void *arg, char *pdata, unsigned short len) { // collect body and send it uint16_t crc; int body_len = len-pi; +#ifdef REST_DBG os_printf("REST: status=%ld, body=%d\n", code, body_len); +#endif if (pi == len) { crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 0); } else { crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 1); crc = CMD_ResponseBody(crc, (uint8_t*)(pdata+pi), body_len); CMD_ResponseEnd(crc); +#ifdef REST_DBG os_printf("REST: body="); for (int j=pi; jsecurity) @@ -96,7 +100,9 @@ static void ICACHE_FLASH_ATTR tcpclient_sent_cb(void *arg) { struct espconn *pCon = (struct espconn *)arg; RestClient* client = (RestClient *)pCon->reverse; +#ifdef REST_DBG os_printf("REST: Sent\n"); +#endif if (client->data_sent != client->data_len) { // we only sent part of the buffer, send the rest espconn_sent(client->pCon, (uint8_t*)(client->data+client->data_sent), @@ -113,14 +119,17 @@ static void ICACHE_FLASH_ATTR tcpclient_connect_cb(void *arg) { struct espconn *pCon = (struct espconn *)arg; RestClient* client = (RestClient *)pCon->reverse; +#ifdef REST_DBG os_printf("REST #%d: connected\n", client-restClient); - +#endif espconn_regist_disconcb(client->pCon, tcpclient_discon_cb); espconn_regist_recvcb(client->pCon, tcpclient_recv); espconn_regist_sentcb(client->pCon, tcpclient_sent_cb); client->data_sent = client->data_len <= 1400 ? client->data_len : 1400; +#ifdef REST_DBG os_printf("REST #%d: sending %d\n", client-restClient, client->data_sent); +#endif //if(client->security){ // espconn_secure_sent(client->pCon, client->data, client->data_sent); //} @@ -133,7 +142,9 @@ static void ICACHE_FLASH_ATTR tcpclient_recon_cb(void *arg, sint8 errType) { struct espconn *pCon = (struct espconn *)arg; RestClient* client = (RestClient *)pCon->reverse; +#ifdef REST_DBG os_printf("REST #%d: conn reset\n", client-restClient); +#endif } static void ICACHE_FLASH_ATTR @@ -142,16 +153,18 @@ rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { RestClient* client = (RestClient *)pConn->reverse; if(ipaddr == NULL) { +#ifdef REST_DBG os_printf("REST DNS: Got no ip, try to reconnect\n"); +#endif return; } - +#ifdef REST_DBG os_printf("REST DNS: found ip %d.%d.%d.%d\n", *((uint8 *) &ipaddr->addr), *((uint8 *) &ipaddr->addr + 1), *((uint8 *) &ipaddr->addr + 2), *((uint8 *) &ipaddr->addr + 3)); - +#endif if(client->ip.addr == 0 && ipaddr->addr != 0) { os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); #ifdef CLIENT_SSL_ENABLE @@ -159,8 +172,10 @@ rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { espconn_secure_connect(client->pCon); } else #endif - espconn_connect(client->pCon); + espconn_connect(client->pCon); +#ifdef REST_DBG os_printf("REST: connecting...\n"); +#endif } } @@ -213,8 +228,9 @@ REST_Setup(CmdPacket *cmd) { os_free(client->pCon); } os_memset(client, 0, sizeof(RestClient)); - +#ifdef CMDREST_DBG os_printf("REST: setup #%d host=%s port=%ld security=%ld\n", clientNum, rest_host, port, security); +#endif client->resp_cb = cmd->callback; @@ -273,7 +289,9 @@ REST_SetHeader(CmdPacket *cmd) { client->header[len] = '\r'; client->header[len+1] = '\n'; client->header[len+2] = 0; +#ifdef CMDREST_DBG os_printf("REST: Set header: %s\r\n", client->header); +#endif break; case HEADER_CONTENT_TYPE: if(client->content_type) os_free(client->content_type); @@ -282,7 +300,9 @@ REST_SetHeader(CmdPacket *cmd) { client->content_type[len] = '\r'; client->content_type[len+1] = '\n'; client->content_type[len+2] = 0; +#ifdef CMDREST_DBG os_printf("REST: Set content_type: %s\r\n", client->content_type); +#endif break; case HEADER_USER_AGENT: if(client->user_agent) os_free(client->user_agent); @@ -291,7 +311,9 @@ REST_SetHeader(CmdPacket *cmd) { client->user_agent[len] = '\r'; client->user_agent[len+1] = '\n'; client->user_agent[len+2] = 0; +#ifdef CMDREST_DBG os_printf("REST: Set user_agent: %s\r\n", client->user_agent); +#endif break; } return 1; @@ -301,32 +323,36 @@ uint32_t ICACHE_FLASH_ATTR REST_Request(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef CMDREST_DBG os_printf("REST: request"); - +#endif // Get client uint32_t clientNum; if (CMD_PopArg(&req, (uint8_t*)&clientNum, 4)) goto fail; if ((clientNum & 0xffff0000) != REST_CB) goto fail; clientNum &= 0xffff; RestClient *client = restClient + clientNum % MAX_REST; +#ifdef CMDREST_DBG os_printf(" #%ld", clientNum); - +#endif // Get HTTP method uint16_t len = CMD_ArgLen(&req); if (len > 15) goto fail; char method[16]; CMD_PopArg(&req, method, len); method[len] = 0; +#ifdef CMDREST_DBG os_printf(" method=%s", method); - +#endif // Get HTTP path len = CMD_ArgLen(&req); if (len > 1023) goto fail; char path[1024]; CMD_PopArg(&req, path, len); path[len] = 0; +#ifdef CMDREST_DBG os_printf(" path=%s", path); - +#endif // Get HTTP body uint32_t realLen = 0; if (CMD_GetArgc(&req) == 3) { @@ -338,7 +364,9 @@ REST_Request(CmdPacket *cmd) { len = CMD_ArgLen(&req); if (len > 2048 || realLen > len) goto fail; } +#ifdef CMDREST_DBG os_printf(" bodyLen=%ld", realLen); +#endif // we need to allocate memory for the header plus the body. First we count the length of the // header (including some extra counted "%s" and then we add the body length. We allocate the @@ -353,30 +381,40 @@ REST_Request(CmdPacket *cmd) { "User-Agent: %s\r\n\r\n"; uint16_t headerLen = strlen(headerFmt) + strlen(method) + strlen(path) + strlen(client->host) + strlen(client->header) + strlen(client->content_type) + strlen(client->user_agent); +#ifdef CMDREST_DBG os_printf(" hdrLen=%d", headerLen); +#endif if (client->data) os_free(client->data); client->data = (char*)os_zalloc(headerLen + realLen); if (client->data == NULL) goto fail; +#ifdef CMDREST_DBG os_printf(" totLen=%ld data=%p", headerLen + realLen, client->data); +#endif client->data_len = os_sprintf((char*)client->data, headerFmt, method, path, client->host, client->header, realLen, client->content_type, client->user_agent); +#ifdef CMDREST_DBG os_printf(" hdrLen=%d", client->data_len); +#endif if (realLen > 0) { CMD_PopArg(&req, client->data + client->data_len, realLen); client->data_len += realLen; } +#ifdef CMDREST_DBG os_printf("\n"); //os_printf("REST request: %s", (char*)client->data); os_printf("REST: pCon state=%d\n", client->pCon->state); +#endif client->pCon->state = ESPCONN_NONE; espconn_regist_connectcb(client->pCon, tcpclient_connect_cb); espconn_regist_reconcb(client->pCon, tcpclient_recon_cb); if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.tcp->remote_ip)) { +#ifdef CMDREST_DBG os_printf("REST: Connect to ip %s:%ld\n",client->host, client->port); +#endif //if(client->security){ // espconn_secure_connect(client->pCon); //} @@ -384,13 +422,17 @@ REST_Request(CmdPacket *cmd) { espconn_connect(client->pCon); //} } else { +#ifdef CMDREST_DBG os_printf("REST: Connect to host %s:%ld\n", client->host, client->port); +#endif espconn_gethostbyname(client->pCon, (char *)client->host, &client->ip, rest_dns_found); } return 1; fail: +#ifdef CMDREST_DBG os_printf("\n"); +#endif return 0; } diff --git a/serial/serbridge.c b/serial/serbridge.c index b91dbbc..ea5c848 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -100,10 +100,15 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state) switch (c) { case DTR_ON: if (mcu_reset_pin >= 0) { +#ifdef SERBR_DBG os_printf("MCU reset gpio%d\n", mcu_reset_pin); +#endif GPIO_OUTPUT_SET(mcu_reset_pin, 0); os_delay_us(100L); - } else os_printf("MCU reset: no pin\n"); + } +#ifdef SERBR_DBG + else os_printf("MCU reset: no pin\n"); +#endif break; case DTR_OFF: if (mcu_reset_pin >= 0) { @@ -113,10 +118,15 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state) break; case RTS_ON: if (mcu_isp_pin >= 0) { +#ifdef SERBR_DBG os_printf("MCU ISP gpio%d\n", mcu_isp_pin); +#endif GPIO_OUTPUT_SET(mcu_isp_pin, 0); os_delay_us(100L); - } else os_printf("MCU isp: no pin\n"); + } +#ifdef SERBR_DBG + else os_printf("MCU isp: no pin\n"); +#endif slip_disabled++; break; case RTS_OFF: @@ -137,11 +147,16 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state) // Generate a reset pulse for the attached microcontroller void ICACHE_FLASH_ATTR serbridgeReset() { if (mcu_reset_pin >= 0) { +#ifdef SERBR_DBG os_printf("MCU reset gpio%d\n", mcu_reset_pin); +#endif GPIO_OUTPUT_SET(mcu_reset_pin, 0); os_delay_us(100L); GPIO_OUTPUT_SET(mcu_reset_pin, 1); - } else os_printf("MCU reset: no pin\n"); + } +#ifdef SERBR_DBG + else os_printf("MCU reset: no pin\n"); +#endif } // Receive callback @@ -162,7 +177,9 @@ static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned sh if ((len == 2 && strncmp(data, "0 ", 2) == 0) || (len == 2 && strncmp(data, "?\n", 2) == 0) || (len == 3 && strncmp(data, "?\r\n", 3) == 0)) { +#ifdef SERBR_DBG os_printf("MCU Reset=gpio%d ISP=gpio%d\n", mcu_reset_pin, mcu_isp_pin); +#endif os_delay_us(2*1000L); // time for os_printf to happen // send reset to arduino/ARM if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 0); @@ -177,14 +194,18 @@ static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned sh slip_disabled++; // disable SLIP so it doesn't interfere with flashing // If the connection starts with a telnet negotiation we will do telnet - } else if (len >= 3 && strncmp(data, (char[]){IAC, WILL, ComPortOpt}, 3) == 0) { + } + else if (len >= 3 && strncmp(data, (char[]){IAC, WILL, ComPortOpt}, 3) == 0) { conn->conn_mode = cmTelnet; conn->telnet_state = TN_normal; // note that the three negotiation chars will be gobbled-up by telnetUnwrap +#ifdef SERBR_DBG os_printf("telnet mode\n"); +#endif // looks like a plain-vanilla connection! - } else { + } + else { conn->conn_mode = cmTransparent; } @@ -218,9 +239,11 @@ sendtxbuffer(serbridgeConnData *conn) { conn->readytosend = false; result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen); conn->txbufferlen = 0; +#ifdef SERBR_DBG if (result != ESPCONN_OK) { os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn); } +#endif } return result; } @@ -233,7 +256,9 @@ sendtxbuffer(serbridgeConnData *conn) { static sint8 ICACHE_FLASH_ATTR espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) { if (conn->txbufferlen + len > MAX_TXBUFFER) { +#ifdef SERBR_DBG os_printf("espbuffsend: txbuffer full on conn %p\n", conn); +#endif return -128; } os_memcpy(conn->txbuffer + conn->txbufferlen, data, len); @@ -323,10 +348,14 @@ static void ICACHE_FLASH_ATTR serbridgeConnectCb(void *arg) { // Find empty conndata in pool int i; for (i=0; i= ' ' && slip_buf[i] <= '~') os_printf("%c", slip_buf[i]); @@ -54,6 +56,7 @@ slip_process() { os_printf("\\%02X", slip_buf[i]); } os_printf("\n"); +#endif } } } @@ -83,7 +86,9 @@ slip_parse_char(char c) { if (slip_len > 0) console_process(slip_buf, slip_len); slip_reset(); slip_inpkt = true; +#ifdef SLIP_DBG os_printf("SLIP: start\n"); +#endif return; } } else if (slip_escaped) { diff --git a/cmd/tcpclient.c b/tcpclient/tcpclient.c similarity index 100% rename from cmd/tcpclient.c rename to tcpclient/tcpclient.c diff --git a/cmd/tcpclient.h b/tcpclient/tcpclient.h similarity index 100% rename from cmd/tcpclient.h rename to tcpclient/tcpclient.h diff --git a/user/latch_json.c b/user/latch_json.c new file mode 100644 index 0000000..0994894 --- /dev/null +++ b/user/latch_json.c @@ -0,0 +1,64 @@ +#include "latch_json.h" +#include "user_funcs.h" +#include +#include +#include + +static LatchState latch; + +static void ICACHE_FLASH_ATTR +updateLatch() { + os_printf("ESP: Latch Callback\n"); + cmdCallback* latchCb = CMD_GetCbByName("Latch"); + if (latchCb->callback != -1) { + uint16_t crc = CMD_ResponseStart(CMD_CB_EVENTS, (uint32_t)&latchCb->callback, 0, 1); + crc = CMD_ResponseBody(crc, (uint8_t*)&latch, sizeof(LatchState)); + CMD_ResponseEnd(crc); + } +} + +static int ICACHE_FLASH_ATTR +latchGet(struct jsontree_context *js_ctx) { + return 0; +} + +static int ICACHE_FLASH_ATTR +latchSet(struct jsontree_context *js_ctx, struct jsonparse_state *parser) { + int type; + int ix = -1; + while ((type = jsonparse_next(parser)) != 0) { + if (type == JSON_TYPE_ARRAY) { + ix = -1; + } + else if (type == JSON_TYPE_OBJECT) { + ix++; + } + else if (type == JSON_TYPE_PAIR_NAME) { + if (jsonparse_strcmp_value(parser, "states") == 0) { + char latchStates[9]; + jsonparse_next(parser); jsonparse_next(parser); + jsonparse_copy_value(parser, latchStates, sizeof(latchStates)); + os_printf("latch states %s\n", latchStates); + uint8_t states = binToByte(latchStates); + latch.stateBits = states; + } + else if (jsonparse_strcmp_value(parser, "fallbackstates") == 0) { + char fallbackStates[9]; + jsonparse_next(parser); jsonparse_next(parser); + jsonparse_copy_value(parser, fallbackStates, sizeof(fallbackStates)); + os_printf("latch states %s\n", fallbackStates); + uint8_t fbstates = binToByte(fallbackStates); + latch.fallbackStateBits = fbstates; + } + } + } + return 0; +} + +static struct jsontree_callback latchCallback = JSONTREE_CALLBACK(latchGet, latchSet); +static char* latchQueueName; + +JSONTREE_OBJECT(latchJsonObj, + JSONTREE_PAIR("states", &latchCallback), + JSONTREE_PAIR("fallbackstates", &latchCallback)); + diff --git a/user/latch_json.h b/user/latch_json.h new file mode 100644 index 0000000..0bc4135 --- /dev/null +++ b/user/latch_json.h @@ -0,0 +1,12 @@ +#ifndef _LATCH_JSON_H_ +#define _LATCH_JSON_H_ +#include + +typedef struct { + uint8_t fallbackStateBits; + uint8_t stateBits; + uint8_t init; + uint8_t fallbackSecondsForBits[8]; +} LatchState; + +#endif // _LATCH_JSON_H_ \ No newline at end of file diff --git a/user/user_funcs.c b/user/user_funcs.c index bdb082b..49dedbd 100644 --- a/user/user_funcs.c +++ b/user/user_funcs.c @@ -1,6 +1,7 @@ #include "user_funcs.h" -bool ICACHE_FLASH_ATTR pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, uint8_t offMinute) { +bool ICACHE_FLASH_ATTR +pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, uint8_t offMinute) { uint16_t NumMinsToday = totalMinutes(hour(), minute()); bool state = false; @@ -19,7 +20,8 @@ bool ICACHE_FLASH_ATTR pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, return state; } -const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) { +const char* ICACHE_FLASH_ATTR +byteToBin(uint8_t num) { static char b[9]; b[0] = '\0'; @@ -30,7 +32,8 @@ const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) { return b; } -const uint8_t ICACHE_FLASH_ATTR binToByte(char* bin_str) { +const uint8_t ICACHE_FLASH_ATTR +binToByte(char* bin_str) { char * tmp; long x = strtol(bin_str, &tmp, 2); return (x <= 255) ? (uint8_t)x : -1; diff --git a/user/user_funcs.h b/user/user_funcs.h index 156e432..b1da228 100644 --- a/user/user_funcs.h +++ b/user/user_funcs.h @@ -7,4 +7,5 @@ bool pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, u const char* byteToBin(uint8_t num); const uint8_t binToByte(char* bin_str); + #endif // _USER_FUNCS_H_ \ No newline at end of file diff --git a/user/user_main.c b/user/user_main.c index cd0dbf0..a796e14 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -1,38 +1,14 @@ #include #include "cgiwifi.h" -#include "mqtt.h" +#include +#include +#include "latch_json.h" +#include "user_funcs.h" -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; +//static ETSTimer mqttTimer; void ICACHE_FLASH_ATTR mqttConnectedCb(uint32_t *args) { @@ -60,11 +36,10 @@ mqttPublishedCb(uint32_t *args) { void ICACHE_FLASH_ATTR mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) { +// MQTT_Client* client = (MQTT_Client*)args; 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; @@ -76,12 +51,33 @@ mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *da 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 +void ICACHE_FLASH_ATTR +wifiStateChangeCb(uint8_t status) { + if (flashConfig.mqtt_enable) { + if (status == wifiGotIP && mqttClient.connState != TCP_CONNECTING) { + MQTT_Connect(&mqttClient); + } + else if (status == wifiIsDisconnected && mqttClient.connState == TCP_CONNECTING) { + MQTT_Disconnect(&mqttClient); + } + } +} + +// initialize the custom stuff that goes beyond esp-link +void app_init() { + if (flashConfig.mqtt_enable) { + MQTT_Init(&mqttClient, flashConfig.mqtt_host, flashConfig.mqtt_port, 0, flashConfig.mqtt_timeout, + flashConfig.mqtt_clientid, flashConfig.mqtt_username, flashConfig.mqtt_password, flashConfig.mqtt_keepalive, flashConfig.mqtt_clean_session + ); + + 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); + } + + wifiAddStateChangeCb(wifiStateChangeCb); +} + From b080f5243b103e564284fcbe1db033c4fb9677bd Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Fri, 11 Sep 2015 16:48:56 -0500 Subject: [PATCH 8/8] Fixed whitespace --- esp-link/cgi.c | 68 ++++++++-------- esp-link/log.c | 212 ++++++++++++++++++++++++------------------------- 2 files changed, 140 insertions(+), 140 deletions(-) diff --git a/esp-link/cgi.c b/esp-link/cgi.c index c99bada..1c870f5 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -18,17 +18,17 @@ Some random cgi routines. #include "cgi.h" 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"); + 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); + httpdHeader(connData, "Content-Type", "application/json"); + httpdEndHeaders(connData); } void ICACHE_FLASH_ATTR @@ -119,43 +119,43 @@ UTILS_StrToIP(const char* str, void *ip){ // Handle system information variables and print their value, returns the number of // characters appended to buff int ICACHE_FLASH_ATTR printGlobalInfo(char *buff, int buflen, char *token) { - if (TOKEN("si_chip_id")) { - return os_sprintf(buff, "0x%x", system_get_chip_id()); - } else if (TOKEN("si_freeheap")) { - return os_sprintf(buff, "%dKB", system_get_free_heap_size()/1024); - } else if (TOKEN("si_uptime")) { - uint32 t = system_get_time() / 1000000; // in seconds - return os_sprintf(buff, "%dd%dh%dm%ds", t/(24*3600), (t/(3600))%24, (t/60)%60, t%60); - } else if (TOKEN("si_boot_version")) { - return os_sprintf(buff, "%d", system_get_boot_version()); - } else if (TOKEN("si_boot_address")) { - return os_sprintf(buff, "0x%x", system_get_userbin_addr()); - } else if (TOKEN("si_cpu_freq")) { - return os_sprintf(buff, "%dMhz", system_get_cpu_freq()); - } else { - return 0; - } + if (TOKEN("si_chip_id")) { + return os_sprintf(buff, "0x%x", system_get_chip_id()); + } else if (TOKEN("si_freeheap")) { + return os_sprintf(buff, "%dKB", system_get_free_heap_size()/1024); + } else if (TOKEN("si_uptime")) { + uint32 t = system_get_time() / 1000000; // in seconds + return os_sprintf(buff, "%dd%dh%dm%ds", t/(24*3600), (t/(3600))%24, (t/60)%60, t%60); + } else if (TOKEN("si_boot_version")) { + return os_sprintf(buff, "%d", system_get_boot_version()); + } else if (TOKEN("si_boot_address")) { + return os_sprintf(buff, "0x%x", system_get_userbin_addr()); + } else if (TOKEN("si_cpu_freq")) { + return os_sprintf(buff, "%dMhz", system_get_cpu_freq()); + } else { + return 0; + } } #endif extern char *esp_link_version; // in user_main.c int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) { - if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - char buff[1024]; - // don't use jsonHeader so the response does get cached - httpdStartResponse(connData, 200); - httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); - httpdHeader(connData, "Content-Type", "application/json"); - httpdEndHeaders(connData); - // construct json response - os_sprintf(buff, + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + char buff[1024]; + // don't use jsonHeader so the response does get cached + httpdStartResponse(connData, 200); + httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); + httpdHeader(connData, "Content-Type", "application/json"); + httpdEndHeaders(connData); + // construct json response + os_sprintf(buff, "{\"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; + " \"version\": \"%s\" }", esp_link_version); + httpdSend(connData, buff, -1); + return HTTPD_CGI_DONE; } diff --git a/esp-link/log.c b/esp-link/log.c index 713b9c3..ca8e0ad 100644 --- a/esp-link/log.c +++ b/esp-link/log.c @@ -22,139 +22,139 @@ static bool log_newline; // at start of a new line // when we connect to wifi AP. Here this is gated by the flash setting void ICACHE_FLASH_ATTR log_uart(bool enable) { - if (!enable && !log_no_uart && flashConfig.log_mode != LOG_MODE_ON) { - // we're asked to turn uart off, and uart is on, and the flash setting isn't always-on + if (!enable && !log_no_uart && flashConfig.log_mode != LOG_MODE_ON) { + // we're asked to turn uart off, and uart is on, and the flash setting isn't always-on #if 1 #ifdef LOG_DBG - os_printf("Turning OFF uart log\n"); + os_printf("Turning OFF uart log\n"); #endif - os_delay_us(4*1000L); // time for uart to flush - log_no_uart = !enable; + os_delay_us(4*1000L); // time for uart to flush + log_no_uart = !enable; #endif - } else if (enable && log_no_uart && flashConfig.log_mode != LOG_MODE_OFF) { - // we're asked to turn uart on, and uart is off, and the flash setting isn't always-off - log_no_uart = !enable; + } else if (enable && log_no_uart && flashConfig.log_mode != LOG_MODE_OFF) { + // we're asked to turn uart on, and uart is off, and the flash setting isn't always-off + log_no_uart = !enable; #ifdef LOG_DBG - os_printf("Turning ON uart log\n"); + os_printf("Turning ON uart log\n"); #endif - } + } } static void ICACHE_FLASH_ATTR log_write(char c) { - log_buf[log_wr] = c; - log_wr = (log_wr+1) % BUF_MAX; - if (log_wr == log_rd) { - log_rd = (log_rd+1) % BUF_MAX; // full, eat first char - log_pos++; - } + log_buf[log_wr] = c; + log_wr = (log_wr+1) % BUF_MAX; + if (log_wr == log_rd) { + log_rd = (log_rd+1) % BUF_MAX; // full, eat first char + log_pos++; + } } #if 0 static char ICACHE_FLASH_ATTR log_read(void) { - char c = 0; - if (log_rd != log_wr) { - c = log_buf[log_rd]; - log_rd = (log_rd+1) % BUF_MAX; - } - return c; + char c = 0; + if (log_rd != log_wr) { + c = log_buf[log_rd]; + log_rd = (log_rd+1) % BUF_MAX; + } + return c; } #endif static void ICACHE_FLASH_ATTR log_write_char(char c) { - // Uart output unless disabled - if (!log_no_uart) { - if (log_newline) { - char buff[16]; - int l = os_sprintf(buff, "%6d> ", (system_get_time()/1000)%1000000); - for (int i=0; i ", (system_get_time()/1000)%1000000); + for (int i=0; iconn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - jsonHeader(connData, 200); - - // figure out where to start in buffer based on URI param - len = httpdFindArg(connData->getArgs, "start", buff, sizeof(buff)); - if (len > 0) { - start = atoi(buff); - if (start < log_pos) { - start = 0; - } else if (start >= log_pos+log_len) { - start = log_len; - } else { - start = start - log_pos; - } - } - - // start outputting - len = os_sprintf(buff, "{\"len\":%d, \"start\":%d, \"text\": \"", - log_len-start, log_pos+start); - - int rd = (log_rd+start) % BUF_MAX; - while (len < 2040 && rd != log_wr) { - uint8_t c = log_buf[rd]; - if (c == '\\' || c == '"') { - buff[len++] = '\\'; - buff[len++] = c; - } else if (c < ' ') { - len += os_sprintf(buff+len, "\\u%04x", c); - } else { - buff[len++] = c; - } - rd = (rd + 1) % BUF_MAX; - } - os_strcpy(buff+len, "\"}"); len+=2; - httpdSend(connData, buff, len); - return HTTPD_CGI_DONE; + char buff[2048]; + int len; // length of text in buff + int log_len = (log_wr+BUF_MAX-log_rd) % BUF_MAX; // num chars in log_buf + int start = 0; // offset onto log_wr to start sending out chars + + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + jsonHeader(connData, 200); + + // figure out where to start in buffer based on URI param + len = httpdFindArg(connData->getArgs, "start", buff, sizeof(buff)); + if (len > 0) { + start = atoi(buff); + if (start < log_pos) { + start = 0; + } else if (start >= log_pos+log_len) { + start = log_len; + } else { + start = start - log_pos; + } + } + + // start outputting + len = os_sprintf(buff, "{\"len\":%d, \"start\":%d, \"text\": \"", + log_len-start, log_pos+start); + + int rd = (log_rd+start) % BUF_MAX; + while (len < 2040 && rd != log_wr) { + uint8_t c = log_buf[rd]; + if (c == '\\' || c == '"') { + buff[len++] = '\\'; + buff[len++] = c; + } else if (c < ' ') { + len += os_sprintf(buff+len, "\\u%04x", c); + } else { + buff[len++] = c; + } + rd = (rd + 1) % BUF_MAX; + } + os_strcpy(buff+len, "\"}"); len+=2; + httpdSend(connData, buff, len); + return HTTPD_CGI_DONE; } static char *dbg_mode[] = { "auto", "off", "on" }; int ICACHE_FLASH_ATTR ajaxLogDbg(HttpdConnData *connData) { - if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. - char buff[512]; - int len, status = 400; - len = httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); - if (len > 0) { - int8_t mode = -1; - if (os_strcmp(buff, "auto") == 0) mode = LOG_MODE_AUTO; - if (os_strcmp(buff, "off") == 0) mode = LOG_MODE_OFF; - if (os_strcmp(buff, "on") == 0) mode = LOG_MODE_ON; - if (mode >= 0) { - flashConfig.log_mode = mode; - if (mode != LOG_MODE_AUTO) log_uart(mode == LOG_MODE_ON); - status = configSave() ? 200 : 400; - } - } else if (connData->requestType == HTTPD_METHOD_GET) { - status = 200; - } - - jsonHeader(connData, status); - os_sprintf(buff, "{\"mode\": \"%s\"}", dbg_mode[flashConfig.log_mode]); - httpdSend(connData, buff, -1); - return HTTPD_CGI_DONE; + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + char buff[512]; + int len, status = 400; + len = httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); + if (len > 0) { + int8_t mode = -1; + if (os_strcmp(buff, "auto") == 0) mode = LOG_MODE_AUTO; + if (os_strcmp(buff, "off") == 0) mode = LOG_MODE_OFF; + if (os_strcmp(buff, "on") == 0) mode = LOG_MODE_ON; + if (mode >= 0) { + flashConfig.log_mode = mode; + if (mode != LOG_MODE_AUTO) log_uart(mode == LOG_MODE_ON); + status = configSave() ? 200 : 400; + } + } else if (connData->requestType == HTTPD_METHOD_GET) { + status = 200; + } + + jsonHeader(connData, status); + os_sprintf(buff, "{\"mode\": \"%s\"}", dbg_mode[flashConfig.log_mode]); + httpdSend(connData, buff, -1); + return HTTPD_CGI_DONE; } void ICACHE_FLASH_ATTR dumpMem(void *addr, int len) { @@ -172,9 +172,9 @@ void ICACHE_FLASH_ATTR dumpMem(void *addr, int len) { } void ICACHE_FLASH_ATTR logInit() { - log_no_uart = flashConfig.log_mode == LOG_MODE_OFF; // ON unless set to always-off - log_wr = 0; - log_rd = 0; + log_no_uart = flashConfig.log_mode == LOG_MODE_OFF; // ON unless set to always-off + log_wr = 0; + log_rd = 0; os_install_putc1((void *)log_write_char); }