diff --git a/builder/utils/cores.py b/builder/utils/cores.py index 8848e08fd..266605460 100644 --- a/builder/utils/cores.py +++ b/builder/utils/cores.py @@ -91,7 +91,7 @@ def env_add_arduino_libraries(env: Environment, queue, name: str, path: str) -> ], includes=[ "!<*/.>", - "!<*/*>", + "!<**/*>", ] if name.startswith("common") else [ diff --git a/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPClient/AsyncUDPClient.ino b/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPClient/AsyncUDPClient.ino new file mode 100644 index 000000000..3348f8a76 --- /dev/null +++ b/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPClient/AsyncUDPClient.ino @@ -0,0 +1,51 @@ +#include "WiFi.h" +#include "AsyncUDP.h" + +const char * ssid = "***********"; +const char * password = "***********"; + +AsyncUDP udp; + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + if (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("WiFi Failed"); + while(1) { + delay(1000); + } + } + if(udp.connect(IPAddress(192,168,1,100), 1234)) { + Serial.println("UDP connected"); + udp.onPacket([](AsyncUDPPacket packet) { + Serial.print("UDP Packet Type: "); + Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); + Serial.print(", From: "); + Serial.print(packet.remoteIP()); + Serial.print(":"); + Serial.print(packet.remotePort()); + Serial.print(", To: "); + Serial.print(packet.localIP()); + Serial.print(":"); + Serial.print(packet.localPort()); + Serial.print(", Length: "); + Serial.print(packet.length()); + Serial.print(", Data: "); + Serial.write(packet.data(), packet.length()); + Serial.println(); + //reply to the client + packet.printf("Got %u bytes of data", packet.length()); + }); + //Send unicast + udp.print("Hello Server!"); + } +} + +void loop() +{ + delay(1000); + //Send broadcast on port 1234 + udp.broadcastTo("Anyone here?", 1234); +} diff --git a/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPMulticastServer/AsyncUDPMulticastServer.ino b/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPMulticastServer/AsyncUDPMulticastServer.ino new file mode 100644 index 000000000..2bbbac51c --- /dev/null +++ b/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPMulticastServer/AsyncUDPMulticastServer.ino @@ -0,0 +1,52 @@ +#include "WiFi.h" +#include "AsyncUDP.h" + +const char * ssid = "***********"; +const char * password = "***********"; + +AsyncUDP udp; + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + if (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("WiFi Failed"); + while(1) { + delay(1000); + } + } + if(udp.listenMulticast(IPAddress(239,1,2,3), 1234)) { + Serial.print("UDP Listening on IP: "); + Serial.println(WiFi.localIP()); + udp.onPacket([](AsyncUDPPacket packet) { + Serial.print("UDP Packet Type: "); + Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); + Serial.print(", From: "); + Serial.print(packet.remoteIP()); + Serial.print(":"); + Serial.print(packet.remotePort()); + Serial.print(", To: "); + Serial.print(packet.localIP()); + Serial.print(":"); + Serial.print(packet.localPort()); + Serial.print(", Length: "); + Serial.print(packet.length()); + Serial.print(", Data: "); + Serial.write(packet.data(), packet.length()); + Serial.println(); + //reply to the client + packet.printf("Got %u bytes of data", packet.length()); + }); + //Send multicast + udp.print("Hello!"); + } +} + +void loop() +{ + delay(1000); + //Send multicast + udp.print("Anyone here?"); +} diff --git a/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPServer/AsyncUDPServer.ino b/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPServer/AsyncUDPServer.ino new file mode 100644 index 000000000..1f8529bd5 --- /dev/null +++ b/cores/common/arduino/libraries/common/AsyncUDP/examples/AsyncUDPServer/AsyncUDPServer.ino @@ -0,0 +1,50 @@ +#include "WiFi.h" +#include "AsyncUDP.h" + +const char * ssid = "***********"; +const char * password = "***********"; + +AsyncUDP udp; + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + if (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("WiFi Failed"); + while(1) { + delay(1000); + } + } + if(udp.listen(1234)) { + Serial.print("UDP Listening on IP: "); + Serial.println(WiFi.localIP()); + udp.onPacket([](AsyncUDPPacket packet) { + Serial.print("UDP Packet Type: "); + Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); + Serial.print(", From: "); + Serial.print(packet.remoteIP()); + Serial.print(":"); + Serial.print(packet.remotePort()); + Serial.print(", To: "); + Serial.print(packet.localIP()); + Serial.print(":"); + Serial.print(packet.localPort()); + Serial.print(", Length: "); + Serial.print(packet.length()); + Serial.print(", Data: "); + Serial.write(packet.data(), packet.length()); + Serial.println(); + //reply to the client + packet.printf("Got %u bytes of data", packet.length()); + }); + } +} + +void loop() +{ + delay(1000); + //Send broadcast + udp.broadcast("Anyone here?"); +} diff --git a/cores/common/arduino/libraries/common/AsyncUDP/keywords.txt b/cores/common/arduino/libraries/common/AsyncUDP/keywords.txt new file mode 100644 index 000000000..67c0b97a7 --- /dev/null +++ b/cores/common/arduino/libraries/common/AsyncUDP/keywords.txt @@ -0,0 +1,33 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +AsyncUDP KEYWORD1 +AsyncUDPPacket KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +connect KEYWORD2 +connected KEYWORD2 +listen KEYWORD2 +listenMulticast KEYWORD2 +close KEYWORD2 +write KEYWORD2 +broadcast KEYWORD2 +onPacket KEYWORD2 +data KEYWORD2 +length KEYWORD2 +localIP KEYWORD2 +localPort KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/cores/common/arduino/libraries/common/AsyncUDP/library.properties b/cores/common/arduino/libraries/common/AsyncUDP/library.properties new file mode 100644 index 000000000..f606bb8c3 --- /dev/null +++ b/cores/common/arduino/libraries/common/AsyncUDP/library.properties @@ -0,0 +1,9 @@ +name=ESP32 Async UDP +version=2.0.0 +author=Me-No-Dev +maintainer=Me-No-Dev +sentence=Async UDP Library for ESP32 +paragraph=Async UDP Library for ESP32 +category=Other +url=https://github.com/me-no-dev/ESPAsyncUDP +architectures=* diff --git a/cores/common/arduino/libraries/common/AsyncUDP/src/AsyncUDP.cpp b/cores/common/arduino/libraries/common/AsyncUDP/src/AsyncUDP.cpp new file mode 100644 index 000000000..e892cf1ee --- /dev/null +++ b/cores/common/arduino/libraries/common/AsyncUDP/src/AsyncUDP.cpp @@ -0,0 +1,716 @@ +#include "Arduino.h" +#include "AsyncUDP.h" + +extern "C" { +#include "lwip/opt.h" +#include "lwip/inet.h" +#include "lwip/udp.h" +#include "lwip/igmp.h" +#include "lwip/ip_addr.h" +#include "lwip/mld6.h" +#include "lwip/prot/ethernet.h" +} + +#include "lwip/priv/tcpip_priv.h" + +typedef struct { + struct tcpip_api_call_data call; + udp_pcb * pcb; + const ip_addr_t *addr; + uint16_t port; + struct pbuf *pb; + err_t err; +} udp_api_call_t; + +static err_t _udp_connect_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_connect(msg->pcb, msg->addr, msg->port); + return msg->err; +} + +static err_t _udp_connect(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){ + udp_api_call_t msg; + msg.pcb = pcb; + msg.addr = addr; + msg.port = port; + tcpip_api_call(_udp_connect_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _udp_disconnect_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = 0; + udp_disconnect(msg->pcb); + return msg->err; +} + +static void _udp_disconnect(struct udp_pcb *pcb){ + udp_api_call_t msg; + msg.pcb = pcb; + tcpip_api_call(_udp_disconnect_api, (struct tcpip_api_call_data*)&msg); +} + +static err_t _udp_remove_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = 0; + udp_remove(msg->pcb); + return msg->err; +} + +static void _udp_remove(struct udp_pcb *pcb){ + udp_api_call_t msg; + msg.pcb = pcb; + tcpip_api_call(_udp_remove_api, (struct tcpip_api_call_data*)&msg); +} + +static err_t _udp_bind_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_bind(msg->pcb, msg->addr, msg->port); + return msg->err; +} + +static err_t _udp_bind(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){ + udp_api_call_t msg; + msg.pcb = pcb; + msg.addr = addr; + msg.port = port; + tcpip_api_call(_udp_bind_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _udp_sendto_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_sendto(msg->pcb, msg->pb, msg->addr, msg->port); + return msg->err; +} + +static err_t _udp_sendto(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *addr, u16_t port){ + udp_api_call_t msg; + msg.pcb = pcb; + msg.addr = addr; + msg.port = port; + msg.pb = pb; + tcpip_api_call(_udp_sendto_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +typedef struct { + void *arg; + udp_pcb *pcb; + pbuf *pb; + const ip_addr_t *addr; + uint16_t port; +} lwip_event_packet_t; + +static QueueHandle_t _udp_queue; +static volatile TaskHandle_t _udp_task_handle = NULL; + +static void _udp_task(void *pvParameters){ + lwip_event_packet_t * e = NULL; + for (;;) { + if(xQueueReceive(_udp_queue, &e, portMAX_DELAY) == pdTRUE){ + if(!e->pb){ + free((void*)(e)); + continue; + } + AsyncUDP::_s_recv(e->arg, e->pcb, e->pb, e->addr, e->port); + free((void*)(e)); + } + } + _udp_task_handle = NULL; + vTaskDelete(NULL); +} + +static bool _udp_task_start(){ + if(!_udp_queue){ + _udp_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *)); + if(!_udp_queue){ + return false; + } + } + if(!_udp_task_handle){ + xTaskCreateUniversal(_udp_task, "async_udp", 4096, NULL, /* CONFIG_ARDUINO_UDP_TASK_PRIORITY */ 3, (TaskHandle_t*)&_udp_task_handle, /* CONFIG_ARDUINO_UDP_RUNNING_CORE*/ 0); + if(!_udp_task_handle){ + return false; + } + } + return true; +} + +static bool _udp_task_post(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port) +{ + if(!_udp_task_handle || !_udp_queue){ + return false; + } + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + if(!e){ + return false; + } + e->arg = arg; + e->pcb = pcb; + e->pb = pb; + e->addr = addr; + e->port = port; + if (xQueueSend(_udp_queue, &e, portMAX_DELAY) != pdPASS) { + free((void*)(e)); + return false; + } + return true; +} + +static void _udp_recv(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port) +{ + while(pb != NULL) { + pbuf * this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + if(!_udp_task_post(arg, pcb, this_pb, addr, port)){ + pbuf_free(this_pb); + } + } +} +/* +static bool _udp_task_stop(){ + if(!_udp_task_post(NULL, NULL, NULL, NULL, 0, NULL)){ + return false; + } + while(_udp_task_handle){ + vTaskDelay(10); + } + + lwip_event_packet_t * e; + while (xQueueReceive(_udp_queue, &e, 0) == pdTRUE) { + if(e->pb){ + pbuf_free(e->pb); + } + free((void*)(e)); + } + vQueueDelete(_udp_queue); + _udp_queue = NULL; +} +*/ + + + +#define UDP_MUTEX_LOCK() //xSemaphoreTake(_lock, portMAX_DELAY) +#define UDP_MUTEX_UNLOCK() //xSemaphoreGive(_lock) + + +AsyncUDPMessage::AsyncUDPMessage(size_t size) +{ + _index = 0; + if(size > CONFIG_TCP_MSS) { + size = CONFIG_TCP_MSS; + } + _size = size; + _buffer = (uint8_t *)malloc(size); +} + +AsyncUDPMessage::~AsyncUDPMessage() +{ + if(_buffer) { + free(_buffer); + } +} + +size_t AsyncUDPMessage::write(const uint8_t *data, size_t len) +{ + if(_buffer == NULL) { + return 0; + } + size_t s = space(); + if(len > s) { + len = s; + } + memcpy(_buffer + _index, data, len); + _index += len; + return len; +} + +size_t AsyncUDPMessage::write(uint8_t data) +{ + return write(&data, 1); +} + +size_t AsyncUDPMessage::space() +{ + if(_buffer == NULL) { + return 0; + } + return _size - _index; +} + +uint8_t * AsyncUDPMessage::data() +{ + return _buffer; +} + +size_t AsyncUDPMessage::length() +{ + return _index; +} + +void AsyncUDPMessage::flush() +{ + _index = 0; +} + +AsyncUDPPacket::AsyncUDPPacket(AsyncUDPPacket &packet){ + _udp = packet._udp; + _pb = packet._pb; + _data = packet._data; + _len = packet._len; + _index = 0; + + memcpy(&_remoteIp, &packet._remoteIp, sizeof(ip_addr_t)); + memcpy(&_localIp, &packet._localIp, sizeof(ip_addr_t)); + _localPort = packet._localPort; + _remotePort = packet._remotePort; + memcpy(_remoteMac, packet._remoteMac, 6); + + pbuf_ref(_pb); +} + +AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr, uint16_t rport) +{ + _udp = udp; + _pb = pb; + _data = (uint8_t*)(pb->payload); + _len = pb->len; + _index = 0; + + pbuf_ref(_pb); + + //memcpy(&_remoteIp, raddr, sizeof(ip_addr_t)); + eth_hdr* eth = NULL; + udp_hdr* udphdr = (udp_hdr *)(_data - UDP_HLEN); + _localPort = ntohs(udphdr->dest); + _remotePort = ntohs(udphdr->src); + + eth = (eth_hdr *)(_data - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR); + struct ip_hdr * iphdr = (struct ip_hdr *)(_data - UDP_HLEN - IP_HLEN); + _localIp.addr = iphdr->dest.addr; + _remoteIp.addr = iphdr->src.addr; + + memcpy(_remoteMac, eth->src.addr, 6); +} + +AsyncUDPPacket::~AsyncUDPPacket() +{ + pbuf_free(_pb); +} + +uint8_t * AsyncUDPPacket::data() +{ + return _data; +} + +size_t AsyncUDPPacket::length() +{ + return _len; +} + +int AsyncUDPPacket::available(){ + return _len - _index; +} + +size_t AsyncUDPPacket::read(uint8_t *data, size_t len){ + size_t i; + size_t a = _len - _index; + if(len > a){ + len = a; + } + for(i=0;iwriteTo(data, len, &_remoteIp, _remotePort); +} + +size_t AsyncUDPPacket::write(uint8_t data) +{ + return write(&data, 1); +} + +size_t AsyncUDPPacket::send(AsyncUDPMessage &message) +{ + return write(message.data(), message.length()); +} + +bool AsyncUDP::_init(){ + if(_pcb){ + return true; + } + _pcb = udp_new(); + if(!_pcb){ + return false; + } + //_lock = xSemaphoreCreateMutex(); + udp_recv(_pcb, &_udp_recv, (void *) this); + return true; +} + +AsyncUDP::AsyncUDP() +{ + _pcb = NULL; + _connected = false; + _lastErr = ERR_OK; + _handler = NULL; +} + +AsyncUDP::~AsyncUDP() +{ + close(); + UDP_MUTEX_LOCK(); + udp_recv(_pcb, NULL, NULL); + _udp_remove(_pcb); + _pcb = NULL; + UDP_MUTEX_UNLOCK(); + //vSemaphoreDelete(_lock); +} + +void AsyncUDP::close() +{ + UDP_MUTEX_LOCK(); + if(_pcb != NULL) { + if(_connected) { + _udp_disconnect(_pcb); + } + _connected = false; + //todo: unjoin multicast group + } + UDP_MUTEX_UNLOCK(); +} + +bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port) +{ + if(!_udp_task_start()){ + log_e("failed to start task"); + return false; + } + if(!_init()) { + return false; + } + close(); + UDP_MUTEX_LOCK(); + _lastErr = _udp_connect(_pcb, addr, port); + if(_lastErr != ERR_OK) { + UDP_MUTEX_UNLOCK(); + return false; + } + _connected = true; + UDP_MUTEX_UNLOCK(); + return true; +} + +bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port) +{ + if(!_udp_task_start()){ + log_e("failed to start task"); + return false; + } + if(!_init()) { + return false; + } + close(); + if(addr){ + IP_SET_TYPE_VAL(_pcb->local_ip, addr->type); + IP_SET_TYPE_VAL(_pcb->remote_ip, addr->type); + } + UDP_MUTEX_LOCK(); + if(_udp_bind(_pcb, addr, port) != ERR_OK) { + UDP_MUTEX_UNLOCK(); + return false; + } + _connected = true; + UDP_MUTEX_UNLOCK(); + return true; +} + +static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join=true) +{ + if(join){ + if (igmp_joingroup(IP4_ADDR_ANY, addr)) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (igmp_leavegroup(IP4_ADDR_ANY, addr)) { + return ESP_ERR_INVALID_STATE; + } + } + + return ESP_OK; +} + +bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl) +{ + if(!ip_addr_ismulticast(addr)) { + return false; + } + + if (joinMulticastGroup(addr, true)!= ERR_OK) { + return false; + } + + if(!listen(NULL, port)) { + return false; + } + + UDP_MUTEX_LOCK(); + _pcb->mcast_ttl = ttl; + _pcb->remote_port = port; + ip_addr_copy(_pcb->remote_ip, *addr); + //ip_addr_copy(_pcb->remote_ip, ip_addr_any_type); + UDP_MUTEX_UNLOCK(); + + return true; +} + +size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * addr, uint16_t port) +{ + if(!_pcb) { + UDP_MUTEX_LOCK(); + _pcb = udp_new(); + UDP_MUTEX_UNLOCK(); + if(_pcb == NULL) { + return 0; + } + } + if(len > CONFIG_TCP_MSS) { + len = CONFIG_TCP_MSS; + } + _lastErr = ERR_OK; + pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if(pbt != NULL) { + uint8_t* dst = reinterpret_cast(pbt->payload); + memcpy(dst, data, len); + UDP_MUTEX_LOCK(); + _lastErr = _udp_sendto(_pcb, pbt, addr, port); + UDP_MUTEX_UNLOCK(); + pbuf_free(pbt); + if(_lastErr < ERR_OK) { + return 0; + } + return len; + } + return 0; +} + +void AsyncUDP::_recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port) +{ + while(pb != NULL) { + pbuf * this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + if(_handler) { + AsyncUDPPacket packet(this, this_pb, addr, port); + _handler(packet); + } + pbuf_free(this_pb); + } +} + +void AsyncUDP::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port) +{ + reinterpret_cast(arg)->_recv(upcb, p, addr, port); +} + +bool AsyncUDP::listen(uint16_t port) +{ + return listen(IP_ANY_TYPE, port); +} + +bool AsyncUDP::listen(const IPAddress addr, uint16_t port) +{ + ip_addr_t laddr; + laddr.addr = addr; + return listen(&laddr, port); +} + +bool AsyncUDP::listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl) +{ + ip_addr_t laddr; + laddr.addr = addr; + return listenMulticast(&laddr, port, ttl); +} + +bool AsyncUDP::connect(const IPAddress addr, uint16_t port) +{ + ip_addr_t daddr; + daddr.addr = addr; + return connect(&daddr, port); +} + +size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port) +{ + ip_addr_t daddr; + daddr.addr = addr; + return writeTo(data, len, &daddr, port); +} + +IPAddress AsyncUDP::listenIP() +{ + if(!_pcb){ + return IPAddress(); + } + return IPAddress(_pcb->remote_ip.addr); +} + +size_t AsyncUDP::write(const uint8_t *data, size_t len) +{ + return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port); +} + +size_t AsyncUDP::write(uint8_t data) +{ + return write(&data, 1); +} + +size_t AsyncUDP::broadcastTo(uint8_t *data, size_t len, uint16_t port) +{ + return writeTo(data, len, IP_ADDR_BROADCAST, port); +} + +size_t AsyncUDP::broadcastTo(const char * data, uint16_t port) +{ + return broadcastTo((uint8_t *)data, strlen(data), port); +} + +size_t AsyncUDP::broadcast(uint8_t *data, size_t len) +{ + if(_pcb->local_port != 0) { + return broadcastTo(data, len, _pcb->local_port); + } + return 0; +} + +size_t AsyncUDP::broadcast(const char * data) +{ + return broadcast((uint8_t *)data, strlen(data)); +} + + +size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port) +{ + if(!message) { + return 0; + } + return writeTo(message.data(), message.length(), addr, port); +} + +size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port) +{ + if(!message) { + return 0; + } + return writeTo(message.data(), message.length(), addr, port); +} + +size_t AsyncUDP::send(AsyncUDPMessage &message) +{ + if(!message) { + return 0; + } + return writeTo(message.data(), message.length(), &(_pcb->remote_ip), _pcb->remote_port); +} + +size_t AsyncUDP::broadcastTo(AsyncUDPMessage &message, uint16_t port) +{ + if(!message) { + return 0; + } + return broadcastTo(message.data(), message.length(), port); +} + +size_t AsyncUDP::broadcast(AsyncUDPMessage &message) +{ + if(!message) { + return 0; + } + return broadcast(message.data(), message.length()); +} + +AsyncUDP::operator bool() +{ + return _connected; +} + +bool AsyncUDP::connected() +{ + return _connected; +} + +esp_err_t AsyncUDP::lastErr() { + return _lastErr; +} + +void AsyncUDP::onPacket(AuPacketHandlerFunctionWithArg cb, void * arg) +{ + onPacket(std::bind(cb, arg, std::placeholders::_1)); +} + +void AsyncUDP::onPacket(AuPacketHandlerFunction cb) +{ + _handler = cb; +} diff --git a/cores/common/arduino/libraries/common/AsyncUDP/src/AsyncUDP.h b/cores/common/arduino/libraries/common/AsyncUDP/src/AsyncUDP.h new file mode 100644 index 000000000..507218e6e --- /dev/null +++ b/cores/common/arduino/libraries/common/AsyncUDP/src/AsyncUDP.h @@ -0,0 +1,142 @@ +#ifndef ESPASYNCUDP_H +#define ESPASYNCUDP_H + +#ifndef CONFIG_TCP_MSS +#define CONFIG_TCP_MSS 1436 +#endif + +#include "IPAddress.h" +#include "Print.h" +#include "Stream.h" +#include +extern "C" { +#include "lwip/ip_addr.h" +} +class AsyncUDP; +class AsyncUDPPacket; +class AsyncUDPMessage; +struct udp_pcb; +struct pbuf; + +typedef std::function AuPacketHandlerFunction; +typedef std::function AuPacketHandlerFunctionWithArg; + +class AsyncUDPMessage : public Print +{ +protected: + uint8_t *_buffer; + size_t _index; + size_t _size; +public: + AsyncUDPMessage(size_t size=CONFIG_TCP_MSS); + virtual ~AsyncUDPMessage(); + size_t write(const uint8_t *data, size_t len); + size_t write(uint8_t data); + size_t space(); + uint8_t * data(); + size_t length(); + void flush(); + operator bool() + { + return _buffer != NULL; + } +}; + +class AsyncUDPPacket : public Stream +{ +protected: + AsyncUDP *_udp; + pbuf *_pb; + ip_addr_t _localIp; + uint16_t _localPort; + ip_addr_t _remoteIp; + uint16_t _remotePort; + uint8_t _remoteMac[6]; + uint8_t *_data; + size_t _len; + size_t _index; +public: + AsyncUDPPacket(AsyncUDPPacket &packet); + AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *addr, uint16_t port); + virtual ~AsyncUDPPacket(); + + uint8_t * data(); + size_t length(); + bool isBroadcast(); + bool isMulticast(); + + IPAddress localIP(); + uint16_t localPort(); + IPAddress remoteIP(); + uint16_t remotePort(); + void remoteMac(uint8_t * mac); + + size_t send(AsyncUDPMessage &message); + + int available(); + size_t read(uint8_t *data, size_t len); + int read(); + int peek(); + void flush(); + + size_t write(const uint8_t *data, size_t len); + size_t write(uint8_t data); +}; + +class AsyncUDP : public Print +{ +protected: + udp_pcb *_pcb; + //SemaphoreHandle_t _lock; + bool _connected; + esp_err_t _lastErr; + AuPacketHandlerFunction _handler; + + bool _init(); + void _recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port); + +public: + AsyncUDP(); + virtual ~AsyncUDP(); + + void onPacket(AuPacketHandlerFunctionWithArg cb, void * arg=NULL); + void onPacket(AuPacketHandlerFunction cb); + + bool listen(const ip_addr_t *addr, uint16_t port); + bool listen(const IPAddress addr, uint16_t port); + bool listen(uint16_t port); + + bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1); + bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1); + + bool connect(const ip_addr_t *addr, uint16_t port); + bool connect(const IPAddress addr, uint16_t port); + + void close(); + + size_t writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, uint16_t port); + size_t writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port); + size_t write(const uint8_t *data, size_t len); + size_t write(uint8_t data); + + size_t broadcastTo(uint8_t *data, size_t len, uint16_t port); + size_t broadcastTo(const char * data, uint16_t port); + size_t broadcast(uint8_t *data, size_t len); + size_t broadcast(const char * data); + + size_t sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port); + size_t sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port); + size_t send(AsyncUDPMessage &message); + + size_t broadcastTo(AsyncUDPMessage &message, uint16_t port); + size_t broadcast(AsyncUDPMessage &message); + + IPAddress listenIP(); + bool connected(); + esp_err_t lastErr(); + operator bool(); + + static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port); +}; + +#endif diff --git a/cores/common/arduino/src/wiring/wiring_compat.h b/cores/common/arduino/src/wiring/wiring_compat.h index 811c6de8d..7dfe65359 100644 --- a/cores/common/arduino/src/wiring/wiring_compat.h +++ b/cores/common/arduino/src/wiring/wiring_compat.h @@ -13,6 +13,27 @@ extern "C" { #define ESP_OK 0 /*!< esp_err_t value indicating success (no error) */ #define ESP_FAIL -1 /*!< Generic esp_err_t code indicating failure */ +#define ESP_ERR_NO_MEM 0x101 /*!< Out of memory */ +#define ESP_ERR_INVALID_ARG 0x102 /*!< Invalid argument */ +#define ESP_ERR_INVALID_STATE 0x103 /*!< Invalid state */ +#define ESP_ERR_INVALID_SIZE 0x104 /*!< Invalid size */ +#define ESP_ERR_NOT_FOUND 0x105 /*!< Requested resource not found */ +#define ESP_ERR_NOT_SUPPORTED 0x106 /*!< Operation or feature not supported */ +#define ESP_ERR_TIMEOUT 0x107 /*!< Operation timed out */ +#define ESP_ERR_INVALID_RESPONSE 0x108 /*!< Received response was invalid */ +#define ESP_ERR_INVALID_CRC 0x109 /*!< CRC or checksum was invalid */ +#define ESP_ERR_INVALID_VERSION 0x10A /*!< Version was invalid */ +#define ESP_ERR_INVALID_MAC 0x10B /*!< MAC address was invalid */ +#define ESP_ERR_NOT_FINISHED 0x10C /*!< Operation has not fully completed */ +#define ESP_ERR_NOT_ALLOWED 0x10D /*!< Operation is not allowed */ + + +#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ +#define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */ +#define ESP_ERR_FLASH_BASE 0x6000 /*!< Starting number of flash error codes */ +#define ESP_ERR_HW_CRYPTO_BASE 0xc000 /*!< Starting number of HW cryptography module error codes */ +#define ESP_ERR_MEMPROT_BASE 0xd000 /*!< Starting number of Memory Protection API error codes */ + // ArduinoCore-API doesn't define these anymore #define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer)) #define PGM_VOID_P const void *