Files
ESP8266lib/net/TCP.h
2018-09-22 15:44:26 +02:00

350 lines
7.0 KiB
C++

#ifndef TCP_H
#define TCP_H
#include "../Platforms.h"
class TCP;
typedef void (*TCPDataCallback)(TCP* tcp, const uint8_t* data, uint16_t len);
typedef void (*TCPConnectCallback)(TCP* tcp);
typedef void (*TCPDisconnectCallback)(TCP* tcp);
#include "../Debug.h"
#include "IP.h"
#if ESP8266
extern "C" {
#include "mem.h"
#include "espconn.h"
}
class TCP {
private:
static constexpr const char* NAME = "TCP";
espconn* con;
esp_tcp tcp;
bool connected = false;
TCPDataCallback onData = nullptr;
TCPConnectCallback onConnect = nullptr;
TCPDisconnectCallback onDisconnect = nullptr;
void* userData = nullptr;
public:
TCP() {
init();
}
/** dtor */
~TCP() {
cleanup();
}
/** send data to the other side */
bool send(const uint8_t* data, const size_t dataLen) {
const int res = espconn_sent(con, (unsigned char*)data, dataLen);
return (res == 0);
}
/** connect to the given IP and port */
void connect(const IP ip, const Port port) {
disconnect();
debugMod2(NAME, "connect(%s, %d)", ip.toString(), port);
con->proto.tcp->remote_port = port;
con->proto.tcp->local_port = espconn_port();
os_memcpy(con->proto.tcp->remote_ip, ip.getPtr(), 4);
espconn_connect(con);
connected = true;
}
/** terminate connection */
void disconnect() {
if (!connected) {return;}
espconn_disconnect(con);
connected = false;
}
void hold() {
if (connected) {
espconn_recv_hold(con);
}
}
void unhold() {
if (connected) {
espconn_recv_unhold(con);
}
}
/** set the callback to call whenever data is received */
void setDataCallback(TCPDataCallback callback) {
this->onData = callback;
}
/** set the callback to call when connection is established */
void setConnectCallback(TCPConnectCallback callback) {
this->onConnect = callback;
}
/** set the callback to call when connection is lost */
void setDisconnectCallback(TCPDisconnectCallback callback) {
this->onDisconnect = callback;
}
/** attach user-data to this object. can bed used within callbacks */
void setUserData(void* ptr) {
this->userData = ptr;
}
/** get previously attached user data */
void* getUserData() const {
return this->userData;
}
private:
/** called for incoming data */
static void _onData(void* ptr, char* data, unsigned short len) {
TCP* tcp = (TCP*) ((espconn*)ptr)->reverse;
if (tcp->onData) {tcp->onData(tcp, (const uint8_t*)data, len);}
}
/** called when connection is established */
static void _onConnect(void* ptr) {
TCP* tcp = (TCP*) ((espconn*)ptr)->reverse;
if (tcp->onConnect) {tcp->onConnect(tcp);}
tcp->connected = true;
}
/** called when connection is lost */
static void _onDisconnect(void* ptr) {
TCP* tcp = (TCP*) ((espconn*)ptr)->reverse;
if (tcp->onDisconnect) {tcp->onDisconnect(tcp);}
tcp->connected = false;
}
/** initialize the UDP "connection" */
void init() {
debugMod(NAME, "init()");
// allocate connection-objects
con = (espconn*) os_zalloc(sizeof(espconn));
ets_memset( con, 0, sizeof( espconn ) );
// configure
con->type = ESPCONN_TCP;
con->state = ESPCONN_NONE;
//con->proto.tcp = (esp_tcp*) os_zalloc(sizeof(esp_tcp));
con->proto.tcp = &tcp;
// attach ourselves for the callback
con->reverse = (void*) this; // user-data to refer to this class
espconn_regist_recvcb(con, _onData);
espconn_regist_connectcb(con, _onConnect);
espconn_regist_disconcb(con, _onDisconnect);
// espconn_regist_reconcb(con, _onDisconnect);
}
/** cleanup everything */
void cleanup() {
debugMod(NAME, "cleanup()");
espconn_delete(con);
//os_free(con->proto.tcp);
os_free(con);
con = nullptr;
}
};
#elif ESP32
#include "lwip/err.h"
#include "lwip/tcp.h"
#include "lwip/ip_addr.h"
class TCP {
private:
static constexpr const char* NAME = "TCP";
struct tcp_pcb* pcb;
bool connected = false;
TCPDataCallback onData = nullptr;
TCPConnectCallback onConnect = nullptr;
TCPDisconnectCallback onDisconnect = nullptr;
void* userData = nullptr;
public:
TCP() {
init();
}
/** dtor */
~TCP() {
cleanup();
}
/** send data to the other side */
bool send(const uint8_t* data, const size_t dataLen) {
err_t res = tcp_write(pcb, data, dataLen, TCP_WRITE_FLAG_COPY);
return (res == ERR_OK);
}
/** connect to the given IP and port */
void connect(const IP4 ip, const Port port) {
debugMod2(NAME, "connect(%s, %d)", ip.toString(), port);
disconnect();
tcp_connect(pcb, ip.getPtr(), port, _onConnectCallback);
}
/** terminate connection */
void disconnect() {
if (!connected) {return;}
tcp_close(pcb);
connected = false;
}
void hold() {
// if (connected) {
// espconn_recv_hold(con);
// }
}
void unhold() {
// if (connected) {
// espconn_recv_unhold(con);
// }
}
/** set the callback to call whenever data is received */
void setDataCallback(TCPDataCallback callback) {
this->onData = callback;
}
/** set the callback to call when connection is established */
void setConnectCallback(TCPConnectCallback callback) {
this->onConnect = callback;
}
/** set the callback to call when connection is lost */
void setDisconnectCallback(TCPDisconnectCallback callback) {
this->onDisconnect = callback;
}
/** attach user-data to this object. can bed used within callbacks */
void setUserData(void* ptr) {
this->userData = ptr;
}
/** get previously attached user data */
void* getUserData() const {
return this->userData;
}
/** inform backend we consumed some data */
void consumed(uint16_t len) {
if (len) {
tcp_recved(pcb, len);
}
}
private:
/** called for incoming data */
static err_t _onData(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err) {
TCP* tcp = (TCP*) arg;
// if p == nullptr -> disconnect -> inform listener
if (!p) {
if (tcp->onDisconnect) {tcp->onDisconnect(tcp);}
return ERR_OK;
}
// process pBuf (might be a chain of buffers)
do {
// pass data to listener
if (tcp->onData) {tcp->onData(tcp, (const uint8_t*)p->payload, p->len);}
// next pBuf in chain (if any)
pbuf* next = p->next;
// free current buffer (we consumed it completely)
pbuf_free(p);
// proceed?
p = next;
} while (p);
// everything fine
return ERR_OK;
}
/** called when connection failed */
static err_t _onConnectCallback(void* arg, struct tcp_pcb* tpcb, err_t err) {
TCP* tcp = (TCP*) arg;
if (err == ERR_OK) {
if (tcp->onConnect) {tcp->onConnect(tcp);}
tcp->connected = true;
} else {
if (tcp->onDisconnect) {tcp->onDisconnect(tcp);}
tcp->connected = false;
}
return ERR_OK;
}
/** initialize the UDP "connection" */
void init() {
debugMod(NAME, "init()");
pcb = tcp_new();
if (!pcb) {debugMod(NAME, "error creating TCP socket");}
// user-pointer
pcb->callback_arg = (void*) this;
tcp_recv(pcb, _onData);
}
/** cleanup everything */
void cleanup() {
debugMod(NAME, "cleanup()");
// TODO
}
};
#endif
#endif // TCP_H