mirror of https://github.com/jeelabs/esp-link.git
Merge branch 'master' of https://github.com/jeelabs/esp-link
commit
1feb736c24
@ -1,315 +0,0 @@ |
||||
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
|
||||
//
|
||||
// TCP client library allowing uControllers attached to the serial port to send commands
|
||||
// to open/close TCP connections and send/recv data.
|
||||
// The serial protocol is described in https://gist.github.com/tve/a46c44bf1f6b42bc572e
|
||||
|
||||
#include <esp8266.h> |
||||
#include "config.h" |
||||
#include "uart.h" |
||||
#include "serled.h" |
||||
#include "tcpclient.h" |
||||
|
||||
// max number of channels the client can open
|
||||
#define MAX_CHAN MAX_TCP_CHAN |
||||
// size of tx buffer
|
||||
#define MAX_TXBUF 1024 |
||||
|
||||
enum TcpState { |
||||
TCP_idle, // unused connection
|
||||
TCP_dns, // doing gethostbyname
|
||||
TCP_conn, // connecting to remote server
|
||||
TCP_data, // connected
|
||||
}; |
||||
|
||||
// Connections
|
||||
typedef struct { |
||||
struct espconn *conn; // esp connection structure
|
||||
esp_tcp *tcp; // esp TCP parameters
|
||||
char *txBuf; // buffer to accumulate into
|
||||
char *txBufSent; // buffer held by espconn
|
||||
uint8_t txBufLen; // number of chars in txbuf
|
||||
enum TcpState state; |
||||
} TcpConn; |
||||
|
||||
static TcpConn tcpConn[MAX_CHAN]; |
||||
|
||||
// forward declarations
|
||||
static void tcpConnFree(TcpConn* tci); |
||||
static TcpConn* tcpConnAlloc(uint8_t chan); |
||||
static void tcpDoSend(TcpConn *tci); |
||||
static void tcpConnectCb(void *arg); |
||||
static void tcpDisconCb(void *arg); |
||||
static void tcpResetCb(void *arg, sint8 err); |
||||
static void tcpSentCb(void *arg); |
||||
static void tcpRecvCb(void *arg, char *data, uint16_t len); |
||||
|
||||
//===== allocate / free connections
|
||||
|
||||
// Allocate a new connection dynamically and return it. Returns NULL if buf alloc failed
|
||||
static TcpConn* ICACHE_FLASH_ATTR |
||||
tcpConnAlloc(uint8_t chan) { |
||||
TcpConn *tci = tcpConn+chan; |
||||
if (tci->state != TCP_idle && tci->conn != NULL) return tci; |
||||
|
||||
// malloc and return espconn struct
|
||||
tci->conn = os_malloc(sizeof(struct espconn)); |
||||
if (tci->conn == NULL) goto fail; |
||||
memset(tci->conn, 0, sizeof(struct espconn)); |
||||
// malloc esp_tcp struct
|
||||
tci->tcp = os_malloc(sizeof(esp_tcp)); |
||||
if (tci->tcp == NULL) goto fail; |
||||
memset(tci->tcp, 0, sizeof(esp_tcp)); |
||||
|
||||
// common init
|
||||
tci->state = TCP_dns; |
||||
tci->conn->type = ESPCONN_TCP; |
||||
tci->conn->state = ESPCONN_NONE; |
||||
tci->conn->proto.tcp = tci->tcp; |
||||
tci->tcp->remote_port = 80; |
||||
espconn_regist_connectcb(tci->conn, tcpConnectCb); |
||||
espconn_regist_reconcb(tci->conn, tcpResetCb); |
||||
espconn_regist_sentcb(tci->conn, tcpSentCb); |
||||
espconn_regist_recvcb(tci->conn, tcpRecvCb); |
||||
espconn_regist_disconcb(tci->conn, tcpDisconCb); |
||||
tci->conn->reverse = tci; |
||||
|
||||
return tci; |
||||
|
||||
fail: |
||||
tcpConnFree(tci); |
||||
return NULL; |
||||
} |
||||
|
||||
// Free a connection dynamically.
|
||||
static void ICACHE_FLASH_ATTR |
||||
tcpConnFree(TcpConn* tci) { |
||||
if (tci->conn != NULL) os_free(tci->conn); |
||||
if (tci->tcp != NULL) os_free(tci->tcp); |
||||
if (tci->txBuf != NULL) os_free(tci->txBuf); |
||||
if (tci->txBufSent != NULL) os_free(tci->txBufSent); |
||||
memset(tci, 0, sizeof(TcpConn)); |
||||
} |
||||
|
||||
//===== DNS
|
||||
|
||||
// DNS name resolution callback
|
||||
static void ICACHE_FLASH_ATTR |
||||
tcpClientHostnameCb(const char *name, ip_addr_t *ipaddr, void *arg) { |
||||
struct espconn *conn = arg; |
||||
TcpConn *tci = conn->reverse; |
||||
os_printf("TCP dns CB (%p %p)\n", arg, tci); |
||||
if (ipaddr == NULL) { |
||||
os_printf("TCP %s not found\n", name); |
||||
} else { |
||||
os_printf("TCP %s -> %d.%d.%d.%d\n", name, IP2STR(ipaddr)); |
||||
tci->tcp->remote_ip[0] = ip4_addr1(ipaddr); |
||||
tci->tcp->remote_ip[1] = ip4_addr2(ipaddr); |
||||
tci->tcp->remote_ip[2] = ip4_addr3(ipaddr); |
||||
tci->tcp->remote_ip[3] = ip4_addr4(ipaddr); |
||||
os_printf("TCP connect %d.%d.%d.%d (%p)\n", IP2STR(tci->tcp->remote_ip), tci); |
||||
if (espconn_connect(tci->conn) == ESPCONN_OK) { |
||||
tci->state = TCP_conn; |
||||
return; |
||||
} |
||||
os_printf("TCP connect failure\n"); |
||||
} |
||||
// oops
|
||||
tcpConnFree(tci); |
||||
} |
||||
|
||||
//===== Connect / disconnect
|
||||
|
||||
// Connected callback
|
||||
static void ICACHE_FLASH_ATTR |
||||
tcpConnectCb(void *arg) { |
||||
struct espconn *conn = arg; |
||||
TcpConn *tci = conn->reverse; |
||||
os_printf("TCP connect CB (%p %p)\n", arg, tci); |
||||
tci->state = TCP_data; |
||||
// send any buffered data
|
||||
if (tci->txBuf != NULL && tci->txBufLen > 0) tcpDoSend(tci); |
||||
// reply to serial
|
||||
char buf[6]; |
||||
short l = os_sprintf(buf, "\n~@%dC\n", tci-tcpConn); |
||||
uart0_tx_buffer(buf, l); |
||||
} |
||||
|
||||
// Disconnect callback
|
||||
static void ICACHE_FLASH_ATTR tcpDisconCb(void *arg) { |
||||
struct espconn *conn = arg; |
||||
TcpConn *tci = conn->reverse; |
||||
os_printf("TCP disconnect CB (%p %p)\n", arg, tci); |
||||
// notify to serial
|
||||
char buf[6]; |
||||
short l = os_sprintf(buf, "\n~@%dZ\n", tci-tcpConn); |
||||
uart0_tx_buffer(buf, l); |
||||
// free
|
||||
tcpConnFree(tci); |
||||
} |
||||
|
||||
// Connection reset callback
|
||||
static void ICACHE_FLASH_ATTR tcpResetCb(void *arg, sint8 err) { |
||||
struct espconn *conn = arg; |
||||
TcpConn *tci = conn->reverse; |
||||
os_printf("TCP reset CB (%p %p) err=%d\n", arg, tci, err); |
||||
// notify to serial
|
||||
char buf[6]; |
||||
short l = os_sprintf(buf, "\n~@%dZ\n", tci-tcpConn); |
||||
uart0_tx_buffer(buf, l); |
||||
// free
|
||||
tcpConnFree(tci); |
||||
} |
||||
|
||||
//===== Sending and receiving
|
||||
|
||||
// Send the next buffer (assumes that the connection is in a state that allows it)
|
||||
static void ICACHE_FLASH_ATTR |
||||
tcpDoSend(TcpConn *tci) { |
||||
sint8 err = espconn_sent(tci->conn, (uint8*)tci->txBuf, tci->txBufLen); |
||||
if (err == ESPCONN_OK) { |
||||
// send successful
|
||||
os_printf("TCP sent (%p %p)\n", tci->conn, tci); |
||||
tci->txBuf[tci->txBufLen] = 0; os_printf("TCP data: %s\n", tci->txBuf); |
||||
tci->txBufSent = tci->txBuf; |
||||
tci->txBuf = NULL; |
||||
tci->txBufLen = 0; |
||||
} else { |
||||
// send error, leave as-is and try again later...
|
||||
os_printf("TCP send err (%p %p) %d\n", tci->conn, tci, err); |
||||
} |
||||
} |
||||
|
||||
// Sent callback
|
||||
static void ICACHE_FLASH_ATTR |
||||
tcpSentCb(void *arg) { |
||||
struct espconn *conn = arg; |
||||
TcpConn *tci = conn->reverse; |
||||
os_printf("TCP sent CB (%p %p)\n", arg, tci); |
||||
if (tci->txBufSent != NULL) os_free(tci->txBufSent); |
||||
tci->txBufSent = NULL; |
||||
|
||||
if (tci->txBuf != NULL && tci->txBufLen == MAX_TXBUF) { |
||||
// next buffer is full, send it now
|
||||
tcpDoSend(tci); |
||||
} |
||||
} |
||||
|
||||
// Recv callback
|
||||
static void ICACHE_FLASH_ATTR tcpRecvCb(void *arg, char *data, uint16_t len) { |
||||
struct espconn *conn = arg; |
||||
TcpConn *tci = conn->reverse; |
||||
os_printf("TCP recv CB (%p %p)\n", arg, tci); |
||||
if (tci->state == TCP_data) { |
||||
uint8_t chan; |
||||
for (chan=0; chan<MAX_CHAN && tcpConn+chan!=tci; chan++) |
||||
if (chan >= MAX_CHAN) return; // oops!?
|
||||
char buf[6]; |
||||
short l = os_sprintf(buf, "\n~%d", chan); |
||||
uart0_tx_buffer(buf, l); |
||||
uart0_tx_buffer(data, len); |
||||
uart0_tx_buffer("\0\n", 2); |
||||
} |
||||
serledFlash(50); // short blink on serial LED
|
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
tcpClientSendChar(uint8_t chan, char c) { |
||||
TcpConn *tci = tcpConn+chan; |
||||
if (tci->state == TCP_idle) return; |
||||
|
||||
if (tci->txBuf != NULL) { |
||||
// we have a buffer
|
||||
if (tci->txBufLen < MAX_TXBUF) { |
||||
// buffer has space, add char and return
|
||||
tci->txBuf[tci->txBufLen++] = c; |
||||
return; |
||||
} else if (tci->txBufSent == NULL) { |
||||
// we don't have a send pending, send full buffer off
|
||||
if (tci->state == TCP_data) tcpDoSend(tci); |
||||
if (tci->txBuf != NULL) return; // something went wrong
|
||||
} else { |
||||
// buffers all backed-up, drop char
|
||||
return; |
||||
} |
||||
} |
||||
// we do not have a buffer (either didn't have one or sent it off)
|
||||
// allocate one
|
||||
tci->txBuf = os_malloc(MAX_TXBUF); |
||||
tci->txBufLen = 0; |
||||
if (tci->txBuf != NULL) { |
||||
tci->txBuf[tci->txBufLen++] = c; |
||||
} |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
tcpClientSendPush(uint8_t chan) { |
||||
TcpConn *tci = tcpConn+chan; |
||||
if (tci->state != TCP_data) return; // no active connection on this channel
|
||||
if (tci->txBuf == NULL || tci->txBufLen == 0) return; // no chars accumulated to send
|
||||
if (tci->txBufSent != NULL) return; // already got a send in progress
|
||||
tcpDoSend(tci); |
||||
} |
||||
|
||||
//===== Command parsing
|
||||
|
||||
// Perform a TCP command: parse the command and do the right thing.
|
||||
// Returns true on success.
|
||||
bool ICACHE_FLASH_ATTR |
||||
tcpClientCommand(uint8_t chan, char cmd, char *cmdBuf) { |
||||
TcpConn *tci; |
||||
char *hostname; |
||||
char *port; |
||||
|
||||
// copy the command so we can modify it
|
||||
char buf[128]; |
||||
os_strncpy(buf, cmdBuf, 128); |
||||
buf[127] = 0; |
||||
|
||||
switch (cmd) { |
||||
//== TCP Connect command
|
||||
case 'T': |
||||
hostname = buf; |
||||
port = hostname; |
||||
while (*port != 0 && *port != ':') port++; |
||||
if (*port != ':') break; |
||||
*port = 0; |
||||
port++; |
||||
int portInt = atoi(port); |
||||
if (portInt < 1 || portInt > 65535) break; |
||||
|
||||
// allocate a connection
|
||||
tci = tcpConnAlloc(chan); |
||||
if (tci == NULL) break; |
||||
tci->state = TCP_dns; |
||||
tci->tcp->remote_port = portInt; |
||||
|
||||
// start the DNS resolution
|
||||
os_printf("TCP %p resolving %s for chan %d (conn=%p)\n", tci, hostname, chan ,tci->conn); |
||||
ip_addr_t ip; |
||||
err_t err = espconn_gethostbyname(tci->conn, hostname, &ip, tcpClientHostnameCb); |
||||
if (err == ESPCONN_OK) { |
||||
// dns cache hit, got the IP address, fake the callback (sigh)
|
||||
os_printf("TCP DNS hit\n"); |
||||
tcpClientHostnameCb(hostname, &ip, tci->conn); |
||||
} else if (err != ESPCONN_INPROGRESS) { |
||||
tcpConnFree(tci); |
||||
break; |
||||
} |
||||
|
||||
return true; |
||||
|
||||
//== TCP Close/disconnect command
|
||||
case 'C': |
||||
os_printf("TCP closing chan %d\n", chan); |
||||
tci = tcpConn+chan; |
||||
if (tci->state > TCP_idle) { |
||||
tci->state = TCP_idle; // hackish...
|
||||
espconn_disconnect(tci->conn); |
||||
} |
||||
break; |
||||
|
||||
} |
||||
return false; |
||||
} |
||||
|
@ -1,16 +0,0 @@ |
||||
#ifndef __TCP_CLIENT_H__ |
||||
#define __TCP_CLIENT_H__ |
||||
|
||||
// max number of channels the client can open
|
||||
#define MAX_TCP_CHAN 8 |
||||
|
||||
// Parse and perform the command, cmdBuf must be null-terminated
|
||||
bool tcpClientCommand(uint8_t chan, char cmd, char *cmdBuf); |
||||
|
||||
// Append a character to the specified channel
|
||||
void tcpClientSendChar(uint8_t chan, char c); |
||||
|
||||
// Enqueue the buffered characters for transmission on the specified channel
|
||||
void tcpClientSendPush(uint8_t chan); |
||||
|
||||
#endif /* __TCP_CLIENT_H__ */ |
@ -0,0 +1,89 @@ |
||||
#include <esp8266.h> |
||||
#include "cgiwifi.h" |
||||
#include "config.h" |
||||
#include "mqtt.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, flashConfig.mqtt_hostname, flashConfig.mqtt_port, 0, 2, |
||||
flashConfig.mqtt_client, flashConfig.mqtt_username, flashConfig.mqtt_password, 60); |
||||
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, 200, 0); |
||||
} |
||||
} |
||||
|
||||
|
||||
// initialize the custom stuff that goes beyond esp-link
|
||||
void mqtt_client_init() { |
||||
wifiAddStateChangeCb(wifiStateChangeCb); |
||||
} |
||||
|
||||
|
||||
#if 0 |
||||
MQTT_Client mqttClient; |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
mqttConnectedCb(uint32_t *args) { |
||||
MQTT_Client* client = (MQTT_Client*)args; |
||||
MQTT_Publish(client, "announce/all", "Hello World!", 0, 0); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
mqttDisconnectedCb(uint32_t *args) { |
||||
// MQTT_Client* client = (MQTT_Client*)args;
|
||||
os_printf("MQTT Disconnected\n"); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
mqttTcpDisconnectedCb(uint32_t *args) { |
||||
// MQTT_Client* client = (MQTT_Client*)args;
|
||||
os_printf("MQTT TCP Disconnected\n"); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
mqttPublishedCb(uint32_t *args) { |
||||
// MQTT_Client* client = (MQTT_Client*)args;
|
||||
os_printf("MQTT Published\n"); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) { |
||||
char *topicBuf = (char*)os_zalloc(topic_len + 1); |
||||
char *dataBuf = (char*)os_zalloc(data_len + 1); |
||||
|
||||
// MQTT_Client* client = (MQTT_Client*)args;
|
||||
|
||||
os_memcpy(topicBuf, topic, topic_len); |
||||
topicBuf[topic_len] = 0; |
||||
|
||||
os_memcpy(dataBuf, data, data_len); |
||||
dataBuf[data_len] = 0; |
||||
|
||||
os_printf("Receive topic: %s, data: %s\n", topicBuf, dataBuf); |
||||
os_free(topicBuf); |
||||
os_free(dataBuf); |
||||
} |
||||
|
||||
MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, MQTT_SECURITY); |
||||
MQTT_InitClient(&mqttClient, MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, MQTT_KEEPALIVE, MQTT_CLSESSION); |
||||
MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0); |
||||
MQTT_OnConnected(&mqttClient, mqttConnectedCb); |
||||
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb); |
||||
MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb); |
||||
MQTT_OnPublished(&mqttClient, mqttPublishedCb); |
||||
MQTT_OnData(&mqttClient, mqttDataCb); |
||||
#endif |
Loading…
Reference in new issue