esp_modem: Moved to component folder

This commit is contained in:
David Čermák
2021-05-19 23:00:28 +08:00
committed by David Cermak
parent 61f264f97a
commit 90641c89eb
133 changed files with 21 additions and 21 deletions

View File

@ -0,0 +1,107 @@
// 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_API_HPP_
#define _ESP_MODEM_API_HPP_
#include <memory>
#include "cxx_include/esp_modem_dce.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
struct esp_modem_dte_config;
struct esp_modem_dce_config;
namespace esp_modem {
class DTE;
typedef struct esp_netif_obj esp_netif_t;
/**
* @defgroup ESP_MODEM_INIT_DTE ESP_MODEM Initialization API for DTE
* @brief Create DTE's
*/
/** @addtogroup ESP_MODEM_INIT_DTE
* @{
*/
using dce_config = ::esp_modem_dce_config;
using dte_config = ::esp_modem_dte_config;
/**
* @brief Create UART DTE
* @param config DTE configuration
* @return shared ptr to DTE on success
* nullptr on failure (either due to insufficient memory or wrong dte configuration)
* if exceptions are disabled the API abort()'s on error
*/
std::shared_ptr<DTE> create_uart_dte(const dte_config *config);
/**
* @brief Create VFS DTE
* @param config DTE configuration
* @return shared ptr to DTE on success
* nullptr on failure (either due to insufficient memory or wrong dte configuration)
* if exceptions are disabled the API abort()'s on error
*/
std::shared_ptr<DTE> create_vfs_dte(const dte_config *config);
/**
* @}
*/
/**
* @defgroup ESP_MODEM_INIT_DCE ESP_MODEM Initialization API for DCE
* @brief ESP_MODEM Initialization API for DCE
*/
/** @addtogroup ESP_MODEM_INIT_DCE
* @{
*/
/**
* @brief Create DCE based on SIM7600 module
* @param config DCE configuration
* @param DTE reference to the communicating DTE
* @param netif reference to the network interface
*
* @return unique ptr to the created DCE on success
* nullptr on failure
* if exceptions are disabled the API abort()'s on error
*/
std::unique_ptr<DCE> create_SIM7600_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif);
/**
* @brief Create DCE based on SIM800 module
*/
std::unique_ptr<DCE> create_SIM800_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif);
/**
* @brief Create DCE based on BG96 module
*/
std::unique_ptr<DCE> create_BG96_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif);
/**
* @brief Create generic DCE
*/
std::unique_ptr<DCE> create_generic_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif);
/**
* @}
*/
} // namespace esp_modem
#endif // _ESP_MODEM_API_HPP_

View File

@ -0,0 +1,112 @@
// 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_CMUX_HPP_
#define _ESP_MODEM_CMUX_HPP_
#include "esp_modem_terminal.hpp"
namespace esp_modem {
constexpr size_t max_terms = 2;
/**
* @defgroup ESP_MODEM_CMUX ESP_MODEM CMUX class
* @brief Definition of CMUX terminal
*/
/** @addtogroup ESP_MODEM_CMUX
* @{
*/
/**
* @brief CMUX state machine
*/
enum class cmux_state {
INIT,
HEADER,
PAYLOAD,
FOOTER,
RECOVER,
};
/**
* @brief CMUX terminal abstraction
*
* This class inherits from Terminal class, as it is a Terminal, but is also composed of another Terminal,
* which is used to communicate with the modem, i.e. the original Terminal which has been multiplexed.
*
* @note Implementation of CMUX protocol is experimental
*/
class CMuxInstance;
/**
* @brief CMux class which consumes the original terminal and creates multiple virtual terminals from it.
* This class is not usable applicable as a DTE terminal
*/
class CMux {
public:
explicit CMux(std::unique_ptr<Terminal> t, std::unique_ptr<uint8_t[]> b, size_t buff_size):
term(std::move(t)), buffer_size(buff_size), buffer(std::move(b)), payload_start(nullptr), total_payload_size(0) {}
~CMux() = default;
[[nodiscard]] bool init();
void set_read_cb(int inst, std::function<bool(uint8_t *data, size_t len)> f);
int write(int i, uint8_t *data, size_t len);
private:
std::function<bool(uint8_t *data, size_t len)> read_cb[max_terms];
void data_available(uint8_t *data, size_t len);
void send_sabm(size_t i);
std::unique_ptr<Terminal> term;
cmux_state state;
uint8_t dlci;
uint8_t type;
size_t payload_len;
uint8_t frame_header[6];
size_t frame_header_offset;
size_t buffer_size;
std::unique_ptr<uint8_t[]> buffer;
bool on_cmux(uint8_t *data, size_t len);
static uint8_t fcs_crc(const uint8_t frame[6]);
Lock lock;
int instance;
int sabm_ack;
uint8_t *payload_start;
size_t total_payload_size;
};
/**
* @brief This represents a specific instance of a CMUX virtual terminal. This class also implements Terminal interface
* and as such could be used as a DTE's terminal.
*/
class CMuxInstance: public Terminal {
public:
explicit CMuxInstance(std::shared_ptr<CMux> parent, int i): cmux(std::move(parent)), instance(i) {}
int write(uint8_t *data, size_t len) override { return cmux->write(instance, data, len); }
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override { return cmux->set_read_cb(instance, std::move(f)); }
int read(uint8_t *data, size_t len) override { return 0; }
void start() override { }
void stop() override { }
private:
std::shared_ptr<CMux> cmux;
int instance;
};
/**
* @}
*/
} // namespace esp_modem
#endif // _ESP_MODEM_CMUX_HPP_

View File

@ -0,0 +1,59 @@
// 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_COMMAND_LIBRARY_HPP_
#define _ESP_MODEM_COMMAND_LIBRARY_HPP_
#include "esp_modem_dte.hpp"
#include "esp_modem_dce_module.hpp"
#include "esp_modem_types.hpp"
#include "generate/esp_modem_command_declare.inc"
namespace esp_modem {
namespace dce_commands {
/**
* @defgroup ESP_MODEM_DCE_COMMAND ESP_MODEM DCE command library
* @brief Library of the most useful DCE commands
*/
/** @addtogroup ESP_MODEM_DCE_COMMAND
* @{
*/
/**
* @brief Declaration of all commands is generated from esp_modem_command_declare.inc
*/
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
return_type name(CommandableIf *t, ## __VA_ARGS__);
DECLARE_ALL_COMMAND_APIS(declare name(Commandable *p, ...);)
#undef ESP_MODEM_DECLARE_DCE_COMMAND
/**
* @brief Following commands that are different for some specific modules
*/
command_result get_battery_status_sim7xxx(CommandableIf* t, int& voltage, int &bcs, int &bcl);
command_result power_down_sim7xxx(CommandableIf* t);
command_result power_down_sim8xx(CommandableIf* t);
command_result set_data_mode_sim8xx(CommandableIf* t);
/**
* @}
*/
} // dce_commands
} // esp_modem
#endif //_ESP_MODEM_COMMAND_LIBRARY_HPP_

View File

@ -0,0 +1,114 @@
// 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_DCE_HPP_
#define _ESP_MODEM_DCE_HPP_
#include <utility>
#include "cxx_include/esp_modem_netif.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
namespace esp_modem {
/**
* @defgroup ESP_MODEM_DCE
* @brief Definition of DCE abstraction
*/
/** @addtogroup ESP_MODEM_DCE
* @{
*/
/**
* @brief Helper class responsible for switching modes of the DCE's
*/
class DCE_Mode {
public:
DCE_Mode(): mode(modem_mode::COMMAND_MODE) {}
~DCE_Mode() = default;
bool set(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
modem_mode get();
private:
modem_mode mode;
};
/**
* @brief General DCE class templated on a specific module. It is responsible for all the necessary transactions
* related to switching modes and consequent synergy with aggregated objects of DTE, Netif and a specific Module
*/
template<class SpecificModule>
class DCE_T {
static_assert(std::is_base_of<ModuleIf, SpecificModule>::value, "DCE must be instantiated with Module class only");
public:
explicit DCE_T(const std::shared_ptr<DTE>& dte, std::shared_ptr<SpecificModule> dev, esp_netif_t * netif):
dte(dte), device(std::move(dev)), netif(dte, netif)
{ }
~DCE_T() = default;
/**
* @brief Set data mode!
*/
void set_data() { set_mode(modem_mode::DATA_MODE); }
void exit_data() { set_mode(modem_mode::COMMAND_MODE); }
void set_cmux() { set_mode(modem_mode::CMUX_MODE); }
SpecificModule* get_module() { return device.get(); }
command_result command(const std::string& command, got_line_cb got_line, uint32_t time_ms)
{
return dte->command(command, std::move(got_line), time_ms);
}
bool set_mode(modem_mode m) { return mode.set(dte.get(), device.get(), netif, m); }
protected:
std::shared_ptr<DTE> dte;
std::shared_ptr<SpecificModule> device;
Netif netif;
DCE_Mode mode;
};
/**
* @brief Common abstraction of the modem DCE, specialized by the GenericModule which is a parent class for the supported
* defices and most common modems, as well.
*/
class DCE: public DCE_T<GenericModule> {
public:
using DCE_T<GenericModule>::DCE_T;
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
template <typename ...Agrs> \
return_type name(Agrs&&... args) \
{ \
return device->name(std::forward<Agrs>(args)...); \
}
DECLARE_ALL_COMMAND_APIS(forwards name(...) { device->name(...); } )
#undef ESP_MODEM_DECLARE_DCE_COMMAND
};
/**
* @}
*/
} // esp_modem
#endif // _ESP_MODEM_DCE_HPP_

View File

@ -0,0 +1,249 @@
// 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_DCE_FACTORY_HPP_
#define _ESP_MODEM_DCE_FACTORY_HPP_
/**
* @defgroup ESP_MODEM_DCE_FACTORY
* @brief DCE modem factory
*/
namespace esp_modem::dce_factory {
using config = ::esp_modem_dce_config;
/** @addtogroup ESP_MODEM_DCE_FACTORY
* @{
*/
/**
* @brief Helper class for creating a uder define pointer in a specific way, either as a plain pointer, shared_ptr or unique_ptr
*/
class FactoryHelper {
public:
static std::unique_ptr<PdpContext> create_pdp_context(std::string &apn);
template <typename T, typename Ptr, typename ...Args>
static auto make(Args&&... args) -> typename std::enable_if<std::is_same<Ptr, T*>::value, T*>::type
{
return new T(std::forward<Args>(args)...);
}
template <typename T, typename Ptr, typename ...Args>
static auto make(Args&&... args) -> typename std::enable_if<std::is_same<Ptr, std::shared_ptr<T>>::value, std::shared_ptr<T>>::type
{
return std::make_shared<T>(std::forward<Args>(args)...);
}
template <typename T, typename Ptr = std::unique_ptr<T>, typename ...Args>
static auto make(Args&&... args) -> typename std::enable_if<std::is_same<Ptr, std::unique_ptr<T>>::value, std::unique_ptr<T>>::type
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
};
/**
* @brief Builder class for building a DCE_T<Module> in a specific way, either form a Module object or by default from the DTE and netif
*/
template<typename Module>
class Builder {
static_assert(std::is_base_of<ModuleIf, Module>::value, "Builder must be used only for Module classes");
public:
Builder(std::shared_ptr<DTE> x, esp_netif_t* esp_netif): dte(std::move(x)), device(nullptr), netif(esp_netif)
{
throw_if_false(netif != nullptr, "Null netif");
}
Builder(std::shared_ptr<DTE> dte, esp_netif_t* esp_netif, std::shared_ptr<Module> dev): dte(std::move(dte)), device(std::move(dev)), netif(esp_netif)
{
throw_if_false(netif != nullptr, "Null netif");
}
~Builder()
{
throw_if_false(device == nullptr, "module was captured or created but never used");
}
template<typename Ptr>
auto create_module(const esp_modem_dce_config *config) -> Ptr
{
return FactoryHelper::make<Module, Ptr>(dte, config);
}
template<typename DceT, typename Ptr>
auto create(const esp_modem_dce_config *config) -> Ptr
{
if (dte == nullptr)
return nullptr;
if (device == nullptr) {
device = create_module<decltype(device)>(config);
if (device == nullptr)
return nullptr;
}
return FactoryHelper::make<DceT, Ptr>(std::move(dte), std::move(device), netif);
}
private:
std::shared_ptr<DTE> dte;
std::shared_ptr<Module> device;
esp_netif_t *netif;
};
/**
* @brief Specific modem choice when creating by the Factory
*/
enum class Modem {
GenericModule, /*!< Default generic module with the most common commands */
SIM7600, /*!< Derived from the GenericModule, specifics applied to SIM7600 model */
BG96, /*!< Derived from the GenericModule, specifics applied to BG69 model */
SIM800, /*!< Derived from the GenericModule with specifics applied to SIM800 model */
};
/**
* @brief Factory class for creating virtual DCE objects based on the configuration of the supplied module.
* This could also be used to create a custom module or a DCE_T<module>, provided user app derives from this factory.
*/
class Factory {
public:
explicit Factory(Modem modem): m(modem) {}
/**
* @brief Create a default unique_ptr DCE in a specific way (from the module)
* @tparam Module Specific Module used in this DCE
* @tparam Args Arguments to the builder, i.e. constructor of esp_modem::DCE_T class
* @param cfg DCE configuration structure ::esp_modem_dte_config
* @param args typically a DTE object and a netif handle for PPP network
* @return unique_ptr DCE of the created DCE on success
*/
template <typename Module, typename ...Args>
static std::unique_ptr<DCE> build_unique(const config *cfg, Args&&... args)
{
return build_generic_DCE<Module, DCE, std::unique_ptr<DCE>>(cfg, std::forward<Args>(args)...);
}
/**
* @brief Create a DCE
* @tparam Module Specific Module used in this DCE
* @tparam Args Arguments to the builder, i.e. constructor of esp_modem::DCE_T class
* @param cfg DCE configuration structure ::esp_modem_dte_config
* @param args typically a DTE object and a netif handle for PPP network
* @return DCE pointer the created DCE on success
*/
template <typename Module, typename ...Args>
static DCE* build(const config *cfg, Args&&... args)
{
return build_generic_DCE<Module, DCE>(cfg, std::forward<Args>(args)...);
}
template <typename Module, typename ...Args>
static std::shared_ptr<Module> build_shared_module(const config *cfg, Args&&... args)
{
return build_module_T<Module>(cfg, std::forward<Args>(args)...);
}
template <typename ...Args>
std::shared_ptr<GenericModule> build_shared_module(const config *cfg, Args&&... args)
{
switch (m) {
case Modem::SIM800:
return build_shared_module<SIM800>(cfg, std::forward<Args>(args)...);
case Modem::SIM7600:
return build_shared_module<SIM7600>(cfg, std::forward<Args>(args)...);
case Modem::BG96:
return build_shared_module<BG96>(cfg, std::forward<Args>(args)...);
case Modem::GenericModule:
return build_shared_module<GenericModule>(cfg, std::forward<Args>(args)...);
default:
break;
}
return nullptr;
}
/**
* @brief Create a default unique_ptr DCE generically, with the chosen module derived from the GenericModule
* @tparam Args Arguments to the builder, i.e. constructor of esp_modem::DCE_T class
* @param cfg DCE configuration structure ::esp_modem_dte_config
* @param args typically a DTE object and a netif handle for PPP network
* @return unique_ptr DCE of the created DCE on success
*/
template <typename ...Args>
std::unique_ptr<DCE> build_unique(const config *cfg, Args&&... args)
{
switch (m) {
case Modem::SIM800:
return build_unique<SIM800>(cfg, std::forward<Args>(args)...);
case Modem::SIM7600:
return build_unique<SIM7600>(cfg, std::forward<Args>(args)...);
case Modem::BG96:
return build_unique<BG96>(cfg, std::forward<Args>(args)...);
case Modem::GenericModule:
return build_unique<GenericModule>(cfg, std::forward<Args>(args)...);
default:
break;
}
return nullptr;
}
template <typename ...Args>
DCE* build(const config *cfg, Args&&... args)
{
switch (m) {
case Modem::SIM800:
return build<SIM800>(cfg, std::forward<Args>(args)...);
case Modem::SIM7600:
return build<SIM7600>(cfg, std::forward<Args>(args)...);
case Modem::BG96:
return build<BG96>(cfg, std::forward<Args>(args)...);
case Modem::GenericModule:
return build<GenericModule>(cfg, std::forward<Args>(args)...);
default:
break;
}
return nullptr;
}
private:
Modem m;
protected:
template <typename Module, typename Ptr = std::shared_ptr<Module>, typename ...Args>
static Ptr build_module_T(const config *cfg, Args&&... args)
{
Builder<Module> b(std::forward<Args>(args)...);
return b.template create_module<Ptr>(cfg);
}
template <typename Module, typename Dce = DCE_T<Module>, typename DcePtr = Dce*, typename ...Args>
static DcePtr build_generic_DCE(const config *cfg, Args&&... args)
{
Builder<Module> b(std::forward<Args>(args)...);
return b.template create<Dce, DcePtr>(cfg);
}
};
/**
* @}
*/
} // namespace esp_modem::dce_factory
#endif // _ESP_MODEM_DCE_FACTORY_HPP_

View File

@ -0,0 +1,150 @@
// 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_DCE_MODULE_
#define _ESP_MODEM_DCE_MODULE_
#include <memory>
#include <utility>
#include "generate/esp_modem_command_declare.inc"
#include "cxx_include/esp_modem_command_library.hpp"
#include "cxx_include/esp_modem_types.hpp"
#include "esp_modem_dce_config.h"
namespace esp_modem {
/**
* @defgroup ESP_MODEM_MODULE
* @brief Definition of modules representing specific modem devices
*/
/** @addtogroup ESP_MODEM_MODULE
* @{
*/
enum class command_result;
class DTE;
struct PdpContext;
/**
* @brief This is a basic building block for custom modules as well as for the supported modules in the esp-modem component
* It derives from the ModuleIf.
*/
class GenericModule: public ModuleIf {
public:
/**
* @brief We can construct a generic device with an existent DTE and it's configuration
* The configuration could be either the dce-config struct or just a pdp context
*/
explicit GenericModule(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp):
dte(std::move(dte)), pdp(std::move(pdp)) {}
explicit GenericModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config* config);
/**
* @brief This is a mandatory method for ModuleIf class, which sets up the device
* to be able to connect to the network. This typically consists of setting basic
* communication parameters and setting the PDP (defining logical access point
* to cellular network)
*/
bool setup_data_mode() override
{
if (set_echo(false) != command_result::OK)
return false;
if (set_pdp_context(*pdp) != command_result::OK)
return false;
return true;
}
/**
* @brief This is a mandatory method of ModuleIf class, which defines
* basic commands for switching between DATA, COMMAND and CMUX modes
*/
bool set_mode(modem_mode mode) override
{
if (mode == modem_mode::DATA_MODE) {
if (set_data_mode() != command_result::OK)
return resume_data_mode() == command_result::OK;
return true;
} else if (mode == modem_mode::COMMAND_MODE) {
return set_command_mode() == command_result::OK;
} else if (mode == modem_mode::CMUX_MODE) {
return set_cmux() == command_result::OK;
}
return true;
}
/**
* @brief Additional method providing runtime configuration of PDP context
*/
void configure_pdp_context(std::unique_ptr<PdpContext> new_pdp)
{
pdp = std::move(new_pdp);
}
/**
* @brief Common DCE commands generated from the API AT list
*/
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
virtual return_type name(__VA_ARGS__);
DECLARE_ALL_COMMAND_APIS(virtual return_type name(...); )
#undef ESP_MODEM_DECLARE_DCE_COMMAND
protected:
std::shared_ptr<DTE> dte; /*!< Generic device needs the DTE as a channel talk to the module using AT commands */
std::unique_ptr<PdpContext> pdp; /*!< It also needs a PDP data, const information used for setting up cellular network */
};
// Definitions of other supported modules with some specific commands overwritten
/**
* @brief Specific definition of the SIM7600 module
*/
class SIM7600: public GenericModule {
using GenericModule::GenericModule;
public:
command_result get_module_name(std::string& name) override;
command_result get_battery_status(int& voltage, int &bcs, int &bcl) override;
command_result power_down() override;
};
/**
* @brief Specific definition of the SIM800 module
*/
class SIM800: public GenericModule {
using GenericModule::GenericModule;
public:
command_result get_module_name(std::string& name) override;
command_result power_down() override;
command_result set_data_mode() override;
};
/**
* @brief Specific definition of the BG96 module
*/
class BG96: public GenericModule {
using GenericModule::GenericModule;
public:
command_result get_module_name(std::string& name) override;
};
/**
* @}
*/
} // namespace esp_modem
#endif // _ESP_MODEM_DCE_MODULE_

View File

@ -0,0 +1,121 @@
// 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_DTE_HPP_
#define _ESP_MODEM_DTE_HPP_
#include <memory>
#include <cstddef>
#include <cstdint>
#include <utility>
#include "cxx_include/esp_modem_primitives.hpp"
#include "cxx_include/esp_modem_terminal.hpp"
#include "cxx_include/esp_modem_cmux.hpp"
#include "cxx_include/esp_modem_types.hpp"
struct esp_modem_dte_config;
namespace esp_modem {
/**
* @defgroup ESP_MODEM_DTE
* @brief Definition of DTE and related classes
*/
/** @addtogroup ESP_MODEM_DTE
* @{
*/
/**
* DTE (Data Terminal Equipment) class
*/
class DTE : public CommandableIf {
public:
/**
* @brief Creates a DTE instance from the terminal
* @param config DTE config structure
* @param t unique-ptr to Terminal
*/
explicit DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t);
explicit DTE(std::unique_ptr<Terminal> t);
~DTE() = default;
/**
* @brief Writing to the underlying terminal
* @param data Data pointer to write
* @param len Data len to write
* @return number of bytes written
*/
int write(uint8_t *data, size_t len);
/**
* @brief Reading from the underlying terminal
* @param d Returning the data pointer of the received payload
* @param len Length of the data payload
* @return number of bytes read
*/
int read(uint8_t **d, size_t len);
/**
* @brief Sets read callback with valid data and length
* @param f Function to be called on data available
*/
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f);
/**
* @brief Sets the DTE to desired mode (Command/Data/Cmux)
* @param m Desired operation mode
* @return true on success
*/
[[nodiscard]] bool set_mode(modem_mode m);
/**
* @brief Sends command and provides callback with responding line
* @param command String parameter representing command
* @param got_line Function to be called after line available as a response
* @param time_ms Time in ms to wait for the answer
* @return OK, FAIL, TIMEOUT
*/
command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms) override;
/**
* @brief Sends the command (same as above) but with a specific separator
*/
command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms, char separator) override;
private:
static const size_t GOT_LINE = SignalGroup::bit0; /*!< Bit indicating response available */
[[nodiscard]] bool setup_cmux(); /*!< Internal setup of CMUX mode */
Lock lock{}; /*!< Locks DTE operations */
size_t buffer_size; /*!< Size of available DTE buffer */
size_t consumed; /*!< Indication of already processed portion in DTE buffer */
std::unique_ptr<uint8_t[]> buffer; /*!< DTE buffer */
std::unique_ptr<Terminal> term; /*!< Primary terminal for this DTE */
Terminal *command_term; /*!< Reference to the terminal used for sending commands */
std::unique_ptr<Terminal> other_term; /*!< Secondary terminal for this DTE */
modem_mode mode; /*!< DTE operation mode */
SignalGroup signal; /*!< Event group used to signal request-response operations */
std::function<bool(uint8_t *data, size_t len)> on_data; /*!< on data callback for current terminal */
};
/**
* @}
*/
} // namespace esp_modem
#endif // _ESP_MODEM_DTE_HPP_

View File

@ -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 <string>
#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_

View File

@ -0,0 +1,89 @@
// 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_NETIF_HPP
#define _ESP_MODEM_NETIF_HPP
#include <memory>
#include <cstddef>
#include "esp_netif.h"
#include "cxx_include/esp_modem_primitives.hpp"
namespace esp_modem {
class DTE;
class Netif;
struct ppp_netif_driver {
esp_netif_driver_base_t base;
Netif *ppp;
};
/**
* @defgroup ESP_MODEM_NETIF
* @brief Network interface layer of the esp-modem
*/
/** @addtogroup ESP_MODEM_NETIF
* @{
*/
/**
* @brief Network interface class responsible to glue the esp-netif to the modem's DCE
*/
class Netif {
public:
explicit Netif(std::shared_ptr<DTE> e, esp_netif_t *netif);
~Netif();
/**
* @brief Start the network interface
*/
void start();
/**
* @brief Blocks until the network interface closes
*/
void wait_until_ppp_exits();
/**
* @brief Stop the network interface
*/
void stop();
private:
void receive(uint8_t *data, size_t len);
static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len);
static esp_err_t esp_modem_post_attach(esp_netif_t *esp_netif, void *args);
static void on_ppp_changed(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
std::shared_ptr<DTE> ppp_dte;
esp_netif_t *netif;
struct ppp_netif_driver driver{};
SignalGroup signal;
static const size_t PPP_STARTED = SignalGroup::bit0;
static const size_t PPP_EXIT = SignalGroup::bit1;
};
/**
* @}
*/
} // namespace esp_modem
#endif // _ESP_MODEM_NETIF_HPP

View File

@ -0,0 +1,106 @@
// 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_PRIMITIVES_HPP_
#define _ESP_MODEM_PRIMITIVES_HPP_
#include "esp_modem_exception.hpp"
#if defined(CONFIG_IDF_TARGET_LINUX)
#include <mutex>
#include <thread>
#else
// forward declarations of FreeRTOS primitives
struct QueueDefinition;
typedef void * EventGroupHandle_t;
#endif
namespace esp_modem {
// Forward declaration for both linux/FreeRTOS targets
//
using TaskFunction_t = void (*)(void*);
#if !defined(CONFIG_IDF_TARGET_LINUX)
struct Lock {
using MutexT = QueueDefinition*;
explicit Lock();
~Lock();
void lock();
void unlock();
private:
MutexT m{};
};
using TaskT = void*;
using SignalT = void*;
#else
using Lock = std::mutex;
struct SignalGroupInternal;
using SignalT = std::unique_ptr<SignalGroupInternal>;
using TaskT = std::thread;
static constexpr uint32_t portMAX_DELAY = UINT32_MAX;
#endif
template<class T>
class Scoped {
public:
explicit Scoped(T &l):lock(l) { lock.lock(); }
~Scoped() { lock.unlock(); }
private:
T& lock;
};
class Task {
public:
explicit Task(size_t stack_size, size_t priority, void *task_param, TaskFunction_t task_function);
~Task();
static void Delete();
static void Relinquish();
private:
TaskT task_handle;
};
class SignalGroup {
public:
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;
explicit SignalGroup();
void set(uint32_t bits);
void clear(uint32_t bits);
// waiting for all and clearing if set
bool wait(uint32_t flags, uint32_t time_ms);
bool is_any(uint32_t flags);
// waiting for any bit, not clearing them
bool wait_any(uint32_t flags, uint32_t time_ms);
~SignalGroup();
private:
SignalT event_group;
};
} // namespace esp_modem
#endif // _ESP_MODEM_PRIMITIVES_HPP_

View File

@ -0,0 +1,89 @@
// 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_TERMINAL_HPP_
#define _ESP_MODEM_TERMINAL_HPP_
#include <memory>
#include <functional>
#include <exception>
#include <cstddef>
#include <cstdint>
#include <utility>
#include "esp_err.h"
#include "esp_modem_primitives.hpp"
namespace esp_modem {
/**
* @defgroup ESP_MODEM_TERMINAL
* @brief Definition of an abstract terminal to be attached to DTE class
*/
/** @addtogroup ESP_MODEM_TERMINAL
* @{
*/
/**
* @brief Terminal errors
*/
enum class terminal_error {
BUFFER_OVERFLOW,
CHECKSUM_ERROR,
UNEXPECTED_CONTROL_FLOW,
};
/**
* @brief Terminal interface. All communication interfaces must comply this interface in order to be used as a DTE
*/
class Terminal {
public:
virtual ~Terminal() = default;
void set_error_cb(std::function<void(terminal_error)> f) { on_error = std::move(f); }
virtual void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) { on_data = std::move(f); }
/**
* @brief Writes data to the terminal
* @param data Data pointer
* @param len Data len
* @return length of data written
*/
virtual int write(uint8_t *data, size_t len) = 0;
/**
* @brief Read from the terminal. This function doesn't block, but return all available data.
* @param data Data pointer to store the read payload
* @param len Maximum data len to read
* @return length of data actually read
*/
virtual int read(uint8_t *data, size_t len) = 0;
virtual void start() = 0;
virtual void stop() = 0;
protected:
std::function<bool(uint8_t *data, size_t len)> on_data;
std::function<void(terminal_error)> on_error;
};
/**
* @}
*/
} // namespace esp_modem
#endif // _ESP_MODEM_TERMINAL_HPP_

View File

@ -0,0 +1,107 @@
// 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_TYPES_HPP_
#define _ESP_MODEM_TYPES_HPP_
#include <functional>
#include <string>
#include <cstddef>
#include <cstdint>
namespace esp_modem {
/**
* @defgroup ESP_MODEM_TYPES
* @brief Basic type definitions used in esp-modem
*/
/** @addtogroup ESP_MODEM_TYPES
* @{
*/
/**
* @brief Modem working mode
*/
enum class modem_mode {
UNDEF,
COMMAND_MODE, /*!< Command mode -- the modem is supposed to send AT commands in this mode */
DATA_MODE, /*!< Data mode -- the modem communicates with network interface on PPP protocol */
CMUX_MODE /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
* assigning one solely to command interface and the other to the data mode */
};
/**
* @brief Module command result
*/
enum class command_result {
OK, /*!< The command completed successfully */
FAIL, /*!< The command explicitly failed */
TIMEOUT /*!< The device didn't respond in the specified timeline */
};
typedef std::function<command_result(uint8_t *data, size_t len)> got_line_cb;
/**
* @brief PDP context used for configuring and setting the data mode up
*/
struct PdpContext {
explicit PdpContext(std::string apn) : apn(std::move(apn)) {}
size_t context_id = 1;
std::string protocol_type = "IP";
std::string apn;
};
/**
* @brief Interface for classes eligible to send AT commands (Modules, DCEs, DTEs)
*/
class CommandableIf {
public:
/**
* @brief Sends custom AT command
* @param command Command to be sent
* @param got_line callback if a line received
* @param time_ms timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
virtual command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator) = 0;
virtual command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms) = 0;
};
/**
* @brief Interface for classes implementing a module for the modem
*/
class ModuleIf {
public:
/**
* @brief Sets the data mode up (provides the necessary configuration to connect to the cellular network
* @return true on success
*/
virtual bool setup_data_mode() = 0;
/**
* @brief Sets the operation mode
* @param mode Desired mode
* @return true on success
*/
virtual bool set_mode(modem_mode mode) = 0;
};
/**
* @}
*/
} // namespace esp_modem
#endif // _ESP_MODEM_TYPES_HPP_