diff --git a/src/espwifiutils.cpp b/src/espwifiutils.cpp index 76a0dd0..4335dd0 100644 --- a/src/espwifiutils.cpp +++ b/src/espwifiutils.cpp @@ -1,5 +1,8 @@ #include "espwifiutils.h" +// system includes +#include + // esp-idf includes #include @@ -116,13 +119,28 @@ std::string toString(esp_netif_dhcp_status_t status) } } -std::string toString(const mac_t &mac) +template<> tl::expected fromString(std::string_view str) { - return fmt::format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", - mac.at(0), mac.at(1), mac.at(2), mac.at(3), mac.at(4), mac.at(5)); + mac_t result; + if (std::sscanf(str.data(), "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", + &result[0], &result[1], &result[2], &result[3], &result[4], &result[5]) == 6) + return result; + + return tl::make_unexpected(fmt::format("invalid format ({})", str)); } -/*static*/ tl::expected ip_address_t::parseFromString(std::string_view address) +std::string toString(const mac_t &val) +{ + return fmt::format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + val.at(0), val.at(1), val.at(2), val.at(3), val.at(4), val.at(5)); +} + +std::string toString(const std::optional &val) +{ + return val ? toString(*val) : "nullopt"; +} + +template<> tl::expected fromString(std::string_view str) { // TODO: add support for "a", "a.b", "a.b.c" formats // TODO: replace with scanf for better performance @@ -132,7 +150,7 @@ std::string toString(const mac_t &mac) uint16_t acc = 0; // Accumulator uint8_t dots = 0; - for (char c : address) + for (char c : str) { if (c >= '0' && c <= '9') { @@ -145,7 +163,7 @@ std::string toString(const mac_t &mac) if (dots == 3) return tl::make_unexpected("Too many dots (there must be 3 dots)"); - result._bytes[dots++] = acc; + result[dots++] = acc; acc = 0; } else @@ -155,14 +173,19 @@ std::string toString(const mac_t &mac) if (dots != 3) return tl::make_unexpected("Too few dots (there must be 3 dots)"); - result._bytes[3] = acc; + result[3] = acc; return result; } -std::string toString(const ip_address_t &address) +std::string toString(ip_address_t val) { - return fmt::format("{}.{}.{}.{}", address[0], address[1], address[2], address[3]); + return fmt::format("{}.{}.{}.{}", val[0], val[1], val[2], val[3]); +} + +std::string toString(const std::optional &val) +{ + return val ? toString(*val) : "nullopt"; } ip_address_t wifi_calculate_network_id(ip_address_t ip, ip_address_t subnet) diff --git a/src/espwifiutils.h b/src/espwifiutils.h index fcf90c0..4700b66 100644 --- a/src/espwifiutils.h +++ b/src/espwifiutils.h @@ -5,6 +5,7 @@ #include #include #include +#include // esp-idf includes #include @@ -24,12 +25,17 @@ std::string toString(wifi_cipher_type_t cipherType); std::string toString(esp_interface_t interface); std::string toString(esp_netif_dhcp_status_t status); +template tl::expected fromString(std::string_view str) = delete; + // A class to make it easier to handle and pass around mac addresses / bssids class mac_t : public std::array { public: + static constexpr const size_t static_size = 6; + using std::array::array; + using std::array::operator=; constexpr explicit mac_t(const uint8_t (&arr)[6]) noexcept { @@ -42,7 +48,9 @@ public: } }; -std::string toString(const mac_t &mac); +template<> tl::expected fromString(std::string_view str); +std::string toString(const mac_t &val); +std::string toString(const std::optional &val); // A class to make it easier to handle and pass around IP addresses // Implementation taken from arduino-esp32 @@ -68,23 +76,22 @@ public: constexpr explicit ip_address_t(esp_ip4_addr_t address) noexcept : _value{address.addr} {} constexpr ip_address_t(std::array bytes) noexcept : _bytes{bytes} {} - static tl::expected parseFromString(std::string_view address); - // Access the raw byte array containing the address. Because this returns a pointer // to the internal structure rather than a copy of the address this function should only // be used when you know that the usage of the returned uint8_t* will be transient and not // stored. constexpr std::array &bytes() noexcept { return _bytes; } - constexpr std::array bytes() const noexcept { return _bytes; } + constexpr const std::array &bytes() const noexcept { return _bytes; } - constexpr value_t value() const noexcept { return _value; } + constexpr value_t &value() noexcept { return _value; } + constexpr const value_t &value() const noexcept { return _value; } friend constexpr bool operator==(const ip_address_t &left, const ip_address_t &right) noexcept { return left._value == right._value; } friend constexpr bool operator!=(const ip_address_t &left, const ip_address_t &right) noexcept { return !(left == right); } // Overloaded index operator to allow getting and setting individual octets of the address - constexpr uint8_t& operator[](int index) noexcept { return _bytes[index]; } - constexpr uint8_t operator[](int index) const noexcept { return _bytes[index]; } + constexpr uint8_t &operator[](int index) noexcept { return _bytes[index]; } + constexpr const uint8_t &operator[](int index) const noexcept { return _bytes[index]; } // Overloaded copy operators to allow initialisation of ip_address_t objects from other types constexpr ip_address_t& operator=(const ip_address_t &other) noexcept { _value = other._value; return *this; } @@ -92,7 +99,9 @@ public: constexpr ip_address_t& operator=(value_t value) noexcept { _value = value; return *this; } }; -std::string toString(const ip_address_t &val); +template<> tl::expected fromString(std::string_view str); +std::string toString(ip_address_t val); +std::string toString(const std::optional &val); ip_address_t wifi_calculate_network_id(ip_address_t ip, ip_address_t subnet); ip_address_t wifi_calculate_broadcast(ip_address_t ip, ip_address_t subnet);