From 89234e9f121a90776d615c20ce11e12307149de9 Mon Sep 17 00:00:00 2001 From: Jochen Vothknecht <jochen3120@gmail.com> Date: Thu, 14 Apr 2022 10:00:50 +0200 Subject: [PATCH] Integrating UDP and timer stuff into SpiderLib --- CLC-qthing/SpiderLib/UDP.cpp | 135 ++++++++++++++++++++++++++++++++++ CLC-qthing/SpiderLib/UDP.hpp | 15 ++++ CLC-qthing/SpiderLib/Util.cpp | 21 ++++++ CLC-qthing/SpiderLib/Util.hpp | 22 ++++++ 4 files changed, 193 insertions(+) create mode 100644 CLC-qthing/SpiderLib/UDP.cpp create mode 100644 CLC-qthing/SpiderLib/UDP.hpp create mode 100644 CLC-qthing/SpiderLib/Util.cpp create mode 100644 CLC-qthing/SpiderLib/Util.hpp diff --git a/CLC-qthing/SpiderLib/UDP.cpp b/CLC-qthing/SpiderLib/UDP.cpp new file mode 100644 index 0000000..4f4e7f3 --- /dev/null +++ b/CLC-qthing/SpiderLib/UDP.cpp @@ -0,0 +1,135 @@ +#include "UDP.hpp" + +/* + +#include <lwip/netdb.h> + +#include <map> + +#include "esp_log.h" +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" + + +static const char* TAG = "udp-server"; + +static const in_port_t PORT = 4213; + +// rate-limits positive udp log messages; time in milliseconds +static const uint16_t loggingTimeout = 500; // TODO: make configurable?! + +static std::map<std::string, qthing::udpPacketCallback> packetCallbackMap; + +void qthing::addUDPPacketCallback(std::string magicString, qthing::udpPacketCallback callback) { + if (packetCallbackMap.count(magicString) > 0) { + qthing::udpPacketCallback old_callback = packetCallbackMap.at(magicString); + packetCallbackMap[magicString] = [old_callback, callback](udpPacket packet) { + old_callback(packet); + callback(packet); + }; + } else { + packetCallbackMap[magicString] = callback; + } + + ESP_LOGI(TAG, "Registered callback for packets with magic string %s", magicString.c_str()); +} + +static char rx_buffer[2048]; // TODO: get MTU + +static void udp_server_task(void* pvParameters) { + char addr_str[128]; + int addr_family; + int ip_protocol; + + struct sockaddr_in6 destAddr; + bzero(&destAddr.sin6_addr.un, sizeof(destAddr.sin6_addr.un)); + destAddr.sin6_family = AF_INET6; + destAddr.sin6_port = htons(PORT); + addr_family = AF_INET6; + ip_protocol = IPPROTO_IPV6; + inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); + + while (true) { + int sock = socket(addr_family, SOCK_DGRAM, ip_protocol); + if (sock < 0) { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + break; + } + ESP_LOGI(TAG, "Socket created"); + + int err = bind(sock, (struct sockaddr*)&destAddr, sizeof(destAddr)); + if (err < 0) { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + } + ESP_LOGI(TAG, "Socket bound"); + ESP_LOGI(TAG, "Waiting for data"); + + // This is for the rate limited logging only + uint32_t loggingBytes = 0; + uint16_t loggingPackets = 0; + uint32_t loggingLastMillis = qthing::millis(); + + while (true) { + struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6 + socklen_t socklen = sizeof(sourceAddr); + + memset(rx_buffer, 0, sizeof(rx_buffer)); + int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr*)&sourceAddr, &socklen); + + // Error occured during receiving + if (len < 0) { + ESP_LOGE(TAG, "recvfrom failed: errno %d", errno); + break; + } + // Data received + else { + + if (loggingTimeout == 0) { + ESP_LOGI(TAG, "Received %d bytes from %s", len, qthing::to_string(sourceAddr).c_str()); + } else { + loggingBytes += len; + loggingPackets += 1; + + if (qthing::millis() - loggingLastMillis > loggingTimeout) { + + ESP_LOGI(TAG, "Received %d bytes in %d packets", loggingBytes, loggingPackets); + + loggingBytes = 0; + loggingPackets = 0; + loggingLastMillis = qthing::millis(); + } + } + + std::string payload_str(rx_buffer); + int16_t lenBestMatch = -1; + qthing::udpPacketCallback callback = NULL; + for (auto it = packetCallbackMap.begin(); it != packetCallbackMap.end(); ++it) { + if (len >= it->first.length() && payload_str.find(it->first) == 0) { + lenBestMatch = len; + callback = it->second; + } + } + + if (lenBestMatch > -1) { + qthing::udpPacket packet = {.sourceAddr = sourceAddr, .payload = rx_buffer, .length = (uint16_t)len}; + + callback(packet); + } else { + ESP_LOGW(TAG, "Packet has unknown magic string"); + } + } + } + + if (sock != -1) { + ESP_LOGE(TAG, "Shutting down socket and restarting..."); + shutdown(sock, 0); + close(sock); + } + } + vTaskDelete(NULL); +} + +void qthing::start_udp_server() { xTaskCreate(udp_server_task, "udp_server", 4096, NULL, 5, NULL); } + +*/ diff --git a/CLC-qthing/SpiderLib/UDP.hpp b/CLC-qthing/SpiderLib/UDP.hpp new file mode 100644 index 0000000..40e3bb9 --- /dev/null +++ b/CLC-qthing/SpiderLib/UDP.hpp @@ -0,0 +1,15 @@ +#pragma once + + +/* + +namespace SpiderLib { + + + void start_udp_server(); + + +} + + +*/ \ No newline at end of file diff --git a/CLC-qthing/SpiderLib/Util.cpp b/CLC-qthing/SpiderLib/Util.cpp new file mode 100644 index 0000000..e563259 --- /dev/null +++ b/CLC-qthing/SpiderLib/Util.cpp @@ -0,0 +1,21 @@ +#include "Util.hpp" + +// ESP32 specific +#include "esp_timer.h" + +// C++ system level +#include <cinttypes> + +// project specific +// #include "MyHeader.hpp" + + + +namespace SpiderLib { + + + uint32_t Time::s() { return (uint64_t)(esp_timer_get_time() / 1000000ULL); } + uint64_t Time::ms() { return (uint64_t)(esp_timer_get_time() / 1000ULL); } + uint64_t Time::us() { return (uint64_t) esp_timer_get_time(); } + +} diff --git a/CLC-qthing/SpiderLib/Util.hpp b/CLC-qthing/SpiderLib/Util.hpp new file mode 100644 index 0000000..b8e049a --- /dev/null +++ b/CLC-qthing/SpiderLib/Util.hpp @@ -0,0 +1,22 @@ +#pragma once + +// ESP32 specific +// #include "MyHeader.h" + +// C++ system level +#include <cinttypes> + +// project specific +// #include "MyHeader.hpp" + + +namespace SpiderLib { + + + class Time { + public: + static uint32_t s(); + static uint64_t ms(); + static uint64_t us(); + }; +} -- GitLab