diff --git a/components/esp_modem/examples/pppos_client/main/Kconfig.projbuild b/components/esp_modem/examples/pppos_client/main/Kconfig.projbuild index 2da54ba01..65243a0b5 100644 --- a/components/esp_modem/examples/pppos_client/main/Kconfig.projbuild +++ b/components/esp_modem/examples/pppos_client/main/Kconfig.projbuild @@ -29,10 +29,18 @@ menu "Example Configuration" bool "BG96" help Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module. + config EXAMPLE_MODEM_DEVICE_SIM7000 + bool "SIM7000" + help + SIM7000 is a Multi-Band LTE-FDD and GSM/GPRS/EDGE module. + config EXAMPLE_MODEM_DEVICE_SIM7070 + bool "SIM7070" + help + SIM7070 is Multi-Band CAT M and NB IoT module. config EXAMPLE_MODEM_DEVICE_SIM7600 bool "SIM7600" help - SIM7600 is Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module + SIM7600 is a Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module. endchoice config EXAMPLE_MODEM_PPP_APN @@ -159,6 +167,21 @@ menu "Example Configuration" default 1024 help Buffer size of UART RX buffer. + + choice EXAMPLE_FLOW_CONTROL + bool "Set preferred modem control flow" + default EXAMPLE_FLOW_CONTROL_NONE + help + Set the modem's preferred control flow + + config EXAMPLE_FLOW_CONTROL_NONE + bool "No control flow" + config EXAMPLE_FLOW_CONTROL_SW + bool "SW control flow" + config EXAMPLE_FLOW_CONTROL_HW + bool "HW control flow" + endchoice + endmenu endmenu diff --git a/components/esp_modem/examples/pppos_client/main/pppos_client_main.c b/components/esp_modem/examples/pppos_client/main/pppos_client_main.c index a7dac04a6..99f669efe 100644 --- a/components/esp_modem/examples/pppos_client/main/pppos_client_main.c +++ b/components/esp_modem/examples/pppos_client/main/pppos_client_main.c @@ -21,6 +21,15 @@ #include "esp_log.h" #include "sdkconfig.h" + +#if defined(CONFIG_EXAMPLE_FLOW_CONTROL_NONE) +#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_NONE +#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_SW) +#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_SW +#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_HW) +#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_HW +#endif + #define BROKER_URL "mqtt://mqtt.eclipseprojects.io" static const char *TAG = "pppos_example"; @@ -161,6 +170,7 @@ void app_main(void) dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN; dte_config.uart_config.rts_io_num = CONFIG_EXAMPLE_MODEM_UART_RTS_PIN; dte_config.uart_config.cts_io_num = CONFIG_EXAMPLE_MODEM_UART_CTS_PIN; + dte_config.uart_config.flow_control = EXAMPLE_FLOW_CONTROL; dte_config.uart_config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE; dte_config.uart_config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE; dte_config.uart_config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE; @@ -174,6 +184,12 @@ void app_main(void) #elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM800 == 1 ESP_LOGI(TAG, "Initializing esp_modem for the SIM800 module..."); esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM800, &dte_config, &dce_config, esp_netif); +#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7000 == 1 + ESP_LOGI(TAG, "Initializing esp_modem for the SIM7000 module..."); + esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM7000, &dte_config, &dce_config, esp_netif); +#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070 == 1 + ESP_LOGI(TAG, "Initializing esp_modem for the SIM7070 module..."); + esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM7070, &dte_config, &dce_config, esp_netif); #elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1 ESP_LOGI(TAG, "Initializing esp_modem for the SIM7600 module..."); esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM7600, &dte_config, &dce_config, esp_netif); @@ -181,6 +197,15 @@ void app_main(void) ESP_LOGI(TAG, "Initializing esp_modem for a generic module..."); esp_modem_dce_t *dce = esp_modem_new(&dte_config, &dce_config, esp_netif); #endif + assert(dce); + if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) { + esp_err_t err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control. + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set the set_flow_control mode"); + return; + } + ESP_LOGI(TAG, "HW set_flow_control OK"); + } #elif defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB) while (1) { @@ -189,13 +214,14 @@ void app_main(void) const esp_modem_dte_config_t dte_usb_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config); ESP_LOGI(TAG, "Waiting for USB device connection..."); esp_modem_dce_t *dce = esp_modem_new_dev_usb(ESP_MODEM_DCE_BG96, &dte_usb_config, &dce_config, esp_netif); + assert(dce); esp_modem_set_error_cb(dce, usb_terminal_error_handler); vTaskDelay(pdMS_TO_TICKS(1000)); // Although the DTE should be ready after USB enumeration, sometimes it fails to respond without this delay #else #error Invalid serial connection to modem. #endif - assert(dce); + xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT); /* Run the modem demo app */ @@ -214,7 +240,7 @@ void app_main(void) int rssi, ber; esp_err_t err = esp_modem_get_signal_quality(dce, &rssi, &ber); if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d", err); + ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err)); return; } ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber); diff --git a/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/CMakeLists.txt b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/CMakeLists.txt new file mode 100644 index 000000000..86e1fa24a --- /dev/null +++ b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register(SRCS "SIM7070_gnss.cpp" + INCLUDE_DIRS "." + PRIV_REQUIRES esp_modem) + +set_target_properties(${COMPONENT_LIB} PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS ON +) diff --git a/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/SIM7070_gnss.cpp b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/SIM7070_gnss.cpp new file mode 100644 index 000000000..b60f01b96 --- /dev/null +++ b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/SIM7070_gnss.cpp @@ -0,0 +1,341 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +// +// Created on: 23.08.2022 +// Author: franz + +#include +#include +#include +#include "sdkconfig.h" +#include "cxx_include/esp_modem_dte.hpp" +#include "cxx_include/esp_modem_dce.hpp" +#include "esp_modem_config.h" +#include "cxx_include/esp_modem_api.hpp" +#include "cxx_include/esp_modem_command_library_utils.hpp" +#include "esp_log.h" +#include "SIM7070_gnss.hpp" + +constexpr auto const TAG = "SIM7070_gnss"; + + +namespace gnss_factory { +using namespace esp_modem; +using namespace dce_factory; + +class LocalFactory: public Factory { + using DCE_gnss_ret = std::unique_ptr; // this custom Factory manufactures only unique_ptr's +public: + static DCE_gnss_ret create(const dce_config *config, std::shared_ptr dte, esp_netif_t *netif) + { + return Factory::build_generic_DCE + (config, std::move(dte), netif); + } +}; + +} // namespace gnss_factory + +/** + * @brief Helper create method which employs the DCE factory for creating DCE objects templated by a custom module + * @return unique pointer of the resultant DCE + */ +std::unique_ptr create_SIM7070_GNSS_dce(const esp_modem::dce_config *config, + std::shared_ptr dte, + esp_netif_t *netif) +{ + return gnss_factory::LocalFactory::create(config, std::move(dte), netif); +} + +esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::CommandableIf *t, esp_modem_gps_t &gps) +{ + + ESP_LOGV(TAG, "%s", __func__ ); + std::string str_out; + auto ret = esp_modem::dce_commands::generic_get_string(t, "AT+CGNSINF\r", str_out); + if (ret != esp_modem::command_result::OK) { + return ret; + } + std::string_view out(str_out); + + + constexpr std::string_view pattern = "+CGNSINF: "; + if (out.find(pattern) == std::string_view::npos) { + return esp_modem::command_result::FAIL; + } + /** + * Parsing +CGNSINF: + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * , + * + */ + out = out.substr(pattern.size()); + int pos = 0; + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //GNSS run status + int GNSS_run_status; + if (std::from_chars(out.data(), out.data() + pos, GNSS_run_status).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + gps.run = (gps_run_t)GNSS_run_status; + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //Fix status + { + std::string_view fix_status = out.substr(0, pos); + if (fix_status.length() > 1) { + int Fix_status; + if (std::from_chars(out.data(), out.data() + pos, Fix_status).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + gps.fix = (gps_fix_t)Fix_status; + } else { + gps.fix = GPS_FIX_INVALID; + } + } //clean up Fix status + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //UTC date & Time + { + std::string_view UTC_date_and_Time = out.substr(0, pos); + if (UTC_date_and_Time.length() > 1) { + if (std::from_chars(out.data() + 0, out.data() + 4, gps.date.year).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + if (std::from_chars(out.data() + 4, out.data() + 6, gps.date.month).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + if (std::from_chars(out.data() + 6, out.data() + 8, gps.date.day).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + if (std::from_chars(out.data() + 8, out.data() + 10, gps.tim.hour).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + if (std::from_chars(out.data() + 10, out.data() + 12, gps.tim.minute).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + if (std::from_chars(out.data() + 12, out.data() + 14, gps.tim.second).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + if (std::from_chars(out.data() + 15, out.data() + 18, gps.tim.thousand).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + } else { + gps.date.year = 0; + gps.date.month = 0; + gps.date.day = 0; + gps.tim.hour = 0; + gps.tim.minute = 0; + gps.tim.second = 0; + gps.tim.thousand = 0; + } + + } //clean up UTC date & Time + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //Latitude + { + std::string_view Latitude = out.substr(0, pos); + if (Latitude.length() > 1) { + gps.latitude = std::stof(std::string(out.substr(0, pos))); + } else { + gps.latitude = 0; + } + } //clean up Latitude + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //Longitude + { + std::string_view Longitude = out.substr(0, pos); + if (Longitude.length() > 1) { + gps.longitude = std::stof(std::string(out.substr(0, pos))); + } else { + gps.longitude = 0; + } + } //clean up Longitude + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //Altitude + { + std::string_view Altitude = out.substr(0, pos); + if (Altitude.length() > 1) { + gps.altitude = std::stof(std::string(out.substr(0, pos))); + } else { + gps.altitude = 0; + } + } //clean up Altitude + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //Speed Over Ground Km/hour + { + std::string_view gps_speed = out.substr(0, pos); + if (gps_speed.length() > 1) { + gps.speed = std::stof(std::string(gps_speed)); + } else { + gps.speed = 0; + } + } //clean up gps_speed + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //Course Over Ground degrees + { + std::string_view gps_cog = out.substr(0, pos); + if (gps_cog.length() > 1) { + gps.cog = std::stof(std::string(gps_cog)); + } else { + gps.cog = 0; + } + } //clean up gps_cog + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + // Fix Mode + { + std::string_view FixModesubstr = out.substr(0, pos); + if (FixModesubstr.length() > 1) { + int Fix_Mode; + if (std::from_chars(out.data(), out.data() + pos, Fix_Mode).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + gps.fix_mode = (gps_fix_mode_t)Fix_Mode; + } else { + gps.fix_mode = GPS_MODE_INVALID; + } + } //clean up Fix Mode + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //HDOP + { + std::string_view HDOP = out.substr(0, pos); + if (HDOP.length() > 1) { + gps.dop_h = std::stof(std::string(HDOP)); + } else { + gps.dop_h = 0; + } + } //clean up HDOP + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //PDOP + { + std::string_view PDOP = out.substr(0, pos); + if (PDOP.length() > 1) { + gps.dop_p = std::stof(std::string(PDOP)); + } else { + gps.dop_p = 0; + } + } //clean up PDOP + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //VDOP + { + std::string_view VDOP = out.substr(0, pos); + if (VDOP.length() > 1) { + gps.dop_v = std::stof(std::string(VDOP)); + } else { + gps.dop_v = 0; + } + } //clean up VDOP + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //sats_in_view + { + std::string_view sats_in_view = out.substr(0, pos); + if (sats_in_view.length() > 1) { + if (std::from_chars(out.data(), out.data() + pos, gps.sats_in_view).ec == std::errc::invalid_argument) { + return esp_modem::command_result::FAIL; + } + } else { + gps.sats_in_view = 0; + } + } //clean up sats_in_view + + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + out = out.substr(pos + 1); + if ((pos = out.find(',')) == std::string::npos) { + return esp_modem::command_result::FAIL; + } + //HPA + { + std::string_view HPA = out.substr(0, pos); + if (HPA.length() > 1) { + gps.hpa = std::stof(std::string(HPA)); + } else { + gps.hpa = 0; + } + } //clean up HPA + out = out.substr(pos + 1); + //VPA + { + std::string_view VPA = out.substr(0, pos); + if (VPA.length() > 1) { + gps.vpa = std::stof(std::string(VPA)); + } else { + gps.vpa = 0; + } + } //clean up VPA + + return esp_modem::command_result::OK; +} + +esp_modem::command_result SIM7070_gnss::get_gnss_information_sim70xx(esp_modem_gps_t &gps) +{ + return get_gnss_information_sim70xx_lib(dte.get(), gps); +} + +esp_modem::command_result DCE_gnss::get_gnss_information_sim70xx(esp_modem_gps_t &gps) +{ + return device->get_gnss_information_sim70xx(gps); +} diff --git a/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/SIM7070_gnss.hpp b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/SIM7070_gnss.hpp new file mode 100644 index 000000000..8ca99dc0d --- /dev/null +++ b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/SIM7070_gnss.hpp @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +// +// Created on: 23.08.2022 +// Author: franz + + +#pragma once + + +#include "cxx_include/esp_modem_dce_factory.hpp" +#include "cxx_include/esp_modem_dce_module.hpp" +#include "nmea_parser.h" + +/** + * @brief Definition of a custom SIM7070 class with GNSS capabilities. + * This inherits from the official esp-modem's SIM7070 device which contains all common library methods. + * On top of that, the SIM7070_gnss adds reading GNSS information, which is implemented in a private component. + */ +class SIM7070_gnss: public esp_modem::SIM7070 { + using SIM7070::SIM7070; +public: + esp_modem::command_result get_gnss_information_sim70xx(esp_modem_gps_t &gps); +}; + +/** + * @brief DCE for the SIM7070_gnss. Here we've got to forward the general commands, aa well as the GNSS one. + */ +class DCE_gnss : public esp_modem::DCE_T { +public: + + using DCE_T::DCE_T; +#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \ + template \ + esp_modem::return_type name(Agrs&&... args) \ + { \ + return device->name(std::forward(args)...); \ + } + + DECLARE_ALL_COMMAND_APIS(forwards name(...) + { + device->name(...); + } ) + +#undef ESP_MODEM_DECLARE_DCE_COMMAND + + esp_modem::command_result get_gnss_information_sim70xx(esp_modem_gps_t &gps); + +}; + + +/** + * @brief Helper create method which employs the customized DCE factory for building DCE_gnss objects + * @return unique pointer of the specific DCE + */ +std::unique_ptr create_SIM7070_GNSS_dce(const esp_modem::dce_config *config, + std::shared_ptr dte, + esp_netif_t *netif); diff --git a/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/nmea_parser.h b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/nmea_parser.h new file mode 100644 index 000000000..a0c59a714 --- /dev/null +++ b/components/esp_modem/examples/simple_cmux_client/components/SIM7070_gnss/nmea_parser.h @@ -0,0 +1,133 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + * + * Origin: https://github.com/espressif/esp-idf/blob/master/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.h + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + +#define GPS_MAX_SATELLITES_IN_USE (12) +#define GPS_MAX_SATELLITES_IN_VIEW (16) + + + +/** + * @brief GPS fix type + * + */ +typedef enum { + GPS_FIX_INVALID, /*!< Not fixed */ + GPS_FIX_GPS, /*!< GPS */ + GPS_FIX_DGPS, /*!< Differential GPS */ +} gps_fix_t; + +/** + * @brief GPS run type + * + */ +typedef enum { + GPS_RUN_INVALID, /*!< Not fixed */ + GPS_RUN_GPS, /*!< GPS */ +} gps_run_t; + +/** + * @brief GPS fix mode + * + */ +typedef enum { + GPS_MODE_INVALID, /*!< Not fixed */ + GPS_MODE_2D, /*!< 2D GPS */ + GPS_MODE_3D /*!< 3D GPS */ +} gps_fix_mode_t; + +/** + * @brief GPS satellite information + * + */ +typedef struct { + uint8_t num; /*!< Satellite number */ + uint8_t elevation; /*!< Satellite elevation */ + uint16_t azimuth; /*!< Satellite azimuth */ + uint8_t snr; /*!< Satellite signal noise ratio */ +} gps_satellite_t; + +/** + * @brief GPS time + * + */ +typedef struct { + uint8_t hour; /*!< Hour */ + uint8_t minute; /*!< Minute */ + uint8_t second; /*!< Second */ + uint16_t thousand; /*!< Thousand */ +} gps_time_t; + +/** + * @brief GPS date + * + */ +typedef struct { + uint8_t day; /*!< Day (start from 1) */ + uint8_t month; /*!< Month (start from 1) */ + uint16_t year; /*!< Year (start from 2000) */ +} gps_date_t; + +/** + * @brief NMEA Statement + * + */ +typedef enum { + STATEMENT_UNKNOWN = 0, /*!< Unknown statement */ + STATEMENT_GGA, /*!< GGA */ + STATEMENT_GSA, /*!< GSA */ + STATEMENT_RMC, /*!< RMC */ + STATEMENT_GSV, /*!< GSV */ + STATEMENT_GLL, /*!< GLL */ + STATEMENT_VTG /*!< VTG */ +} nmea_statement_t; + +/** + * @brief GPS object + * + */ +struct esp_modem_gps { + float latitude; /*!< Latitude (degrees) */ + float longitude; /*!< Longitude (degrees) */ + float altitude; /*!< Altitude (meters) */ + gps_run_t run; /*!< run status */ + gps_fix_t fix; /*!< Fix status */ + uint8_t sats_in_use; /*!< Number of satellites in use */ + gps_time_t tim; /*!< time in UTC */ + gps_fix_mode_t fix_mode; /*!< Fix mode */ + float dop_h; /*!< Horizontal dilution of precision */ + float dop_p; /*!< Position dilution of precision */ + float dop_v; /*!< Vertical dilution of precision */ + uint8_t sats_in_view; /*!< Number of satellites in view */ + gps_date_t date; /*!< Fix date */ + float speed; /*!< Ground speed, unit: m/s */ + float cog; /*!< Course over ground */ + float hpa; /*!< Horizontal Position Accuracy */ + float vpa; /*!< Vertical Position Accuracy */ +}; + +typedef struct esp_modem_gps esp_modem_gps_t; + +/** + * @brief NMEA Parser Event ID + * + */ +typedef enum { + GPS_UPDATE, /*!< GPS information has been updated */ + GPS_UNKNOWN /*!< Unknown statements detected */ +} nmea_event_id_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_modem/examples/simple_cmux_client/main/Kconfig.projbuild b/components/esp_modem/examples/simple_cmux_client/main/Kconfig.projbuild index 16c0da168..bf733a9ee 100644 --- a/components/esp_modem/examples/simple_cmux_client/main/Kconfig.projbuild +++ b/components/esp_modem/examples/simple_cmux_client/main/Kconfig.projbuild @@ -22,6 +22,10 @@ menu "Example Configuration" bool "SIM7070" help SIM7070 is Multi-Band CAT M and NB IoT module. + config EXAMPLE_MODEM_DEVICE_SIM7070_GNSS + bool "SIM7070_GNSS" + help + SIM7070 is Multi-Band CAT M and NB IoT module with Support for GNSS Location API config EXAMPLE_MODEM_DEVICE_SIM7600 bool "SIM7600" help @@ -119,4 +123,10 @@ menu "Example Configuration" help Close the multiplexed mode at the end of the example and rollback to command mode. + config BROKER_URI + string "Broker URL" + default "mqtt://test.mosquitto.org" + help + URL of an mqtt broker which this example connects to. + endmenu diff --git a/components/esp_modem/examples/simple_cmux_client/main/simple_cmux_client_main.cpp b/components/esp_modem/examples/simple_cmux_client/main/simple_cmux_client_main.cpp index 0f3f4b760..df9229547 100644 --- a/components/esp_modem/examples/simple_cmux_client/main/simple_cmux_client_main.cpp +++ b/components/esp_modem/examples/simple_cmux_client/main/simple_cmux_client_main.cpp @@ -25,6 +25,7 @@ #include "esp_vfs_dev.h" // For optional VFS support #include "esp_https_ota.h" // For potential OTA configuration #include "vfs_resource/vfs_create.hpp" +#include "SIM7070_gnss.hpp" #if defined(CONFIG_EXAMPLE_FLOW_CONTROL_NONE) #define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_NONE @@ -34,7 +35,7 @@ #define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_HW #endif -#define BROKER_URL "mqtt://mqtt.eclipseprojects.io" +#define BROKER_URL CONFIG_BROKER_URI using namespace esp_modem; @@ -87,15 +88,17 @@ extern "C" void app_main(void) assert(esp_netif); #if CONFIG_EXAMPLE_MODEM_DEVICE_BG96 == 1 - std::unique_ptr dce = create_BG96_dce(&dce_config, dte, esp_netif); + auto dce = create_BG96_dce(&dce_config, dte, esp_netif); #elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM800 == 1 - std::unique_ptr dce = create_SIM800_dce(&dce_config, dte, esp_netif); + auto dce = create_SIM800_dce(&dce_config, dte, esp_netif); #elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7000 == 1 - std::unique_ptr dce = create_SIM7000_dce(&dce_config, dte, esp_netif); + auto dce = create_SIM7000_dce(&dce_config, dte, esp_netif); #elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070 == 1 - std::unique_ptr dce = create_SIM7070_dce(&dce_config, dte, esp_netif); + auto dce = create_SIM7070_dce(&dce_config, dte, esp_netif); +#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070_GNSS == 1 + auto dce = create_SIM7070_GNSS_dce(&dce_config, dte, esp_netif); #elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1 - std::unique_ptr dce = create_SIM7600_dce(&dce_config, dte, esp_netif); + auto dce = create_SIM7600_dce(&dce_config, dte, esp_netif); #else #error "Unsupported device" #endif @@ -135,6 +138,12 @@ extern "C" void app_main(void) } std::cout << "Operator name:" << str << std::endl; +#if CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070_GNSS == 1 + if (dce->set_gnss_power_mode(1) == esp_modem::command_result::OK) { + std::cout << "Modem set_gnss_power_mode: OK" << std::endl; + } +#endif + /* Try to connect to the network and publish an mqtt topic */ ESPEventHandlerSync event_handler(loop); event_handler.listen_to(ESPEvent(IP_EVENT, ESPEventID(ESP_EVENT_ANY_ID))); @@ -184,6 +193,43 @@ extern "C" void app_main(void) std::cout << "Modem IMSI number:" << str << std::endl; } + +#if CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070_GNSS == 1 + esp_modem_gps_t gps; + + for (int i = 0; i < 200; ++i) { + if (dce->get_gnss_information_sim70xx(gps) == esp_modem::command_result::OK) { + ESP_LOGI(TAG, "gps.run %i", + gps.run); + ESP_LOGI(TAG, "gps.fix %i", + gps.fix); + ESP_LOGI(TAG, "gps.date.year %i gps.date.month %i gps.date.day %i", + gps.date.year, gps.date.month, gps.date.day); + ESP_LOGI(TAG, "gps.tim.hour %i gps.tim.minute %i gps.tim.second %i gps.tim.thousand %i", + gps.tim.hour, gps.tim.minute, gps.tim.second, gps.tim.thousand); + ESP_LOGI(TAG, "gps.latitude %f gps.longitude %f ", + gps.latitude, gps.longitude ); + ESP_LOGI(TAG, "gps.altitude %f", + gps.altitude); + ESP_LOGI(TAG, "gps.speed %f", + gps.speed); + ESP_LOGI(TAG, "gps.cog %f", + gps.cog); + ESP_LOGI(TAG, "gps.fix_mode %i", + gps.fix_mode); + ESP_LOGI(TAG, "gps.dop_h %f gps.dop_p %f gps.dop_v %f ", + gps.dop_h, gps.dop_p, gps.dop_v ); + ESP_LOGI(TAG, "gps.sats_in_view %i", + gps.sats_in_view); + ESP_LOGI(TAG, "gps.hpa %f gps.vpa %f", + gps.hpa, gps.vpa); + } + vTaskDelay(pdMS_TO_TICKS(1000)); //Wait + + } +#endif // CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070_GNSS + + #if CONFIG_EXAMPLE_PERFORM_OTA == 1 esp_http_client_config_t config = { }; config.skip_cert_common_name_check = true; diff --git a/components/esp_modem/examples/simple_cmux_client/sdkconfig.defaults b/components/esp_modem/examples/simple_cmux_client/sdkconfig.defaults index 8f54fe475..dab94ca82 100644 --- a/components/esp_modem/examples/simple_cmux_client/sdkconfig.defaults +++ b/components/esp_modem/examples/simple_cmux_client/sdkconfig.defaults @@ -9,4 +9,4 @@ CONFIG_PARTITION_TABLE_TWO_OTA=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF=y CONFIG_NEWLIB_STDIN_LINE_ENDING_LF=y -CONFIG_MAIN_TASK_STACK_SIZE=8192 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 diff --git a/components/esp_modem/idf_component.yml b/components/esp_modem/idf_component.yml index ae17e474f..ef5bbe906 100644 --- a/components/esp_modem/idf_component.yml +++ b/components/esp_modem/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.1.24" +version: "0.1.25" description: esp modem url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem dependencies: diff --git a/components/esp_modem/include/cxx_include/esp_modem_command_library_utils.hpp b/components/esp_modem/include/cxx_include/esp_modem_command_library_utils.hpp new file mode 100644 index 000000000..b47c150d8 --- /dev/null +++ b/components/esp_modem/include/cxx_include/esp_modem_command_library_utils.hpp @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +namespace esp_modem::dce_commands { + +/** + * @brief Generic command that passes on supplied pass_phrase, and fails on fail_phrase + * @param t Any "Command-able" class that implements "command()" method + * @param command Command to issue + * @param pass_phrase Pattern to find in replies to complete the command successfully + * @param fail_phrase If this pattern found the command fails immediately + * @param timeout_ms Command timeout in ms + * @return Generic command return type (OK, FAIL, TIMEOUT) + */ +command_result generic_command(CommandableIf *t, const std::string &command, + const std::string &pass_phrase, + const std::string &fail_phrase, uint32_t timeout_ms); + +/** + * @brief Utility command to send command and return reply (after DCE says OK) + * @param t Anything that is "command-able" + * @param command Command to issue + * @param output String to return + * @param timeout_ms + * @param timeout_ms Command timeout in ms + * @return Generic command return type (OK, FAIL, TIMEOUT) + */ +command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms = 500); + +/** + * @brief Generic command that passes on "OK" and fails on "ERROR" + * @param t Anything that is "command-able" + * @param command Command to issue + * @param timeout + * @param timeout_ms Command timeout in ms + * @return Generic command return type (OK, FAIL, TIMEOUT) + */ +command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout_ms = 500); + +} // esp_modem::dce_commands diff --git a/components/esp_modem/src/esp_modem_command_library.cpp b/components/esp_modem/src/esp_modem_command_library.cpp index 18d74532f..2a638e982 100644 --- a/components/esp_modem/src/esp_modem_command_library.cpp +++ b/components/esp_modem/src/esp_modem_command_library.cpp @@ -10,15 +10,16 @@ #include "cxx_include/esp_modem_dte.hpp" #include "cxx_include/esp_modem_dce_module.hpp" #include "cxx_include/esp_modem_command_library.hpp" +#include "cxx_include/esp_modem_command_library_utils.hpp" namespace esp_modem::dce_commands { static const char *TAG = "command_lib"; -command_result generic_command(CommandableIf *t, const std::string &command, - const std::list &pass_phrase, - const std::list &fail_phrase, - uint32_t timeout_ms) +static command_result generic_command(CommandableIf *t, const std::string &command, + const std::list &pass_phrase, + const std::list &fail_phrase, + uint32_t timeout_ms) { ESP_LOGD(TAG, "%s command %s\n", __func__, command.c_str()); return t->command(command, [&](uint8_t *data, size_t len) { @@ -40,9 +41,9 @@ command_result generic_command(CommandableIf *t, const std::string &command, } -static inline command_result generic_command(CommandableIf *t, const std::string &command, - const std::string &pass_phrase, - const std::string &fail_phrase, uint32_t timeout_ms) +command_result generic_command(CommandableIf *t, const std::string &command, + const std::string &pass_phrase, + const std::string &fail_phrase, uint32_t timeout_ms) { ESP_LOGV(TAG, "%s", __func__ ); const auto pass = std::list({pass_phrase}); @@ -50,7 +51,7 @@ static inline command_result generic_command(CommandableIf *t, const std::string return generic_command(t, command, pass, fail, timeout_ms); } -static inline command_result generic_get_string(CommandableIf *t, const std::string &command, std::string_view &output, uint32_t timeout_ms = 500) +static command_result generic_get_string(CommandableIf *t, const std::string &command, std::string_view &output, uint32_t timeout_ms = 500) { ESP_LOGV(TAG, "%s", __func__ ); return t->command(command, [&](uint8_t *data, size_t len) { @@ -77,7 +78,7 @@ static inline command_result generic_get_string(CommandableIf *t, const std::str }, timeout_ms); } -static inline command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms = 500) +command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms) { ESP_LOGV(TAG, "%s", __func__ ); std::string_view out; @@ -89,10 +90,10 @@ static inline command_result generic_get_string(CommandableIf *t, const std::str } -static inline command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout = 500) +command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout_ms) { ESP_LOGV(TAG, "%s", __func__ ); - return generic_command(t, command, "OK", "ERROR", timeout); + return generic_command(t, command, "OK", "ERROR", timeout_ms); } command_result sync(CommandableIf *t)