/** * @file etherCommon.hpp * @author Gustice * @brief Helper Functions for Ethernet usage * * @copyright Copyright (c) 2024 */ #pragma once #include "esp_log.h" #include "esp_netif.h" #include "lwip/err.h" #include "lwip/sockets.h" #include "lwip/sys.h" #include #include #include #include #if defined(CONFIG_LWIP_NETBUF_RECVINFO) constexpr bool NETBUF_RECVINFO = true; #else constexpr bool NETBUF_RECVINFO = false; #endif #if defined(CONFIG_EXAMPLE_IPV4) constexpr bool USE_IPV4 = true; #else constexpr bool USE_IPV4 = false; #endif #if defined(CONFIG_EXAMPLE_IPV6) constexpr bool USE_IPV6 = true; #else constexpr bool USE_IPV6 = false; #endif class Ip { public: Ip(uint32_t ipV4) { _address.word = ipV4; } Ip(esp_ip4_addr_t ipV4) { _address.word = ipV4.addr; } Ip(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) { _address.bytes[0] = b0; _address.bytes[1] = b1; _address.bytes[2] = b2; _address.bytes[3] = b3; } Ip(std::string ipStr) { _address.word = ipaddr_addr(ipStr.c_str()); } uint8_t operator[](int index) const { return _address.bytes[index]; }; uint32_t asWord() const { return _address.word; } std::string asString() const { return inet_ntoa(_address.word); } private: union { uint8_t bytes[4]; // IPv4 address uint32_t word; } _address; }; class Mac { public: Mac(uint8_t val[NETIF_MAX_HWADDR_LEN]) { std::memcpy(bytes.begin(), val, NETIF_MAX_HWADDR_LEN); } uint8_t operator[](int index) const { return bytes[index]; }; std::string asString() const { char buffer[64]; sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]); return {buffer}; } const std::array &asArray() const { return bytes; } private: std::array bytes; // IPv4 address }; /** * @brief IP-set class */ struct IpInfo { /// @brief IP address Ip address{0u}; /// @brief IP subnet Ip subnet{0u}; /// @brief Gateway IP Ip gateway{0u}; /// @brief MAC-Address Mac macAddress; /// @brief Get broadcast address from IP and subnet /// @return Ip getBradcastAddress() const { auto sn = address.asWord() | ~subnet.asWord(); return Ip(sn); } }; struct IpAdr { public: IpAdr(std::string ipStr, uint16_t port); IpAdr(uint32_t ip, uint16_t port); IpAdr(uint16_t port); IpAdr(sockaddr_in ipV4data); static constexpr int IpProtocol = IPPROTO_IP; // IPPROTO_IPV6 for version 6 static constexpr int ProtocolFamily = AF_INET; // AF_INET6 for version 6 /// @brief StackFamily e.g. AF_INET or AF_INET6 sa_family_t getProtocolFamily() const { return addrStore.ss_family; } std::string getIp() { struct sockaddr_in *ipV4 = (struct sockaddr_in *)&addrStore; return inet_ntoa(ipV4->sin_addr.s_addr); } uint16_t getPort() const { struct sockaddr_in *ipV4 = (struct sockaddr_in *)&addrStore; return ntohs(ipV4->sin_port); }; struct sockaddr *asSockAddrPtr() const { return (struct sockaddr *)&addrStore; } static constexpr int Size = sizeof(sockaddr_storage); private: struct sockaddr_storage addrStore; }; struct IpAdrV6 { public: IpAdrV6(std::string ipStr, uint16_t port); IpAdrV6(in6_addr ip, uint16_t port); IpAdrV6(uint16_t port); IpAdrV6(sockaddr_in6 ipV6data); static constexpr int IpProtocol = IPPROTO_IPV6; static constexpr int ProtocolFamily = AF_INET6; /// @brief StackFamily e.g. AF_INET or AF_INET6 sa_family_t getProtocolFamily() const { return addrStore.ss_family; } std::string getIp() { struct sockaddr_in6 *ipV6 = (struct sockaddr_in6 *)&addrStore; return inet6_ntoa(ipV6->sin6_addr); } uint16_t getPort() const { struct sockaddr_in6 *ipV6 = (struct sockaddr_in6 *)&addrStore; return ntohs(ipV6->sin6_port); }; struct sockaddr *asSockAddrPtr() const { return (struct sockaddr *)&addrStore; } static constexpr int Size = sizeof(sockaddr_storage); private: struct sockaddr_storage addrStore; }; /** * @brief Simplified abstraction for sockets */ class SocketBase { public: /// @brief Get if stream is active /// @return true if active virtual bool isActive() { return active; } IpInfo getIpInfo() { auto *netIf = esp_netif_get_default_netif(); esp_netif_ip_info_t ip; uint8_t mac[NETIF_MAX_HWADDR_LEN]; ESP_ERROR_CHECK(esp_netif_get_ip_info(netIf, &ip)); ESP_ERROR_CHECK(esp_netif_get_mac(netIf, mac)); IpInfo ips{ .address = Ip{ip.ip}, .subnet = Ip(ip.netmask), .gateway = Ip(ip.netmask), .macAddress = Mac(mac)}; return ips; } protected: bool active; };