diff --git a/src/asyncudplistener.cpp b/src/asyncudplistener.cpp index 19311f0..6740e87 100644 --- a/src/asyncudplistener.cpp +++ b/src/asyncudplistener.cpp @@ -27,7 +27,7 @@ struct lwip_event_packet_t struct netif *netif; }; -typedef struct +struct udp_api_call_t { struct tcpip_api_call_data call; udp_pcb * pcb; @@ -36,7 +36,24 @@ typedef struct struct pbuf *pb; struct netif *netif; err_t err; -} udp_api_call_t; +}; + +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; +} + +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; +} err_t _udp_bind_api(struct tcpip_api_call_data *api_call_msg) { @@ -55,6 +72,22 @@ err_t _udp_bind(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port) return msg.err; } +err_t _udp_send_api(struct tcpip_api_call_data *api_call_msg) +{ + udp_api_call_t *msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_send(msg->pcb, msg->pb); + return msg->err; +} + +err_t _udp_send(struct udp_pcb *pcb, struct pbuf *pb) +{ + udp_api_call_t msg; + msg.pcb = pcb; + msg.pb = pb; + tcpip_api_call(_udp_send_api, (struct tcpip_api_call_data *)&msg); + return msg.err; +} + 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; @@ -147,16 +180,8 @@ std::expected makeUdpPacketWrapper(pbufUniquePtr bool AsyncUdpListener::listen(const ip_addr_t *addr, uint16_t port) { - if (!_udp_queue.constructed()) - { - _udp_queue.construct(UBaseType_t{32}, sizeof(lwip_event_packet_t *)); - if (!_udp_queue->handle) - { - _udp_queue.destruct(); - ESP_LOGE(TAG, "xQueueCreate failed"); - return false; - } - } + if (!ensureQueue()) + return false; close(); @@ -173,9 +198,9 @@ bool AsyncUdpListener::listen(const ip_addr_t *addr, uint16_t port) } // ESP_LOGI(TAG, "calling udp_bind()..."); - if (_udp_bind(_pcb, addr, port) != ERR_OK) + if (const auto err = _udp_bind(_pcb, addr, port); err != ERR_OK) { - ESP_LOGE(TAG, "failed to bind"); + ESP_LOGE(TAG, "bind() failed with %i", err); return false; } @@ -184,6 +209,56 @@ bool AsyncUdpListener::listen(const ip_addr_t *addr, uint16_t port) return true; } +bool AsyncUdpListener::connect(ip_addr_t ip, uint16_t port) +{ + if (!ensureQueue()) + return false; + + close(); + + if (!_init()) + { + ESP_LOGE(TAG, "failed to init"); + return false; + } + +// ESP_LOGI(TAG, "calling udp_connect()..."); + if (const auto err = _udp_connect(_pcb, &ip, port); err != ERR_OK) + { + ESP_LOGE(TAG, "connect() failed with %i", err); + return false; + } + + _connected = true; + + return true; +} + +bool AsyncUdpListener::connect(esp_ip_addr_t ip, uint16_t port) +{ + return connect(wifi_stack::convertIp(ip), port); +} + +bool AsyncUdpListener::send(std::string_view buffer) +{ + auto pbt = pbufUniquePtr{pbuf_alloc(PBUF_TRANSPORT, buffer.size(), PBUF_RAM), pbuf_free}; + if (!pbt) + { + ESP_LOGE(TAG, "could not allocate pbf"); + return false; + } + + std::memcpy(pbt->payload, buffer.data(), buffer.size()); + + if (const auto err = _udp_send(_pcb, pbt.get()); err != ERR_OK) + { + ESP_LOGE(TAG, "send() failed with %i", err); + return false; + } + + return true; +} + std::optional AsyncUdpListener::poll(TickType_t xTicksToWait) { if (!_udp_queue.constructed()) @@ -280,6 +355,22 @@ void AsyncUdpListener::close() } } +bool AsyncUdpListener::ensureQueue() +{ + if (!_udp_queue.constructed()) + { + _udp_queue.construct(UBaseType_t{32}, sizeof(lwip_event_packet_t *)); + if (!_udp_queue->handle) + { + _udp_queue.destruct(); + ESP_LOGE(TAG, "xQueueCreate failed"); + return false; + } + } + + return true; +} + bool AsyncUdpListener::_init() { if (!_pcb) diff --git a/src/asyncudplistener.h b/src/asyncudplistener.h index 8edd688..9538006 100644 --- a/src/asyncudplistener.h +++ b/src/asyncudplistener.h @@ -90,6 +90,11 @@ public: return listen(IP_ANY_TYPE, port); } + bool connect(ip_addr_t ip, uint16_t port); + bool connect(esp_ip_addr_t ip, uint16_t port); + + bool send(std::string_view buffer); + std::optional poll(TickType_t xTicksToWait = 0); void _udp_task_post(udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif); @@ -97,6 +102,7 @@ public: void close(); private: + bool ensureQueue(); bool _init(); private: