mirror of
https://github.com/jeelabs/esp-link.git
synced 2026-03-24 18:06:51 +01:00
Added functionality for UDP socket client, TCP socket client and server
Added tools (download links in Makefile are not working) Adjusted Makefile Adjusted .gitignore
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -15,6 +15,6 @@ esp-link.opensdf
|
||||
esp-link.sdf
|
||||
espfs/mkespfsimage/mman-win32/libmman.a
|
||||
.localhistory/
|
||||
tools/
|
||||
#tools/
|
||||
local.conf
|
||||
*.tgz
|
||||
|
||||
17
Makefile
17
Makefile
@@ -58,6 +58,7 @@ XTENSA_TOOLS_ROOT ?= $(abspath ../esp-open-sdk/xtensa-lx106-elf/bin)/
|
||||
# WARNING: if you change this expect to make code adjustments elsewhere, don't expect
|
||||
# that esp-link will magically work with a different version of the SDK!!!
|
||||
SDK_VERS ?= esp_iot_sdk_v1.5.4
|
||||
#SDK_VERS ?= esp_iot_sdk_v2.0.0
|
||||
|
||||
# Try to find the firmware manually extracted, e.g. after downloading from Espressif's BBS,
|
||||
# http://bbs.espressif.com/viewforum.php?f=46
|
||||
@@ -101,7 +102,7 @@ LED_SERIAL_PIN ?= 14
|
||||
# --------------- esp-link modules config options ---------------
|
||||
|
||||
# Optional Modules mqtt
|
||||
MODULES ?= mqtt rest syslog
|
||||
MODULES ?= mqtt rest tcp udp syslog
|
||||
|
||||
# --------------- esphttpd config options ---------------
|
||||
|
||||
@@ -216,6 +217,14 @@ ifneq (,$(findstring rest,$(MODULES)))
|
||||
CFLAGS += -DREST
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring tcp,$(MODULES)))
|
||||
CFLAGS += -DTCP
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring udp,$(MODULES)))
|
||||
CFLAGS += -DUDP
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring syslog,$(MODULES)))
|
||||
CFLAGS += -DSYSLOG
|
||||
endif
|
||||
@@ -409,9 +418,9 @@ tools/$(HTML_COMPRESSOR):
|
||||
cd tools; wget --no-check-certificate https://htmlcompressor.googlecode.com/files/$(HTML_COMPRESSOR) -O $(HTML_COMPRESSOR)
|
||||
else
|
||||
tools/$(HTML_COMPRESSOR):
|
||||
$(Q) mkdir -p tools
|
||||
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)
|
||||
# $(Q) mkdir -p tools
|
||||
# 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_HTMLCOMPRESSOR)","yes")
|
||||
|
||||
12
cmd/cmd.h
12
cmd/cmd.h
@@ -45,9 +45,15 @@ typedef enum {
|
||||
CMD_MQTT_SUBSCRIBE, // subscribe to a topic
|
||||
CMD_MQTT_LWT, // set the last-will-topic and messge
|
||||
|
||||
CMD_REST_SETUP = 20,
|
||||
CMD_REST_REQUEST,
|
||||
CMD_REST_SETHEADER,
|
||||
CMD_REST_SETUP = 20, // set-up callbacks
|
||||
CMD_REST_REQUEST, // do REST request
|
||||
CMD_REST_SETHEADER, // define header
|
||||
|
||||
CMD_TCP_SETUP = 30, // set-up callbacks
|
||||
CMD_TCP_SEND, // send data over TCP socket
|
||||
|
||||
CMD_UDP_SETUP = 40, // set-up callbacks
|
||||
CMD_UDP_SEND, // send data over UDP socket
|
||||
} CmdName;
|
||||
|
||||
typedef void (*cmdfunc_t)(CmdPacket *cmd);
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
#ifdef REST
|
||||
#include <rest.h>
|
||||
#endif
|
||||
#ifdef TCP
|
||||
#include <tcp.h>
|
||||
#endif
|
||||
#ifdef UDP
|
||||
#include <udp.h>
|
||||
#endif
|
||||
|
||||
#ifdef CMD_DBG
|
||||
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
|
||||
@@ -47,6 +53,14 @@ const CmdList commands[] = {
|
||||
{CMD_REST_REQUEST, "REST_REQ", REST_Request},
|
||||
{CMD_REST_SETHEADER, "REST_SETHDR", REST_SetHeader},
|
||||
#endif
|
||||
#ifdef TCP
|
||||
{CMD_TCP_SETUP, "TCP_SETUP", TCP_Setup},
|
||||
{CMD_TCP_SEND, "TCP_SEND", TCP_Send},
|
||||
#endif
|
||||
#ifdef UDP
|
||||
{CMD_UDP_SETUP, "UDP_SETUP", UDP_Setup},
|
||||
{CMD_UDP_SEND, "UDP_SEND", UDP_Send},
|
||||
#endif
|
||||
};
|
||||
|
||||
//===== List of registered callbacks (to uC)
|
||||
|
||||
382
tcp/tcp.c
Normal file
382
tcp/tcp.c
Normal file
@@ -0,0 +1,382 @@
|
||||
// Copyright 2016 by BeeGee, see LICENSE.txt
|
||||
//
|
||||
// Adapted from: github.com/tuanpmt/esp_bridge, Created on: Mar 4, 2015, Author: Minh
|
||||
// Adapted from: rest.c, Author: Thorsten von Eicken
|
||||
|
||||
#include "esp8266.h"
|
||||
#include "c_types.h"
|
||||
#include "ip_addr.h"
|
||||
#include "tcp.h"
|
||||
#include "cmd.h"
|
||||
|
||||
#define TCP_DBG
|
||||
|
||||
#ifdef TCP_DBG
|
||||
#define DBG_TCP(format, ...) os_printf(format, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DBG_TCP(format, ...) do { } while(0)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char *host;
|
||||
uint32_t port;
|
||||
ip_addr_t ip;
|
||||
struct espconn *pCon;
|
||||
char *data;
|
||||
uint16_t data_len;
|
||||
uint16_t data_sent;
|
||||
uint32_t resp_cb;
|
||||
uint8_t conn_num;
|
||||
uint8_t sock_mode;
|
||||
} TcpClient;
|
||||
|
||||
|
||||
// Connection pool for TCP socket clients. Attached MCU's just call TCP_setup and this allocates
|
||||
// a connection, They never call any 'free' and given that the attached MCU could restart at
|
||||
// any time, we cannot really rely on the attached MCU to call 'free' ever, so better do without.
|
||||
// Instead, we allocate a fixed pool of connections an round-robin. What this means is that the
|
||||
// attached MCU should really use at most as many TCP connections as there are slots in the pool.
|
||||
#define MAX_TCP 4
|
||||
static TcpClient tcpClient[MAX_TCP];
|
||||
static uint8_t tcpNum = 0xff; // index into tcpClient for next slot to allocate
|
||||
|
||||
// Any incoming data?
|
||||
static void ICACHE_FLASH_ATTR
|
||||
tcpclient_recv_cb(void *arg, char *pusrdata, unsigned short length) {
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
TcpClient* client = (TcpClient *)pCon->reverse;
|
||||
|
||||
uint8_t clientNum = client->conn_num;
|
||||
uint8_t cb_type = 1;
|
||||
DBG_TCP("TCP #%d: Received %d bytes: %s\n", client-tcpClient, length, pusrdata);
|
||||
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 4);
|
||||
cmdResponseBody(&cb_type, 1);
|
||||
cmdResponseBody(&clientNum, 1);
|
||||
cmdResponseBody(&length, 2);
|
||||
cmdResponseBody(pusrdata, length);
|
||||
cmdResponseEnd();
|
||||
|
||||
if (client->sock_mode != SOCKET_SERVER) { // We don't wait for a response
|
||||
DBG_TCP("TCP #%d: disconnect after receiving\n", client-tcpClient);
|
||||
espconn_disconnect(client->pCon); // disconnect from the server
|
||||
}
|
||||
}
|
||||
|
||||
// Data is sent
|
||||
static void ICACHE_FLASH_ATTR
|
||||
tcpclient_sent_cb(void *arg) {
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
TcpClient* client = (TcpClient *)pCon->reverse;
|
||||
|
||||
uint8_t clientNum = client->conn_num;
|
||||
uint8_t cb_type = 0;
|
||||
DBG_TCP("TCP #%d: Sent\n", client-tcpClient);
|
||||
sint16 sentDataLen = client->data_sent;
|
||||
if (client->data_sent != client->data_len) {
|
||||
// we only sent part of the buffer, send the rest
|
||||
espconn_send(client->pCon, (uint8_t*)(client->data+client->data_sent),
|
||||
client->data_len-client->data_sent);
|
||||
client->data_sent = client->data_len;
|
||||
} else {
|
||||
// we're done sending, free the memory
|
||||
if (client->data) os_free(client->data);
|
||||
client->data = 0;
|
||||
|
||||
if (client->sock_mode == SOCKET_CLIENT) { // We don't wait for a response
|
||||
DBG_TCP("TCP #%d: disconnect after sending\n", client-tcpClient);
|
||||
espconn_disconnect(client->pCon);
|
||||
}
|
||||
|
||||
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
|
||||
cmdResponseBody(&cb_type, 1);
|
||||
cmdResponseBody(&clientNum, 1);
|
||||
cmdResponseBody(&sentDataLen, 2);
|
||||
cmdResponseEnd();
|
||||
}
|
||||
}
|
||||
|
||||
// Connection is disconnected
|
||||
static void ICACHE_FLASH_ATTR
|
||||
tcpclient_discon_cb(void *arg) {
|
||||
struct espconn *pespconn = (struct espconn *)arg;
|
||||
TcpClient* client = (TcpClient *)pespconn->reverse;
|
||||
|
||||
uint8_t clientNum = client->conn_num;
|
||||
uint8_t cb_type = 3;
|
||||
sint16 _status = 0;
|
||||
DBG_TCP("TCP #%d: Disconnect\n", client-tcpClient);
|
||||
// free the data buffer, if we have one
|
||||
if (client->data) os_free(client->data);
|
||||
client->data = 0;
|
||||
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
|
||||
cmdResponseBody(&cb_type, 1);
|
||||
cmdResponseBody(&clientNum, 1);
|
||||
cmdResponseBody(&_status, 2);
|
||||
cmdResponseEnd();
|
||||
}
|
||||
|
||||
// Connection was reset
|
||||
static void ICACHE_FLASH_ATTR
|
||||
tcpclient_recon_cb(void *arg, sint8 errType) {
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
TcpClient* client = (TcpClient *)pCon->reverse;
|
||||
|
||||
uint8_t clientNum = client->conn_num;
|
||||
uint8_t cb_type = 2;
|
||||
sint16 _errType = errType;
|
||||
os_printf("TCP #%d: conn reset, err=%d\n", client-tcpClient, _errType);
|
||||
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
|
||||
cmdResponseBody(&cb_type, 1);
|
||||
cmdResponseBody(&clientNum, 1);
|
||||
cmdResponseBody(&_errType, 2);
|
||||
cmdResponseEnd();
|
||||
// free the data buffer, if we have one
|
||||
if (client->data) os_free(client->data);
|
||||
client->data = 0;
|
||||
}
|
||||
|
||||
// Connection is done
|
||||
static void ICACHE_FLASH_ATTR
|
||||
tcpclient_connect_cb(void *arg) {
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
TcpClient* client = (TcpClient *)pCon->reverse;
|
||||
|
||||
uint8_t clientNum = client->conn_num;
|
||||
uint8_t cb_type = 3;
|
||||
sint16 _status = 1;
|
||||
DBG_TCP("TCP #%d: connected socket mode = %d\n", client-tcpClient, client->sock_mode);
|
||||
espconn_regist_disconcb(client->pCon, tcpclient_discon_cb);
|
||||
espconn_regist_recvcb(client->pCon, tcpclient_recv_cb);
|
||||
espconn_regist_sentcb(client->pCon, tcpclient_sent_cb);
|
||||
|
||||
DBG_TCP("TCP #%d: sending %d\n", client-tcpClient, client->data_sent);
|
||||
if (client->sock_mode != SOCKET_SERVER) { // Send data after established connection only in client mode
|
||||
client->data_sent = client->data_len <= 1400 ? client->data_len : 1400;
|
||||
DBG_TCP("TCP #%d: sending %d\n", client-tcpClient, client->data_sent);
|
||||
espconn_send(client->pCon, (uint8_t*)client->data, client->data_sent);
|
||||
}
|
||||
|
||||
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
|
||||
cmdResponseBody(&cb_type, 1);
|
||||
cmdResponseBody(&clientNum, 1);
|
||||
cmdResponseBody(&_status, 2);
|
||||
cmdResponseEnd();
|
||||
}
|
||||
|
||||
static void ICACHE_FLASH_ATTR
|
||||
tcp_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) {
|
||||
struct espconn *pConn = (struct espconn *)arg;
|
||||
TcpClient* client = (TcpClient *)pConn->reverse;
|
||||
|
||||
if(ipaddr == NULL) {
|
||||
os_printf("TCP #%d DNS: Got no ip, try to reconnect\n", client-tcpClient);
|
||||
return;
|
||||
}
|
||||
DBG_TCP("TCP 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);
|
||||
espconn_connect(client->pCon);
|
||||
DBG_TCP("TCP #%d: connecting...\n", client-tcpClient);
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
TCP_Setup(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
uint16_t port;
|
||||
uint8_t sock_mode;
|
||||
int32_t err = -1; // error code in case of failure
|
||||
|
||||
// start parsing the command
|
||||
cmdRequest(&req, cmd);
|
||||
if(cmdGetArgc(&req) != 3) {
|
||||
DBG_TCP("TCP Setup parse command failure: (cmdGetArgc(&req) != 3)\n");
|
||||
goto fail;
|
||||
}
|
||||
err--;
|
||||
|
||||
// get the hostname (IP address)
|
||||
uint16_t len = cmdArgLen(&req);
|
||||
if (len > 128) {
|
||||
DBG_TCP("TCP Setup parse command failure: hostname longer than 128 characters\n");
|
||||
goto fail; // safety check
|
||||
}
|
||||
err--;
|
||||
uint8_t *tcp_host = (uint8_t*)os_zalloc(len + 1);
|
||||
if (tcp_host == NULL) {
|
||||
DBG_TCP("TCP Setup failed to alloc memory for tcp_host\n");
|
||||
goto fail;
|
||||
}
|
||||
if (cmdPopArg(&req, tcp_host, len)) {
|
||||
DBG_TCP("TCP Setup parse command failure: (cmdPopArg(&req, tcp_host, len))\n");
|
||||
goto fail;
|
||||
}
|
||||
err--;
|
||||
tcp_host[len] = 0;
|
||||
|
||||
// get the port
|
||||
if (cmdPopArg(&req, (uint8_t*)&port, 2)) {
|
||||
DBG_TCP("TCP Setup parse command failure: cannot get port\n");
|
||||
os_free(tcp_host);
|
||||
goto fail;
|
||||
}
|
||||
err--;
|
||||
|
||||
// get the socket mode
|
||||
if (cmdPopArg(&req, (uint8_t*)&sock_mode, 1)) {
|
||||
DBG_TCP("TCP Setup parse command failure: cannot get mode\n");
|
||||
os_free(tcp_host);
|
||||
goto fail;
|
||||
}
|
||||
err--;
|
||||
DBG_TCP("TCP Setup listener flag\n");
|
||||
|
||||
// clear connection structures the first time
|
||||
if (tcpNum == 0xff) {
|
||||
os_memset(tcpClient, 0, MAX_TCP * sizeof(TcpClient));
|
||||
tcpNum = 0;
|
||||
}
|
||||
|
||||
// allocate a connection structure
|
||||
TcpClient *client = tcpClient + tcpNum;
|
||||
uint8_t clientNum = tcpNum;
|
||||
tcpNum = (tcpNum+1)%MAX_TCP;
|
||||
|
||||
// free any data structure that may be left from a previous connection
|
||||
if (client->data) os_free(client->data);
|
||||
if (client->pCon) {
|
||||
if (client->pCon->proto.tcp) os_free(client->pCon->proto.tcp);
|
||||
os_free(client->pCon);
|
||||
}
|
||||
os_memset(client, 0, sizeof(TcpClient));
|
||||
DBG_TCP("TCP #%d: Setup host=%s port=%d \n", clientNum, tcp_host, port);
|
||||
|
||||
client->sock_mode = sock_mode;
|
||||
client->resp_cb = cmd->value;
|
||||
client->conn_num = clientNum;
|
||||
|
||||
client->host = (char *)tcp_host;
|
||||
client->port = port;
|
||||
|
||||
client->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
|
||||
if (client->pCon == NULL) {
|
||||
DBG_TCP("TCP #%d: Setup failed to alloc memory for client_pCon\n", clientNum);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
client->pCon->type = ESPCONN_TCP;
|
||||
client->pCon->state = ESPCONN_NONE;
|
||||
client->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
|
||||
if (client->pCon->proto.tcp == NULL) {
|
||||
DBG_TCP("TCP #%d: Setup failed to alloc memory for client->pCon->proto.tcp\n", clientNum);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_memcpy(client->host, tcp_host, 4);
|
||||
client->pCon->proto.tcp->remote_port = client->port;
|
||||
client->pCon->proto.tcp->local_port = client->port; // espconn_port();
|
||||
|
||||
client->pCon->reverse = client;
|
||||
|
||||
espconn_regist_sentcb(client->pCon, tcpclient_sent_cb);
|
||||
espconn_regist_recvcb(client->pCon, tcpclient_recv_cb);
|
||||
espconn_regist_reconcb(client->pCon, tcpclient_recon_cb);
|
||||
if (client->sock_mode == SOCKET_SERVER) { // Server mode?
|
||||
DBG_TCP("TCP #%d: Enable server mode on port%d\n", clientNum, client->port);
|
||||
espconn_accept(client->pCon);
|
||||
espconn_regist_connectcb(client->pCon, tcpclient_connect_cb);
|
||||
}
|
||||
|
||||
cmdResponseStart(CMD_RESP_V, clientNum, 0);
|
||||
cmdResponseEnd();
|
||||
DBG_TCP("TCP #%d: setup finished\n", clientNum);
|
||||
return;
|
||||
|
||||
fail:
|
||||
cmdResponseStart(CMD_RESP_V, err, 0);
|
||||
cmdResponseEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
TCP_Send(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
cmdRequest(&req, cmd);
|
||||
|
||||
// Get client
|
||||
uint32_t clientNum = cmd->value;
|
||||
TcpClient *client = tcpClient + (clientNum % MAX_TCP);
|
||||
DBG_TCP("TCP #%d: send", clientNum);
|
||||
|
||||
if (cmd->argc != 1 && cmd->argc != 2) {
|
||||
DBG_TCP("\nTCP #%d: send - wrong number of arguments\n", clientNum);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get data to sent
|
||||
uint16_t dataLen = cmdArgLen(&req);
|
||||
DBG_TCP(" dataLen=%d", dataLen);
|
||||
char tcpData[1024];
|
||||
cmdPopArg(&req, tcpData, dataLen);
|
||||
tcpData[dataLen] = 0;
|
||||
DBG_TCP(" tcpData=%s", tcpData);
|
||||
|
||||
// we need to allocate memory for the data. We copy the message into it
|
||||
char *tcpDataSet = "%s";
|
||||
|
||||
if (client->data) os_free(client->data);
|
||||
client->data = (char*)os_zalloc(dataLen);
|
||||
if (client->data == NULL) {
|
||||
DBG_TCP("\nTCP #%d failed to alloc memory for client->data\n", clientNum);
|
||||
goto fail;
|
||||
}
|
||||
client->data_len = os_sprintf((char*)client->data, tcpDataSet, tcpData);
|
||||
|
||||
DBG_TCP("\n");
|
||||
|
||||
DBG_TCP("TCP #%d: Create connection to ip %s:%d\n", clientNum, client->host, client->port);
|
||||
|
||||
if (client->sock_mode == SOCKET_SERVER) { // In server mode we should be connected already and send the data immediately
|
||||
remot_info *premot = NULL;
|
||||
if (espconn_get_connection_info(client->pCon,&premot,0) == ESPCONN_OK){
|
||||
for (uint8 count = 0; count < client->pCon->link_cnt; count ++){
|
||||
client->pCon->proto.tcp->remote_port = premot[count].remote_port;
|
||||
|
||||
client->pCon->proto.tcp->remote_ip[0] = premot[count].remote_ip[0];
|
||||
client->pCon->proto.tcp->remote_ip[1] = premot[count].remote_ip[1];
|
||||
client->pCon->proto.tcp->remote_ip[2] = premot[count].remote_ip[2];
|
||||
client->pCon->proto.tcp->remote_ip[3] = premot[count].remote_ip[3];
|
||||
DBG_TCP("TCP #%d: connected to %d.%d.%d.%d:%d\n",
|
||||
client-tcpClient,
|
||||
client->pCon->proto.tcp->remote_ip[0],
|
||||
client->pCon->proto.tcp->remote_ip[1],
|
||||
client->pCon->proto.tcp->remote_ip[2],
|
||||
client->pCon->proto.tcp->remote_ip[3],
|
||||
client->pCon->proto.tcp->remote_port
|
||||
);
|
||||
}
|
||||
client->data_sent = client->data_len <= 1400 ? client->data_len : 1400;
|
||||
DBG_TCP("TCP #%d: Server sending %d\n", client-tcpClient, client->data_sent);
|
||||
espconn_send(client->pCon, (uint8_t*)client->data, client->data_sent);
|
||||
}
|
||||
} else {
|
||||
espconn_regist_connectcb(client->pCon, tcpclient_connect_cb);
|
||||
|
||||
if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.tcp->remote_ip)) {
|
||||
DBG_TCP("TCP #%d: Connect to ip %s:%d\n", clientNum, client->host, client->port);
|
||||
espconn_connect(client->pCon);
|
||||
} else {
|
||||
DBG_TCP("TCP #%d: Connect to host %s:%d\n", clientNum, client->host, client->port);
|
||||
espconn_gethostbyname(client->pCon, (char *)client->host, &client->ip, tcp_dns_found);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
DBG_TCP("\n");
|
||||
}
|
||||
20
tcp/tcp.h
Normal file
20
tcp/tcp.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* tcp.h
|
||||
*
|
||||
* Created on: Sep 2nd 2016
|
||||
* Author: BeeGee
|
||||
*/
|
||||
|
||||
#ifndef MODULES_TCP_H_
|
||||
#define MODULES_TCP_H_
|
||||
|
||||
#include "cmd.h"
|
||||
|
||||
void TCP_Setup(CmdPacket *cmd);
|
||||
void TCP_Send(CmdPacket *cmd);
|
||||
|
||||
#define SOCKET_CLIENT 0 // TCP socket client for sending only, doesn't wait for response from server
|
||||
#define SOCKET_CLIENT_LISTEN 1 // TCP socket client, waits for response from server after sending
|
||||
#define SOCKET_SERVER 2 // TCP socket server
|
||||
|
||||
#endif /* MODULES_TCP_H_ */
|
||||
BIN
tools/htmlcompressor-1.5.3.jar
Normal file
BIN
tools/htmlcompressor-1.5.3.jar
Normal file
Binary file not shown.
BIN
tools/yuicompressor-2.4.8.jar
Normal file
BIN
tools/yuicompressor-2.4.8.jar
Normal file
Binary file not shown.
243
udp/udp.c
Normal file
243
udp/udp.c
Normal file
@@ -0,0 +1,243 @@
|
||||
// Copyright 2016 by BeeGee, see LICENSE.txt
|
||||
//
|
||||
// Adapted from: github.com/tuanpmt/esp_bridge, Created on: Mar 4, 2015, Author: Minh
|
||||
// Adapted from: rest.c, Author: Thorsten von Eicken
|
||||
|
||||
#include "esp8266.h"
|
||||
#include "c_types.h"
|
||||
#include "ip_addr.h"
|
||||
#include "udp.h"
|
||||
#include "cmd.h"
|
||||
|
||||
#define UDP_DBG
|
||||
|
||||
#ifdef UDP_DBG
|
||||
#define DBG_UDP(format, ...) os_printf(format, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DBG_UDP(format, ...) do { } while(0)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char *host;
|
||||
uint32_t port;
|
||||
ip_addr_t ip;
|
||||
struct espconn *pCon;
|
||||
char *data;
|
||||
uint16_t data_len;
|
||||
uint16_t data_sent;
|
||||
uint32_t resp_cb;
|
||||
uint8_t conn_num;
|
||||
} UdpClient;
|
||||
|
||||
|
||||
// Connection pool for UDP socket clients. Attached MCU's just call UDP_setup and this allocates
|
||||
// a connection, They never call any 'free' and given that the attached MCU could restart at
|
||||
// any time, we cannot really rely on the attached MCU to call 'free' ever, so better do without.
|
||||
// Instead, we allocate a fixed pool of connections an round-robin. What this means is that the
|
||||
// attached MCU should really use at most as many UDP connections as there are slots in the pool.
|
||||
#define MAX_UDP 4
|
||||
static UdpClient udpClient[MAX_UDP];
|
||||
static uint8_t udpNum = 0xff; // index into udpClient for next slot to allocate
|
||||
|
||||
// Any incoming data?
|
||||
static void ICACHE_FLASH_ATTR
|
||||
udpclient_recv_cb(void *arg, char *pusrdata, unsigned short length) {
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
UdpClient* client = (UdpClient *)pCon->reverse;
|
||||
|
||||
uint8_t clientNum = client->conn_num;
|
||||
uint8_t cb_type = 1;
|
||||
DBG_UDP("UDP #%d: Received %d bytes: %s\n",clientNum, length, pusrdata);
|
||||
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 4);
|
||||
cmdResponseBody(&cb_type, 1);
|
||||
cmdResponseBody(&clientNum, 1);
|
||||
cmdResponseBody(&length, 2);
|
||||
cmdResponseBody(pusrdata, length);
|
||||
cmdResponseEnd();
|
||||
}
|
||||
|
||||
// Data is sent
|
||||
static void ICACHE_FLASH_ATTR
|
||||
udpclient_sent_cb(void *arg) {
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
UdpClient* client = (UdpClient *)pCon->reverse;
|
||||
|
||||
uint8_t clientNum = client->conn_num;
|
||||
uint8_t cb_type = 0;
|
||||
DBG_UDP("UDP #%d: Sent\n",clientNum);
|
||||
sint16 sentDataLen = client->data_sent;
|
||||
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),
|
||||
client->data_len-client->data_sent);
|
||||
client->data_sent = client->data_len;
|
||||
} else {
|
||||
// we're done sending, free the memory
|
||||
if (client->data) os_free(client->data);
|
||||
client->data = 0;
|
||||
|
||||
cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
|
||||
cmdResponseBody(&cb_type, 1);
|
||||
cmdResponseBody(&clientNum, 1);
|
||||
cmdResponseBody(&sentDataLen, 2);
|
||||
cmdResponseEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
UDP_Setup(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
uint16_t port;
|
||||
int32_t err = -1; // error code in case of failure
|
||||
|
||||
// start parsing the command
|
||||
cmdRequest(&req, cmd);
|
||||
if(cmdGetArgc(&req) != 3) {
|
||||
DBG_UDP("UDP Setup parse command failure: (cmdGetArgc(&req) != 3)\n");
|
||||
goto fail;
|
||||
}
|
||||
err--;
|
||||
|
||||
// get the hostname (IP address)
|
||||
uint16_t len = cmdArgLen(&req);
|
||||
if (len > 128) {
|
||||
DBG_UDP("UDP Setup parse command failure: hostname longer than 128 characters\n");
|
||||
goto fail; // safety check
|
||||
}
|
||||
err--;
|
||||
uint8_t *udp_host = (uint8_t*)os_zalloc(len + 1);
|
||||
if (udp_host == NULL) {
|
||||
DBG_UDP("UDP Setup failed to alloc memory for udp_host\n");
|
||||
goto fail;
|
||||
}
|
||||
if (cmdPopArg(&req, udp_host, len)) {
|
||||
DBG_UDP("UDP Setup parse command failure: (cmdPopArg(&req, udp_host, len))\n");
|
||||
goto fail;
|
||||
}
|
||||
err--;
|
||||
udp_host[len] = 0;
|
||||
|
||||
// get the port
|
||||
if (cmdPopArg(&req, (uint8_t*)&port, 2)) {
|
||||
DBG_UDP("UDP Setup parse command failure: cannot get port\n");
|
||||
os_free(udp_host);
|
||||
goto fail;
|
||||
}
|
||||
err--;
|
||||
|
||||
// clear connection structures the first time
|
||||
if (udpNum == 0xff) {
|
||||
os_memset(udpClient, 0, MAX_UDP * sizeof(UdpClient));
|
||||
udpNum = 0;
|
||||
}
|
||||
|
||||
// allocate a connection structure
|
||||
UdpClient *client = udpClient + udpNum;
|
||||
uint8_t clientNum = udpNum;
|
||||
udpNum = (udpNum+1)%MAX_UDP;
|
||||
|
||||
// free any data structure that may be left from a previous connection
|
||||
if (client->data) os_free(client->data);
|
||||
if (client->pCon) {
|
||||
if (client->pCon->proto.udp) os_free(client->pCon->proto.udp);
|
||||
os_free(client->pCon);
|
||||
}
|
||||
os_memset(client, 0, sizeof(UdpClient));
|
||||
DBG_UDP("UDP #%d: Setup #%d udp_host=%s port=%d \n", clientNum, udp_host, port);
|
||||
|
||||
client->resp_cb = cmd->value;
|
||||
client->conn_num = clientNum;
|
||||
|
||||
client->host = (char *)udp_host;
|
||||
client->port = port;
|
||||
wifi_set_broadcast_if(STATIONAP_MODE);
|
||||
|
||||
client->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
|
||||
if (client->pCon == NULL) {
|
||||
DBG_UDP("UDP #%d: Setup failed to alloc memory for client_pCon\n", clientNum);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
client->pCon->type = ESPCONN_UDP;
|
||||
client->pCon->state = ESPCONN_NONE;
|
||||
client->pCon->proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp));
|
||||
if (client->pCon->proto.udp == NULL) {
|
||||
DBG_UDP("UDP #%d: Setup failed to alloc memory for client->pCon->proto.tcp\n", clientNum);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_memcpy(client->host, udp_host, 4);
|
||||
client->pCon->proto.udp->remote_port = client->port;
|
||||
client->pCon->proto.udp->local_port = client->port;
|
||||
|
||||
client->pCon->reverse = client;
|
||||
|
||||
espconn_regist_sentcb(client->pCon, udpclient_sent_cb);
|
||||
espconn_regist_recvcb(client->pCon, udpclient_recv_cb);
|
||||
|
||||
DBG_UDP("UDP #%d: Create connection to ip %s:%d\n", clientNum, client->host, client->port);
|
||||
|
||||
if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.tcp->remote_ip)) {
|
||||
espconn_create(client->pCon);
|
||||
} else {
|
||||
DBG_UDP("UDP #%d: failed to copy remote_ip to &client->pCon->proto.tcp->remote_ip\n", clientNum);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
cmdResponseStart(CMD_RESP_V, clientNum, 0);
|
||||
cmdResponseEnd();
|
||||
DBG_UDP("UDP #%d: setup finished\n", clientNum);
|
||||
return;
|
||||
|
||||
fail:
|
||||
cmdResponseStart(CMD_RESP_V, err, 0);
|
||||
cmdResponseEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
UDP_Send(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
cmdRequest(&req, cmd);
|
||||
|
||||
// Get client
|
||||
uint32_t clientNum = cmd->value;
|
||||
UdpClient *client = udpClient + (clientNum % MAX_UDP);
|
||||
DBG_UDP("UDP #%d: send", clientNum);
|
||||
|
||||
if (cmd->argc != 1 && cmd->argc != 2) {
|
||||
DBG_UDP("\nUDP #%d: send - wrong number of arguments\n", clientNum);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get data to sent
|
||||
uint16_t dataLen = cmdArgLen(&req);
|
||||
DBG_UDP(" dataLen=%d", dataLen);
|
||||
char udpData[1024];
|
||||
cmdPopArg(&req, udpData, dataLen);
|
||||
udpData[dataLen] = 0;
|
||||
DBG_UDP(" udpData=%s", udpData);
|
||||
|
||||
// we need to allocate memory for the data. We copy the message into it
|
||||
char *udpDataSet = "%s";
|
||||
|
||||
if (client->data) os_free(client->data);
|
||||
client->data = (char*)os_zalloc(dataLen);
|
||||
if (client->data == NULL) {
|
||||
DBG_UDP("\nUDP #%d: failed to alloc memory for client->data\n", clientNum);
|
||||
goto fail;
|
||||
}
|
||||
client->data_len = os_sprintf((char*)client->data, udpDataSet, udpData);
|
||||
|
||||
DBG_UDP("\n");
|
||||
|
||||
client->data_sent = client->data_len <= 1400 ? client->data_len : 1400;
|
||||
DBG_UDP("UDP #%d: sending %d bytes: %s\n", client-udpClient, client->data_sent, client->data);
|
||||
espconn_sent(client->pCon, (uint8_t*)client->data, client->data_sent);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
DBG_UDP("\n");
|
||||
}
|
||||
Reference in New Issue
Block a user