diff --git a/esp_modem/CMakeLists.txt b/esp_modem/CMakeLists.txt index 1d6e17644..ae6b43ef6 100644 --- a/esp_modem/CMakeLists.txt +++ b/esp_modem/CMakeLists.txt @@ -1,18 +1,31 @@ -set(srcs "src/esp_modem_dte.cpp" +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") + set(platform_srcs src/esp_modem_primitives_linux.cpp + src/esp_modem_uart_linux.cpp + src/esp_modem_netif_linux.cpp) + set(dependencies esp_system_protocols_linux) +else() + set(platform_srcs src/esp_modem_primitives_freertos.cpp + src/esp_modem_uart.cpp + src/esp_modem_netif.cpp) + set(dependencies driver) +endif() + +set(srcs ${platform_srcs} + "src/esp_modem_dte.cpp" "src/esp_modem_dce.cpp" - "src/esp_modem_netif.cpp" "src/esp_modem_api.cpp" "src/esp_modem_factory.cpp" "src/esp_modem_cmux.cpp" "src/esp_modem_command_library.cpp" - "src/esp_modem_modules.cpp" - "src/esp_modem_uart.cpp") + "src/esp_modem_modules.cpp") set(include_dirs "include") idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS private_include - REQUIRES driver) + REQUIRES ${dependencies}) -target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17) \ No newline at end of file +target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17) diff --git a/esp_modem/include/cxx_include/esp_modem_dce.hpp b/esp_modem/include/cxx_include/esp_modem_dce.hpp index bb644467a..c93611699 100644 --- a/esp_modem/include/cxx_include/esp_modem_dce.hpp +++ b/esp_modem/include/cxx_include/esp_modem_dce.hpp @@ -58,9 +58,10 @@ public: return dte->command(command, std::move(got_line), time_ms); } -protected: bool set_mode(modem_mode m) { return mode.set(dte.get(), module.get(), netif, m); } +protected: + std::shared_ptr dte; std::shared_ptr module; diff --git a/esp_modem/include/cxx_include/esp_modem_dce_factory.hpp b/esp_modem/include/cxx_include/esp_modem_dce_factory.hpp index eb0d31918..dd31805cc 100644 --- a/esp_modem/include/cxx_include/esp_modem_dce_factory.hpp +++ b/esp_modem/include/cxx_include/esp_modem_dce_factory.hpp @@ -50,12 +50,12 @@ template class Builder { static_assert(std::is_base_of::value, "Builder must be used only for Module classes"); public: - explicit Builder(std::shared_ptr dte): dte(std::move(dte)) - { - esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_PPP(); - netif = esp_netif_new(&netif_config); - throw_if_false(netif != nullptr, "Cannot create default PPP netif"); - } +// explicit Builder(std::shared_ptr dte): dte(std::move(dte)) +// { +// esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_PPP(); +// netif = esp_netif_new(&netif_config); +// throw_if_false(netif != nullptr, "Cannot create default PPP netif"); +// } Builder(std::shared_ptr x, esp_netif_t* esp_netif): dte(std::move(x)), module(nullptr), netif(esp_netif) { diff --git a/esp_modem/include/cxx_include/esp_modem_dte.hpp b/esp_modem/include/cxx_include/esp_modem_dte.hpp index a8c941ad2..22a3c8313 100644 --- a/esp_modem/include/cxx_include/esp_modem_dte.hpp +++ b/esp_modem/include/cxx_include/esp_modem_dte.hpp @@ -69,7 +69,7 @@ private: void setup_cmux(); - static const size_t GOT_LINE = BIT0; + static const size_t GOT_LINE = signal_group::bit0; size_t buffer_size; size_t consumed; std::unique_ptr buffer; diff --git a/esp_modem/include/cxx_include/esp_modem_exception.hpp b/esp_modem/include/cxx_include/esp_modem_exception.hpp new file mode 100644 index 000000000..d696bfd22 --- /dev/null +++ b/esp_modem/include/cxx_include/esp_modem_exception.hpp @@ -0,0 +1,66 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_MODEM_EXCEPTION_HPP_ +#define _ESP_MODEM_EXCEPTION_HPP_ + +#include +#include "esp_err.h" + +namespace esp_modem { + +#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS +#define THROW(exception) throw(exception) +class esp_err_exception: virtual public std::exception { +public: + explicit esp_err_exception(esp_err_t err): esp_err(err) {} + explicit esp_err_exception(std::string msg): esp_err(ESP_FAIL), message(std::move(msg)) {} + explicit esp_err_exception(std::string msg, esp_err_t err): esp_err(err), message(std::move(msg)) {} + virtual esp_err_t get_err_t() { return esp_err; } + ~esp_err_exception() noexcept override = default; + virtual const char* what() const noexcept { + return message.c_str(); + } +private: + esp_err_t esp_err; + std::string message; +}; +#else +#define THROW(exception) abort() +#endif + +static inline void throw_if_false(bool condition, std::string message) +{ + if (!condition) { + THROW(esp_err_exception(std::move(message))); + } +} + +static inline void throw_if_esp_fail(esp_err_t err, std::string message) +{ + if (err != ESP_OK) { + THROW(esp_err_exception(std::move(message), err)); + } +} + +static inline void throw_if_esp_fail(esp_err_t err) +{ + if (err != ESP_OK) { + THROW(esp_err_exception(err)); + } +} + +} // namespace esp_modem + +#endif //_ESP_MODEM_EXCEPTION_HPP_ diff --git a/esp_modem/include/cxx_include/esp_modem_netif.hpp b/esp_modem/include/cxx_include/esp_modem_netif.hpp index c0aa8e7cb..f2afbbea1 100644 --- a/esp_modem/include/cxx_include/esp_modem_netif.hpp +++ b/esp_modem/include/cxx_include/esp_modem_netif.hpp @@ -15,6 +15,8 @@ #ifndef _ESP_MODEM_NETIF_HPP #define _ESP_MODEM_NETIF_HPP +#include +#include #include "esp_netif.h" #include "cxx_include/esp_modem_primitives.hpp" @@ -36,7 +38,7 @@ public: void start(); - void wait_until_ppp_exits() { signal.wait(PPP_EXIT, 30000); } + void wait_until_ppp_exits(); void stop(); @@ -53,8 +55,8 @@ private: esp_netif_t *netif; struct ppp_netif_driver driver{}; signal_group signal; - static const size_t PPP_STARTED = BIT0; - static const size_t PPP_EXIT = BIT1; + static const size_t PPP_STARTED = signal_group::bit0; + static const size_t PPP_EXIT = signal_group::bit1; }; } // namespace esp_modem diff --git a/esp_modem/include/cxx_include/esp_modem_primitives.hpp b/esp_modem/include/cxx_include/esp_modem_primitives.hpp index 83a2f06ed..03a01d950 100644 --- a/esp_modem/include/cxx_include/esp_modem_primitives.hpp +++ b/esp_modem/include/cxx_include/esp_modem_primitives.hpp @@ -14,116 +14,73 @@ #ifndef _ESP_MODEM_PRIMITIVES_HPP_ #define _ESP_MODEM_PRIMITIVES_HPP_ -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" -#include "freertos/semphr.h" +#include "esp_modem_exception.hpp" + +#if defined(CONFIG_IDF_TARGET_LINUX) +#include +#else +// forward declarations of FreeRTOS primitives +struct QueueDefinition; +typedef void * EventGroupHandle_t; +#endif + namespace esp_modem { -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS -#define THROW(exception) throw(exception) -class esp_err_exception: virtual public std::exception { -public: - explicit esp_err_exception(esp_err_t err): esp_err(err) {} - explicit esp_err_exception(std::string msg): esp_err(ESP_FAIL), message(std::move(msg)) {} - explicit esp_err_exception(std::string msg, esp_err_t err): esp_err(err), message(std::move(msg)) {} - virtual esp_err_t get_err_t() { return esp_err; } - ~esp_err_exception() noexcept override = default; - virtual const char* what() const noexcept { - return message.c_str(); - } -private: - esp_err_t esp_err; - std::string message; -}; -#else -#define THROW(exception) abort() -#endif - -static inline void throw_if_false(bool condition, std::string message) -{ - if (!condition) { - THROW(esp_err_exception(std::move(message))); - } -} - -static inline void throw_if_esp_fail(esp_err_t err, std::string message) -{ - if (err != ESP_OK) { - THROW(esp_err_exception(std::move(message), err)); - } -} - -static inline void throw_if_esp_fail(esp_err_t err) -{ - if (err != ESP_OK) { - THROW(esp_err_exception(err)); - } -} - +#if !defined(CONFIG_IDF_TARGET_LINUX) struct Lock { - explicit Lock(): lock(nullptr) - { - lock = xSemaphoreCreateRecursiveMutex(); - throw_if_false(lock != nullptr, "create signal event group failed"); - } - ~Lock() { vSemaphoreDelete(lock); } - void take() { xSemaphoreTakeRecursive(lock, portMAX_DELAY); } + using MutexT = QueueDefinition*; - void give() { xSemaphoreGiveRecursive(lock); } - xSemaphoreHandle lock; + explicit Lock(); + ~Lock(); + void lock(); + void unlock(); +private: + MutexT m{}; }; +using Signal = void*; + +#else +using Lock = std::mutex; +struct SignalGroup; +using Signal = std::unique_ptr; +#endif + template class Scoped { public: - explicit Scoped(T &l):lock(l) { lock.take(); } - ~Scoped() { lock.give(); } + explicit Scoped(T &l):lock(l) { lock.lock(); } + ~Scoped() { lock.unlock(); } private: T& lock; }; struct signal_group { - explicit signal_group(): event_group(nullptr) - { - event_group = xEventGroupCreate(); - throw_if_false(event_group != nullptr, "create signal event group failed"); - } + static constexpr size_t bit0 = 1 << 0; + static constexpr size_t bit1 = 1 << 1; + static constexpr size_t bit2 = 1 << 2; + static constexpr size_t bit3 = 1 << 3; - void set(uint32_t bits) - { - xEventGroupSetBits(event_group, bits); - } + explicit signal_group(); - void clear(uint32_t bits) - { - xEventGroupClearBits(event_group, bits); - } + void set(uint32_t bits); - bool wait(uint32_t flags, uint32_t time_ms) // waiting for all and clearing if set - { - EventBits_t bits = xEventGroupWaitBits(event_group, flags, pdTRUE, pdTRUE, pdMS_TO_TICKS(time_ms)); - return bits & flags; - } + void clear(uint32_t bits); - bool is_any(uint32_t flags) - { - return xEventGroupGetBits(event_group) & flags; - } + // waiting for all and clearing if set + bool wait(uint32_t flags, uint32_t time_ms); - bool wait_any(uint32_t flags, uint32_t time_ms) // waiting for any bit, not clearing them - { - EventBits_t bits = xEventGroupWaitBits(event_group, flags, pdFALSE, pdFALSE, pdMS_TO_TICKS(time_ms)); - return bits & flags; - } + bool is_any(uint32_t flags); - ~signal_group() - { - if (event_group) vEventGroupDelete(event_group); - } + // waiting for any bit, not clearing them + bool wait_any(uint32_t flags, uint32_t time_ms); - EventGroupHandle_t event_group; + ~signal_group(); + +private: + Signal event_group; }; } // namespace esp_modem diff --git a/esp_modem/src/esp_modem_api.cpp b/esp_modem/src/esp_modem_api.cpp index db5b09896..527c0897d 100644 --- a/esp_modem/src/esp_modem_api.cpp +++ b/esp_modem/src/esp_modem_api.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include "cxx_include/esp_modem_dte.hpp" #include "uart_terminal.hpp" #include "esp_log.h" diff --git a/esp_modem/src/esp_modem_cmux.cpp b/esp_modem/src/esp_modem_cmux.cpp index da3fa9c73..d9aa8a4ff 100644 --- a/esp_modem/src/esp_modem_cmux.cpp +++ b/esp_modem/src/esp_modem_cmux.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include "cxx_include/esp_modem_dte.hpp" #include "esp_log.h" @@ -87,7 +88,7 @@ void CMUXedTerminal::start() for (size_t i = 0; i < 3; i++) { send_sabm(i); - vTaskDelay(100 / portTICK_PERIOD_MS); // Waiting before open next DLC + usleep(100'000); } } @@ -110,13 +111,13 @@ bool CMUXedTerminal::process_cmux_recv(size_t len) bool output(uint8_t *data, size_t len, std::string message) { - printf("OUTPUT: %s len=%d \n", message.c_str(), len); +// printf("OUTPUT: %s len=%ld \n", message.c_str(), len); for (int i=0; i< len; ++i) { printf("0x%02x, ",data[i]); } printf("----\n"); - printf("%.*s", len, data); + printf("%.*s", (int)len, data); return true; } @@ -219,7 +220,7 @@ void CMUXedTerminal::setup_cmux() for (size_t i = 0; i < 3; i++) { send_sabm(i); - vTaskDelay(100 / portTICK_PERIOD_MS); // Waiting before open next DLC + usleep(100'000); } } @@ -235,8 +236,6 @@ void DTE::setup_cmux() void DTE::send_cmux_command(uint8_t i, const std::string& command) { -// send_sabm(i); -// vTaskDelay(100 / portTICK_PERIOD_MS); // Waiting before open next DLC uint8_t frame[6]; frame[0] = SOF_MARKER; diff --git a/esp_modem/src/esp_modem_dte.cpp b/esp_modem/src/esp_modem_dte.cpp index f852d5bfe..518e8b49d 100644 --- a/esp_modem/src/esp_modem_dte.cpp +++ b/esp_modem/src/esp_modem_dte.cpp @@ -29,7 +29,6 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui { Scoped l(lock); command_result res = command_result::TIMEOUT; - term->write((uint8_t *)command.c_str(), command.length()); term->set_data_cb([&](size_t len){ auto data_to_read = std::min(len, buffer_size - consumed); auto data = buffer.get() + consumed; @@ -44,6 +43,7 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui } return false; }); + term->write((uint8_t *)command.c_str(), command.length()); auto got_lf = signal.wait(GOT_LINE, time_ms); if (got_lf && res == command_result::TIMEOUT) { throw_if_esp_fail(ESP_ERR_INVALID_STATE); diff --git a/esp_modem/src/esp_modem_netif.cpp b/esp_modem/src/esp_modem_netif.cpp index 6953a567f..e37c81a63 100644 --- a/esp_modem/src/esp_modem_netif.cpp +++ b/esp_modem/src/esp_modem_netif.cpp @@ -53,7 +53,7 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args) { // check if PPP error events are enabled, if not, do enable the error occurred/state changed // to notify the modem layer when switching modes esp_netif_ppp_config_t ppp_config; - esp_netif_ppp_get_params(esp_netif, &ppp_config); + // esp_netif_ppp_get_params(esp_netif, &ppp_config); if (!ppp_config.ppp_error_event_enabled) { ppp_config.ppp_error_event_enabled = true; esp_netif_ppp_set_params(esp_netif, &ppp_config); @@ -102,4 +102,8 @@ Netif::~Netif() { esp_event_handler_unregister(IP_EVENT, IP_EVENT_PPP_LOST_IP, esp_netif_action_disconnected); } +void Netif::wait_until_ppp_exits() { + signal.wait(PPP_EXIT, 30000); +} + } // namespace esp_modem \ No newline at end of file diff --git a/esp_modem/src/esp_modem_netif_linux.cpp b/esp_modem/src/esp_modem_netif_linux.cpp new file mode 100644 index 000000000..9ac784a6a --- /dev/null +++ b/esp_modem/src/esp_modem_netif_linux.cpp @@ -0,0 +1,51 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cxx_include/esp_modem_netif.hpp" + +namespace esp_modem { + +void Netif::on_ppp_changed(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) { +} + +esp_err_t Netif::esp_modem_dte_transmit(void *h, void *buffer, size_t len) { + return ESP_OK; +} + +esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args) { + return ESP_OK; +} + +void Netif::receive(uint8_t *data, size_t len) { +} + +Netif::Netif(std::shared_ptr e, esp_netif_t *ppp_netif) : + ppp_dte(std::move(e)), netif(ppp_netif) { +} + +void Netif::start() { +} + +void Netif::stop() { +} + +Netif::~Netif() { +} + +void Netif::wait_until_ppp_exits() { + +} + +} // namespace esp_modem \ No newline at end of file diff --git a/esp_modem/src/esp_modem_primitives_freertos.cpp b/esp_modem/src/esp_modem_primitives_freertos.cpp new file mode 100644 index 000000000..1403abd74 --- /dev/null +++ b/esp_modem/src/esp_modem_primitives_freertos.cpp @@ -0,0 +1,84 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cxx_include/esp_modem_primitives.hpp" + +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "freertos/semphr.h" + + + +namespace esp_modem { + + + +void Lock::unlock() { + xSemaphoreGiveRecursive(m); +} + +Lock::Lock(): m(nullptr) +{ + m = xSemaphoreCreateRecursiveMutex(); + throw_if_false(m != nullptr, "create signal event group failed"); +} + +Lock::~Lock() { + vSemaphoreDelete(m); +} + +void Lock::lock() { + xSemaphoreTakeRecursive(m, portMAX_DELAY); +} + + +signal_group::signal_group(): event_group(nullptr) +{ + event_group = xEventGroupCreate(); + throw_if_false(event_group != nullptr, "create signal event group failed"); +} + +void signal_group::set(uint32_t bits) +{ + xEventGroupSetBits(event_group, bits); +} + +void signal_group::clear(uint32_t bits) +{ + xEventGroupClearBits(event_group, bits); +} + +bool signal_group::wait(uint32_t flags, uint32_t time_ms) +{ + EventBits_t bits = xEventGroupWaitBits(event_group, flags, pdTRUE, pdTRUE, pdMS_TO_TICKS(time_ms)); + return bits & flags; +} + +bool signal_group::is_any(uint32_t flags) +{ + return xEventGroupGetBits(event_group) & flags; +} + +bool signal_group::wait_any(uint32_t flags, uint32_t time_ms) +{ + EventBits_t bits = xEventGroupWaitBits(event_group, flags, pdFALSE, pdFALSE, pdMS_TO_TICKS(time_ms)); + return bits & flags; +} + +signal_group::~signal_group() +{ + if (event_group) vEventGroupDelete(event_group); +} + +} // namespace esp_modem \ No newline at end of file diff --git a/esp_modem/src/esp_modem_primitives_linux.cpp b/esp_modem/src/esp_modem_primitives_linux.cpp new file mode 100644 index 000000000..b09c9bbf1 --- /dev/null +++ b/esp_modem/src/esp_modem_primitives_linux.cpp @@ -0,0 +1,72 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "cxx_include/esp_modem_primitives.hpp" + + +namespace esp_modem { + +struct SignalGroup { + std::condition_variable notify; + std::mutex m; + uint32_t flags{ 0 }; +}; + + +signal_group::signal_group(): event_group(std::make_unique()) +{ +} + +void signal_group::set(uint32_t bits) +{ + std::unique_lock lock(event_group->m); + event_group->flags |= bits; +} + +void signal_group::clear(uint32_t bits) +{ + std::unique_lock lock(event_group->m); + event_group->flags &= ~bits; +} + +bool signal_group::wait(uint32_t flags, uint32_t time_ms) +{ + std::unique_lock lock(event_group->m); + return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&]{ + if ((flags&event_group->flags) == flags) { + event_group->flags &= ~flags; + return true; + } + return false; + }); +// return ret != std::cv_status::timeout; +// , [&]{return flags&event_group->flags; }); +} + +bool signal_group::is_any(uint32_t flags) +{ + std::unique_lock lock(event_group->m); + return flags&event_group->flags; +} + +bool signal_group::wait_any(uint32_t flags, uint32_t time_ms) +{ + std::unique_lock lock(event_group->m); + return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&]{ return flags&event_group->flags; }); +} + +signal_group::~signal_group() = default; + +} // namespace esp_modem \ No newline at end of file diff --git a/esp_modem/src/esp_modem_uart_linux.cpp b/esp_modem/src/esp_modem_uart_linux.cpp new file mode 100644 index 000000000..8adfcdb3d --- /dev/null +++ b/esp_modem/src/esp_modem_uart_linux.cpp @@ -0,0 +1,15 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cxx_include/esp_modem_dte.hpp" diff --git a/esp_modem/test/host_test/CMakeLists.txt b/esp_modem/test/host_test/CMakeLists.txt new file mode 100644 index 000000000..e530042a3 --- /dev/null +++ b/esp_modem/test/host_test/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS ../..) + +set(COMPONENTS main) +project(host_modem_test) + + +idf_component_get_property(esp_modem esp_modem COMPONENT_LIB) +target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_COMPILER_CXX_EXCEPTIONS") +target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_IDF_TARGET_LINUX") +target_link_options(${esp_modem} INTERFACE -fsanitize=address) +#set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") +#set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") \ No newline at end of file diff --git a/esp_modem/test/host_test/components/esp_event_mock/CMakeLists.txt b/esp_modem/test/host_test/components/esp_event_mock/CMakeLists.txt new file mode 100644 index 000000000..606c16f80 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_event_mock/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS esp_event_mock.c + INCLUDE_DIRS include + REQUIRES esp_system_protocols_linux) diff --git a/esp_modem/test/host_test/components/esp_event_mock/esp_event_mock.c b/esp_modem/test/host_test/components/esp_event_mock/esp_event_mock.c new file mode 100644 index 000000000..dc4883fa5 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_event_mock/esp_event_mock.c @@ -0,0 +1,21 @@ +// +// Created by david on 2/11/21. +// + +#include "esp_err.h" +#include "esp_event.h" + + +const char * WIFI_EVENT = "WIFI_EVENT"; +const char * IP_EVENT = "IP_EVENT"; + +esp_err_t esp_event_handler_register(const char * event_base, int32_t event_id, void* event_handler, void* event_handler_arg) +{ + return ESP_OK; +} + + +esp_err_t esp_event_handler_unregister(const char * event_base, int32_t event_id, void* event_handler) +{ + return ESP_OK; +} diff --git a/esp_modem/test/host_test/components/esp_event_mock/include/esp_event.h b/esp_modem/test/host_test/components/esp_event_mock/include/esp_event.h new file mode 100644 index 000000000..75e4a3e86 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_event_mock/include/esp_event.h @@ -0,0 +1,35 @@ +// +// Created by david on 2/9/21. +// + +#ifndef MDNS_HOST_ESP_EVENT_H +#define MDNS_HOST_ESP_EVENT_H + +#include +#include "esp_netif_ip_addr.h" +#include "esp_err.h" + + +typedef void * esp_event_base_t; +typedef void * system_event_t; + +extern const char * WIFI_EVENT; +extern const char * IP_EVENT; + +#define ESP_EVENT_ANY_BASE NULL /**< register handler for any event base */ +#define ESP_EVENT_ANY_ID -1 /**< register handler for any event id */ + + +typedef struct { + int if_index; /*!< Interface index for which the event is received (left for legacy compilation) */ + esp_netif_t *esp_netif; /*!< Pointer to corresponding esp-netif object */ + esp_netif_ip6_info_t ip6_info; /*!< IPv6 address of the interface */ + int ip_index; /*!< IPv6 address index */ +} ip_event_got_ip6_t; + + +esp_err_t esp_event_handler_register(const char * event_base, int32_t event_id, void* event_handler, void* event_handler_arg); + +esp_err_t esp_event_handler_unregister(const char * event_base, int32_t event_id, void* event_handler); + +#endif //MDNS_HOST_ESP_EVENT_H diff --git a/esp_modem/test/host_test/components/esp_event_mock/include/esp_event_base.h b/esp_modem/test/host_test/components/esp_event_mock/include/esp_event_base.h new file mode 100644 index 000000000..187859a72 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_event_mock/include/esp_event_base.h @@ -0,0 +1,17 @@ +// +// Created by david on 2/9/21. +// + +#ifndef MDNS_HOST_ESP_EVENT_BASE_H +#define MDNS_HOST_ESP_EVENT_BASE_H + +typedef enum { + WIFI_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */ + WIFI_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ + WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */ + WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ + IP_EVENT_STA_GOT_IP, + IP_EVENT_GOT_IP6 +} mdns_used_event_t; + +#endif //MDNS_HOST_ESP_EVENT_BASE_H diff --git a/esp_modem/test/host_test/components/esp_netif_linux/CMakeLists.txt b/esp_modem/test/host_test/components/esp_netif_linux/CMakeLists.txt new file mode 100644 index 000000000..086034b08 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_netif_linux/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS esp_netif_linux.c + INCLUDE_DIRS include + REQUIRES esp_system_protocols_linux) diff --git a/esp_modem/test/host_test/components/esp_netif_linux/esp_netif_linux.c b/esp_modem/test/host_test/components/esp_netif_linux/esp_netif_linux.c new file mode 100644 index 000000000..fbc9332b1 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_netif_linux/esp_netif_linux.c @@ -0,0 +1,68 @@ +// +// Created by david on 2/7/21. +// +#include + +#include "esp_netif.h" +#include "esp_err.h" +#include //strlen +#include +#include //inet_addr +#include +#include +#include + +esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key) +{ + return NULL; +} + +esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) +{ + ESP_IPADDR4_INIT(&ip_info->ip, 1,2,3,4); + return ESP_OK; +} + +esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status) +{ + return ESP_OK; +} + + +esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6) +{ + + struct ifaddrs *addrs, *tmp; + getifaddrs(&addrs); + tmp = addrs; + + while (tmp) + { +// if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) +// { +// struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr; +// printf("%s: %s\n", tmp->ifa_name, inet_ntoa(pAddr->sin_addr)); +// } else + + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) { + char addr[64]; + struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr; + inet_ntop(AF_INET6, &pAddr->sin6_addr, addr, sizeof(addr) ); + printf("%s: %s\n", tmp->ifa_name, addr); + inet6_addr_to_ip6addr(if_ip6, &pAddr->sin6_addr); + } + + tmp = tmp->ifa_next; + } + + freeifaddrs(addrs); + return ESP_OK; +} + +int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif) +{ + char * ifname = "enp1s0"; + uint32_t interfaceIndex = if_nametoindex(ifname); + printf("%s: %d\n", ifname, interfaceIndex); + return interfaceIndex; +} diff --git a/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif.h b/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif.h new file mode 100644 index 000000000..83340b767 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif.h @@ -0,0 +1,60 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _HOST_ESP_NETIF_H_ +#define _HOST_ESP_NETIF_H_ + +#include +#include +#include "esp_netif_ip_addr.h" +#include "esp_err.h" +#include "esp_event.h" + +struct esp_netif_obj {}; + +typedef struct esp_netif_driver_base_s { + esp_err_t (*post_attach)(esp_netif_t *netif, void* h); + esp_netif_t *netif; +} esp_netif_driver_base_t; + +struct esp_netif_driver_ifconfig { + void* handle; + esp_err_t (*transmit)(void *h, void *buffer, size_t len); + esp_err_t (*transmit_wrap)(void *h, void *buffer, size_t len, void *netstack_buffer); + void (*driver_free_rx_buffer)(void *h, void* buffer); +}; + +typedef struct esp_netif_obj esp_netif_t; + +/** @brief Status of DHCP client or DHCP server */ +typedef enum { + ESP_NETIF_DHCP_INIT = 0, /**< DHCP client/server is in initial state (not yet started) */ + ESP_NETIF_DHCP_STARTED, /**< DHCP client/server has been started */ + ESP_NETIF_DHCP_STOPPED, /**< DHCP client/server has been stopped */ + ESP_NETIF_DHCP_STATUS_MAX +} esp_netif_dhcp_status_t; + + +esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key); + +esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info); + +esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status); + +esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6); +int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif); + +void esp_netif_action_connected(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data); +void esp_netif_action_disconnected(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data); + +#endif // _HOST_ESP_NETIF_H_ diff --git a/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif_ip_addr.h b/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif_ip_addr.h new file mode 100644 index 000000000..88ab38d3f --- /dev/null +++ b/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif_ip_addr.h @@ -0,0 +1,182 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_NETIF_IP_ADDR_H_ +#define _ESP_NETIF_IP_ADDR_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define esp_netif_htonl(x) ((uint32_t)(x)) +#else +#define esp_netif_htonl(x) ((((x) & (uint32_t)0x000000ffUL) << 24) | \ + (((x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((x) & (uint32_t)0xff000000UL) >> 24)) +#endif + +#define esp_netif_ip4_makeu32(a,b,c,d) (((uint32_t)((a) & 0xff) << 24) | \ + ((uint32_t)((b) & 0xff) << 16) | \ + ((uint32_t)((c) & 0xff) << 8) | \ + (uint32_t)((d) & 0xff)) + +// Access address in 16-bit block +#define ESP_IP6_ADDR_BLOCK1(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[0]) >> 16) & 0xffff)) +#define ESP_IP6_ADDR_BLOCK2(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[0])) & 0xffff)) +#define ESP_IP6_ADDR_BLOCK3(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[1]) >> 16) & 0xffff)) +#define ESP_IP6_ADDR_BLOCK4(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[1])) & 0xffff)) +#define ESP_IP6_ADDR_BLOCK5(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[2]) >> 16) & 0xffff)) +#define ESP_IP6_ADDR_BLOCK6(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[2])) & 0xffff)) +#define ESP_IP6_ADDR_BLOCK7(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[3]) >> 16) & 0xffff)) +#define ESP_IP6_ADDR_BLOCK8(ip6addr) ((uint16_t)((esp_netif_htonl((ip6addr)->addr[3])) & 0xffff)) + +#define IPSTR "%d.%d.%d.%d" +#define esp_ip4_addr_get_byte(ipaddr, idx) (((const uint8_t*)(&(ipaddr)->addr))[idx]) +#define esp_ip4_addr1(ipaddr) esp_ip4_addr_get_byte(ipaddr, 0) +#define esp_ip4_addr2(ipaddr) esp_ip4_addr_get_byte(ipaddr, 1) +#define esp_ip4_addr3(ipaddr) esp_ip4_addr_get_byte(ipaddr, 2) +#define esp_ip4_addr4(ipaddr) esp_ip4_addr_get_byte(ipaddr, 3) + + +#define esp_ip4_addr1_16(ipaddr) ((uint16_t)esp_ip4_addr1(ipaddr)) +#define esp_ip4_addr2_16(ipaddr) ((uint16_t)esp_ip4_addr2(ipaddr)) +#define esp_ip4_addr3_16(ipaddr) ((uint16_t)esp_ip4_addr3(ipaddr)) +#define esp_ip4_addr4_16(ipaddr) ((uint16_t)esp_ip4_addr4(ipaddr)) + +#define IP2STR(ipaddr) esp_ip4_addr1_16(ipaddr), \ + esp_ip4_addr2_16(ipaddr), \ + esp_ip4_addr3_16(ipaddr), \ + esp_ip4_addr4_16(ipaddr) + +#define IPV6STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" + +#define IPV62STR(ipaddr) ESP_IP6_ADDR_BLOCK1(&(ipaddr)), \ + ESP_IP6_ADDR_BLOCK2(&(ipaddr)), \ + ESP_IP6_ADDR_BLOCK3(&(ipaddr)), \ + ESP_IP6_ADDR_BLOCK4(&(ipaddr)), \ + ESP_IP6_ADDR_BLOCK5(&(ipaddr)), \ + ESP_IP6_ADDR_BLOCK6(&(ipaddr)), \ + ESP_IP6_ADDR_BLOCK7(&(ipaddr)), \ + ESP_IP6_ADDR_BLOCK8(&(ipaddr)) + +#define ESP_IPADDR_TYPE_V4 0U +#define ESP_IPADDR_TYPE_V6 6U +#define ESP_IPADDR_TYPE_ANY 46U + +#define ESP_IP4TOUINT32(a,b,c,d) (((uint32_t)((a) & 0xffU) << 24) | \ + ((uint32_t)((b) & 0xffU) << 16) | \ + ((uint32_t)((c) & 0xffU) << 8) | \ + (uint32_t)((d) & 0xffU)) + +#define ESP_IP4TOADDR(a,b,c,d) esp_netif_htonl(ESP_IP4TOUINT32(a, b, c, d)) + +// new definitions +#define ESP_IPADDR4_INIT(ipaddr, a,b,c,d) (ipaddr)->addr = ESP_IP4TOADDR(a,b,c,d) +#define ESP_IP6TOADDR(a, b, c, d) { { { { a, b, c, d } , 0 } }, ESP_IPADDR_TYPE_V6 } + +// TODO: use esp-netif instead of lwip API +#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6)) +#define ip_2_ip4(ipaddr) (&((ipaddr)->u_addr.ip4)) +#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0) +#define IP_GET_TYPE(ipaddr) ((ipaddr)->type) +#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == ESP_IPADDR_TYPE_V6) +#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr) +#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3];}while(0) + +#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), *ip_2_ip4(&(src))); }}while(0) + + +#define IP_MULTICAST(a) IN_CLASSD(a) + +#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & htonl(0xff000000UL)) == htonl(0xff000000UL)) +#define IP6_NO_ZONE 0 +#define ip6_addr_clear_zone(ip6addr) ((ip6addr)->zone = IP6_NO_ZONE) + +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->s6_addr32[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->s6_addr32[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->s6_addr32[2] = (source_ip6addr)->addr[2]; \ + (target_in6addr)->s6_addr32[3] = (source_ip6addr)->addr[3];} + +#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->s6_addr32[0]; \ + (target_ip6addr)->addr[1] = (source_in6addr)->s6_addr32[1]; \ + (target_ip6addr)->addr[2] = (source_in6addr)->s6_addr32[2]; \ + (target_ip6addr)->addr[3] = (source_in6addr)->s6_addr32[3]; \ + ip6_addr_clear_zone(target_ip6addr);} + + +struct esp_ip6_addr { + uint32_t addr[4]; + uint8_t zone; +}; + + + +struct esp_ip4_addr { + uint32_t addr; +}; + +typedef struct esp_ip4_addr esp_ip4_addr_t; + +typedef struct esp_ip6_addr esp_ip6_addr_t; + +typedef struct _ip_addr { + union { + esp_ip6_addr_t ip6; + esp_ip4_addr_t ip4; + } u_addr; + uint8_t type; +} esp_ip_addr_t; + +typedef enum { + ESP_IP6_ADDR_IS_UNKNOWN, + ESP_IP6_ADDR_IS_GLOBAL, + ESP_IP6_ADDR_IS_LINK_LOCAL, + ESP_IP6_ADDR_IS_SITE_LOCAL, + ESP_IP6_ADDR_IS_UNIQUE_LOCAL, + ESP_IP6_ADDR_IS_IPV4_MAPPED_IPV6 +} esp_ip6_addr_type_t; + +typedef struct { + esp_ip4_addr_t ip; /**< Interface IPV4 address */ + esp_ip4_addr_t netmask; /**< Interface IPV4 netmask */ + esp_ip4_addr_t gw; /**< Interface IPV4 gateway address */ +} esp_netif_ip_info_t; + +typedef struct { + esp_ip6_addr_t ip; /**< Interface IPV6 address */ +} esp_netif_ip6_info_t; + +/** + * @brief Get the IPv6 address type + * + * @param[in] ip6_addr IPv6 type + * + * @return IPv6 type in form of enum esp_ip6_addr_type_t + */ +esp_ip6_addr_type_t esp_netif_ip6_get_addr_type(esp_ip6_addr_t* ip6_addr); + +#ifdef __cplusplus +} +#endif + +#endif //_ESP_NETIF_IP_ADDR_H_ diff --git a/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif_ppp.h b/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif_ppp.h new file mode 100644 index 000000000..4a1b5ae6d --- /dev/null +++ b/esp_modem/test/host_test/components/esp_netif_linux/include/esp_netif_ppp.h @@ -0,0 +1,22 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#ifndef _ESP_NETIF_PPP_H_ +#define _ESP_NETIF_PPP_H_ + +#define NETIF_PP_PHASE_OFFSET 0x100 + + +#endif //_ESP_NETIF_PPP_H_ diff --git a/esp_modem/test/host_test/components/esp_system_protocols_linux/CMakeLists.txt b/esp_modem/test/host_test/components/esp_system_protocols_linux/CMakeLists.txt new file mode 100644 index 000000000..e4149f579 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_system_protocols_linux/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(INCLUDE_DIRS include + REQUIRES esp_netif_linux esp_event_mock) diff --git a/esp_modem/test/host_test/components/esp_system_protocols_linux/include/driver/uart.h b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/driver/uart.h new file mode 100644 index 000000000..1dcf89f54 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/driver/uart.h @@ -0,0 +1,6 @@ +#pragma once + +typedef int uart_port_t; +typedef int uart_word_length_t; +typedef int uart_stop_bits_t; +typedef int uart_parity_t; \ No newline at end of file diff --git a/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_err.h b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_err.h new file mode 100644 index 000000000..259e0a895 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_err.h @@ -0,0 +1,17 @@ + + +#include "esp_system_common_declares.h" + +typedef int esp_err_t; + +#define ESP_FAIL -1 +#define ESP_OK 0 + +#define ESP_ERR_NO_MEM 0x101 +#define ESP_ERR_INVALID_ARG 0x102 +#define ESP_ERR_INVALID_STATE 0x103 +#define ESP_ERR_INVALID_SIZE 0x104 +#define ESP_ERR_NOT_FOUND 0x105 +#define ESP_ERR_NOT_SUPPORTED 0x106 +#define ESP_ERR_TIMEOUT 0x107 +#define ESP_ERR_INVALID_RESPONSE 0x diff --git a/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_log.h b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_log.h new file mode 100644 index 000000000..d0095fd95 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_log.h @@ -0,0 +1,22 @@ +// +// Created by david on 2/10/21. +// + +#ifndef MDNS_HOST_ESP_LOG_H +#define MDNS_HOST_ESP_LOG_H + +#include + +#define ESP_LOG_INFO 1 +#define ESP_LOG_BUFFER_HEXDUMP(...) + +#define ESP_LOGE(TAG, ...) +//printf(TAG); printf("ERROR: " __VA_ARGS__); printf("\n") +#define ESP_LOGW(TAG, ...) +//printf(TAG); printf("WARN: "__VA_ARGS__); printf("\n") +#define ESP_LOGI(TAG, ...) +//printf(TAG); printf("INFO: "__VA_ARGS__); printf("\n") +#define ESP_LOGD(TAG, ...) +//printf(TAG); printf("DEBUG: "__VA_ARGS__); printf("\n") + +#endif //MDNS_HOST_ESP_LOG_H diff --git a/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_system_common_declares.h b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_system_common_declares.h new file mode 100644 index 000000000..a6f29caf6 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/esp_system_common_declares.h @@ -0,0 +1,13 @@ +// +// Created by david on 2/17/21. +// + +#ifndef MDNS_HOST_ESP_SYSTEM_COMMON_DECLARES_H +#define MDNS_HOST_ESP_SYSTEM_COMMON_DECLARES_H + +struct esp_netif_obj; + +typedef struct esp_netif_obj esp_netif_t; + + +#endif //MDNS_HOST_ESP_SYSTEM_COMMON_DECLARES_H diff --git a/esp_modem/test/host_test/components/esp_system_protocols_linux/include/machine/endian.h b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/machine/endian.h new file mode 100644 index 000000000..adcf1a9f3 --- /dev/null +++ b/esp_modem/test/host_test/components/esp_system_protocols_linux/include/machine/endian.h @@ -0,0 +1,10 @@ +// +// Created by david on 2/17/21. +// + +#ifndef MDNS_HOST_ENDIAN_H +#define MDNS_HOST_ENDIAN_H + +#include_next "endian.h" + +#endif //MDNS_HOST_ENDIAN_H diff --git a/esp_modem/test/host_test/main/CMakeLists.txt b/esp_modem/test/host_test/main/CMakeLists.txt new file mode 100644 index 000000000..07e4c5852 --- /dev/null +++ b/esp_modem/test/host_test/main/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register(SRCS "test_modem.cpp" + INCLUDE_DIRS "$ENV{IDF_PATH}/tools/catch" + REQUIRES esp_modem) + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads) + +target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17) +target_compile_definitions(${COMPONENT_LIB} PRIVATE "-DCONFIG_IDF_TARGET_LINUX") diff --git a/esp_modem/test/host_test/main/test_modem.cpp b/esp_modem/test/host_test/main/test_modem.cpp new file mode 100644 index 000000000..fdea59c9f --- /dev/null +++ b/esp_modem/test/host_test/main/test_modem.cpp @@ -0,0 +1,145 @@ +#define CATCH_CONFIG_MAIN // This tells the catch header to generate a main +#include +#include +#include "catch.hpp" +#include "cxx_include/esp_modem_terminal.hpp" +#include "cxx_include/esp_modem_api.hpp" + +using namespace esp_modem; + +class LoopbackTerm : public Terminal { +public: + explicit LoopbackTerm(): loopback_data(), data_len(0) {} + + ~LoopbackTerm() override = default; + + void start() override { + status = status_t::STARTED; + } + + void stop() override { + status = status_t::STOPPED; + } + + int write(uint8_t *data, size_t len) override { + if (len > 2 && (data[len-1] == '\r' || data[len-1] == '+') ) { + std::string command((char*)data, len); + std::string response; + if (command == "ATE1\r" || command == "ATE0\r" || command == "+++") { + response = "OK\r\n"; + } else if (command == "ATO\r") { + response = "ERROR\r\n"; + } else if (command.find("ATD") != std::string::npos) { + response = "CONNECT\r\n"; + } else if (command.find("AT") != std::string::npos) { + response = "OK\r\n"; + } + if (!response.empty()) { + data_len = response.length(); + loopback_data.resize(data_len); + memcpy(&loopback_data[0], &response[0], data_len); + auto ret = std::async(on_data, data_len); + return len; + } + } + loopback_data.resize(data_len + len); + memcpy(&loopback_data[data_len], data, len); + data_len += len; + auto ret = std::async(on_data, data_len); + return len; + } + + int read(uint8_t *data, size_t len) override { + size_t read_len = std::min(data_len, len); + if (read_len) { + memcpy(data, &loopback_data[0], len); + loopback_data.erase(loopback_data.begin(), loopback_data.begin() + read_len); + data_len -= len; + } + return read_len; + } + + void set_data_cb(std::function f) override { + on_data = std::move(f); + } + +private: + enum class status_t { + STARTED, + STOPPED + }; + status_t status; + signal_group signal; + std::vector loopback_data; + size_t data_len; +}; + +TEST_CASE("DTE send/receive command", "[esp_modem]") +{ + auto term = std::make_unique(); + auto dte = std::make_unique(std::move(term)); + + const auto test_command = "Test\n"; + CHECK(term == nullptr); + + dte->set_mode(esp_modem::modem_mode::COMMAND_MODE); + + auto ret = dte->command(test_command, [&](uint8_t *data, size_t len) { + std::string response((char*)data, len); + CHECK(response == test_command); + return command_result::OK; + }, 1000); + CHECK(ret == command_result::OK); +} + +TEST_CASE("DCE commands", "[esp_modem]") +{ + auto term = std::make_unique(); + auto dte = std::make_shared(std::move(term)); + CHECK(term == nullptr); + + esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("APN"); + esp_netif_t netif{}; + auto dce = create_SIM7600_dce(&dce_config, dte, &netif); + CHECK(dce != nullptr); + + const auto test_command = "Test\n"; + auto ret = dce->command(test_command, [&](uint8_t *data, size_t len) { + std::string response((char*)data, len); + CHECK(response == test_command); + return command_result::OK; + }, 1000); + CHECK(ret == command_result::OK); +} + +TEST_CASE("DCE AT commands", "[esp_modem]") +{ + auto term = std::make_unique(); + auto dte = std::make_shared(std::move(term)); + CHECK(term == nullptr); + + esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("APN"); + esp_netif_t netif{}; + auto dce = create_SIM7600_dce(&dce_config, dte, &netif); + CHECK(dce != nullptr); + + CHECK(dce->set_echo(false) == command_result::OK); + CHECK(dce->set_echo(true) == command_result::OK); + CHECK(dce->resume_data_mode() == command_result::FAIL); +} + +TEST_CASE("DCE modes", "[esp_modem]") +{ + auto term = std::make_unique(); + auto dte = std::make_shared(std::move(term)); + CHECK(term == nullptr); + + esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("APN"); + esp_netif_t netif{}; + auto dce = create_SIM7600_dce(&dce_config, dte, &netif); + CHECK(dce != nullptr); + + CHECK(dce->set_mode(esp_modem::modem_mode::COMMAND_MODE) == false); + CHECK(dce->set_mode(esp_modem::modem_mode::DATA_MODE) == true); + CHECK(dce->set_mode(esp_modem::modem_mode::COMMAND_MODE) == true); +} diff --git a/esp_modem/test/host_test/sdkconfig.defaults b/esp_modem/test/host_test/sdkconfig.defaults new file mode 100644 index 000000000..cd841b55e --- /dev/null +++ b/esp_modem/test/host_test/sdkconfig.defaults @@ -0,0 +1,5 @@ +CONFIG_IDF_TARGET="linux" +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_COMPILER_CXX_RTTI=y +CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 +CONFIG_COMPILER_STACK_CHECK_NONE=y diff --git a/esp_modem/test/target/CMakeLists.txt b/esp_modem/test/target/CMakeLists.txt new file mode 100644 index 000000000..951af224e --- /dev/null +++ b/esp_modem/test/target/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS "../..") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(pppd_test) diff --git a/esp_modem/test/target/main/CMakeLists.txt b/esp_modem/test/target/main/CMakeLists.txt new file mode 100644 index 000000000..13d93f496 --- /dev/null +++ b/esp_modem/test/target/main/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register(SRCS "pppd_test.cpp" + "NetworkDCE.cpp" + INCLUDE_DIRS "$ENV{IDF_PATH}/tools/catch" + REQUIRES esp_modem) + +target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17) diff --git a/esp_modem/test/target/main/Kconfig.projbuild b/esp_modem/test/target/main/Kconfig.projbuild new file mode 100644 index 000000000..19e9f86e0 --- /dev/null +++ b/esp_modem/test/target/main/Kconfig.projbuild @@ -0,0 +1,26 @@ +menu "Example Configuration" + + config ESP_WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + + config ESP_WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + config ESP_WIFI_CHANNEL + int "WiFi Channel" + range 1 13 + default 1 + help + WiFi channel (network channel) for the example to use. + + config ESP_MAX_STA_CONN + int "Maximal STA connections" + default 4 + help + Max number of the STA connects to AP. +endmenu diff --git a/esp_modem/test/target/main/NetworkDCE.cpp b/esp_modem/test/target/main/NetworkDCE.cpp new file mode 100644 index 000000000..710798d6b --- /dev/null +++ b/esp_modem/test/target/main/NetworkDCE.cpp @@ -0,0 +1,78 @@ +// +// Created by david on 3/25/21. +// +#include "cxx_include/esp_modem_dte.hpp" +#include "esp_modem_config.h" +#include "cxx_include/esp_modem_api.hpp" +#include "cxx_include/esp_modem_dce_factory.hpp" +#include +#include + +using namespace esp_modem; +using namespace esp_modem::dce_factory; + +class NetModule; +typedef DCE_T NetDCE; + +class NetDCE_Factory: public Factory { +public: + template + static DCE_T* create(const config *cfg, Args&&... args) + { + return build_generic_DCE< /* Object to create */ DCE_T, /* vanilla pointer */ DCE_T *, /* module */ T> + (cfg, std::forward(args)...); + } +}; + +class NetModule: public ModuleIf { +public: + explicit NetModule(std::shared_ptr dte, const esp_modem_dce_config *cfg): + dte(std::move(dte)) {} + + bool setup_data_mode() override + { + return true; + } + + bool set_mode(modem_mode mode) override + { + return true; + } + + static esp_err_t init(esp_netif_t *netif) + { + // configure + esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); + esp_modem_dce_config dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(""); + + // create DTE and minimal network DCE + auto uart_dte = create_uart_dte(&dte_config); + dce = NetDCE_Factory::create(&dce_config, uart_dte, netif); + return dce == nullptr ? ESP_FAIL : ESP_OK; + } + + static void deinit() { delete dce; } + static void start() { dce->set_data(); } + static void stop() { dce->exit_data(); } + +private: + static NetDCE *dce; + std::shared_ptr dte; +}; + +NetDCE *NetModule::dce = nullptr; + +esp_err_t modem_init_network(esp_netif_t *netif) +{ + return NetModule::init(netif); +} + +void modem_start_network() +{ + NetModule::start(); +} + +void modem_stop_network() +{ + NetModule::stop(); +} diff --git a/esp_modem/test/target/main/pppd_test.cpp b/esp_modem/test/target/main/pppd_test.cpp new file mode 100644 index 000000000..b3608c72a --- /dev/null +++ b/esp_modem/test/target/main/pppd_test.cpp @@ -0,0 +1,125 @@ +#include +#include "esp_system.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_netif_ppp.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" + +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +static const char *TAG = "pppd_test"; +static EventGroupHandle_t event_group = NULL; + +static void on_modem_event(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_base == IP_EVENT) { + ESP_LOGD(TAG, "IP event! %d", event_id); + if (event_id == IP_EVENT_PPP_GOT_IP) { + esp_netif_dns_info_t dns_info; + + + ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + esp_netif_t *netif = event->esp_netif; + + ESP_LOGI(TAG, "Modem Connect to PPP Server"); + ESP_LOGI(TAG, "~~~~~~~~~~~~~~"); + ESP_LOGI(TAG, "IP : " IPSTR, IP2STR(&event->ip_info.ip)); + ESP_LOGI(TAG, "Netmask : " IPSTR, IP2STR(&event->ip_info.netmask)); + ESP_LOGI(TAG, "Gateway : " IPSTR, IP2STR(&event->ip_info.gw)); + esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_info); + ESP_LOGI(TAG, "Name Server1: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4)); + esp_netif_get_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_info); + ESP_LOGI(TAG, "Name Server2: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4)); + ESP_LOGI(TAG, "~~~~~~~~~~~~~~"); + + ESP_LOGI(TAG, "GOT ip event!!!"); + xEventGroupSetBits(event_group, 1); + } else if (event_id == IP_EVENT_PPP_LOST_IP) { + ESP_LOGI(TAG, "Modem Disconnect from PPP Server"); + } else if (event_id == IP_EVENT_GOT_IP6) { + ESP_LOGI(TAG, "GOT IPv6 event!"); + ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; + ESP_LOGI(TAG, "Got IPv6 address " IPV6STR, IPV62STR(event->ip6_info.ip)); + } + } +} + +static void on_ppp_changed(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ESP_LOGI(TAG, "PPP state changed event %d", event_id); + if (event_id == NETIF_PPP_ERRORUSER) { + /* User interrupted event from esp-netif */ + esp_netif_t *netif = static_cast(event_data); + ESP_LOGI(TAG, "User interrupted event from netif:%p", netif); + xEventGroupSetBits(event_group, 2); + } +} + + + +esp_err_t modem_init_network(esp_netif_t *netif); +void modem_start_network(); +void modem_stop_network(); + +extern "C" void app_main(void) +{ + + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + event_group = xEventGroupCreate(); + + // init the DTE + esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP(); + esp_netif_t *ppp_netif = esp_netif_new(&ppp_netif_config); + assert(ppp_netif); + esp_netif_ppp_config_t ppp_config = { true, true }; + esp_netif_ppp_set_params(ppp_netif, &ppp_config); + + ESP_ERROR_CHECK(modem_init_network(ppp_netif)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_modem_event, nullptr)); + ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, nullptr)); + + modem_start_network(); + Catch::Session session; + int numFailed = session.run(); + if (numFailed > 0) { + ESP_LOGE(TAG, "Test FAILED!"); + } else { + ESP_LOGI(TAG, "Test passed!"); + } + +} + +TEST_CASE("Connect test", "[esp_modem]") +{ + EventBits_t b = xEventGroupWaitBits(event_group, 1, pdTRUE, pdFALSE, pdMS_TO_TICKS(15000)); + CHECK(b == 1); +} + +TEST_CASE("Disconnection test", "[esp_modem]") +{ + modem_stop_network(); + EventBits_t b = xEventGroupWaitBits(event_group, 2, pdTRUE, pdFALSE, pdMS_TO_TICKS(15000)); + CHECK(b == 2); +} + + +extern "C" { + +static void handle(int nr) +{ + ESP_LOGE(TAG, "Signal handler %d", nr); +} + +_sig_func_ptr signal (int nr, _sig_func_ptr) +{ + return handle; +} + + +}