mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-16 12:02:11 +02:00
feat(esp_modem): Add support to CMUX exit
Closes https://github.com/espressif/esp-protocols/issues/37
This commit is contained in:
@ -64,6 +64,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] bool init();
|
[[nodiscard]] bool init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Closes CMux protocol and ejects attached terminal and buffer
|
||||||
|
* @return nullptr on failure
|
||||||
|
* tuple of the original terminal and buffer on success
|
||||||
|
*/
|
||||||
|
std::tuple<std::unique_ptr<Terminal>, std::unique_ptr<uint8_t[]>, size_t> deinit_and_eject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets read callback for the appropriate terminal
|
* @brief Sets read callback for the appropriate terminal
|
||||||
* @param inst Index of the terminal
|
* @param inst Index of the terminal
|
||||||
@ -84,6 +91,9 @@ private:
|
|||||||
static uint8_t fcs_crc(const uint8_t frame[6]); /*!< Utility to calculate FCS CRC */
|
static uint8_t fcs_crc(const uint8_t frame[6]); /*!< Utility to calculate FCS CRC */
|
||||||
void data_available(uint8_t *data, size_t len); /*!< Called when valid data available */
|
void data_available(uint8_t *data, size_t len); /*!< Called when valid data available */
|
||||||
void send_sabm(size_t i); /*!< Sending initial SABM */
|
void send_sabm(size_t i); /*!< Sending initial SABM */
|
||||||
|
void send_disc(size_t i); /*!< Sending closing request for each virtual terminal */
|
||||||
|
void close_down(); /*!< Close up the control terminla (term=0) */
|
||||||
|
bool exit_cmux_protocol(); /*!< Sequence of exit of all virtual terms and control term */
|
||||||
bool on_cmux(uint8_t *data, size_t len); /*!< Called from terminal layer when raw CMUX protocol data available */
|
bool on_cmux(uint8_t *data, size_t len); /*!< Called from terminal layer when raw CMUX protocol data available */
|
||||||
|
|
||||||
struct CMuxFrame; /*!< Forward declare the Frame struct, used in protocol decoders */
|
struct CMuxFrame; /*!< Forward declare the Frame struct, used in protocol decoders */
|
||||||
@ -147,6 +157,7 @@ public:
|
|||||||
}
|
}
|
||||||
void start() override { }
|
void start() override { }
|
||||||
void stop() override { }
|
void stop() override { }
|
||||||
|
CMux* get_cmux() { return cmux.get(); }
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<CMux> cmux;
|
std::shared_ptr<CMux> cmux;
|
||||||
size_t instance;
|
size_t instance;
|
||||||
|
@ -98,6 +98,7 @@ private:
|
|||||||
static const size_t GOT_LINE = SignalGroup::bit0; /*!< Bit indicating response available */
|
static const size_t GOT_LINE = SignalGroup::bit0; /*!< Bit indicating response available */
|
||||||
|
|
||||||
[[nodiscard]] bool setup_cmux(); /*!< Internal setup of CMUX mode */
|
[[nodiscard]] bool setup_cmux(); /*!< Internal setup of CMUX mode */
|
||||||
|
[[nodiscard]] bool exit_cmux(); /*!< Exit of CMUX mode */
|
||||||
|
|
||||||
Lock lock{}; /*!< Locks DTE operations */
|
Lock lock{}; /*!< Locks DTE operations */
|
||||||
size_t buffer_size; /*!< Size of available DTE buffer */
|
size_t buffer_size; /*!< Size of available DTE buffer */
|
||||||
|
@ -78,6 +78,25 @@ uint8_t CMux::fcs_crc(const uint8_t frame[6])
|
|||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMux::close_down()
|
||||||
|
{
|
||||||
|
uint8_t frame[] = {
|
||||||
|
SOF_MARKER, 0x3, 0xFF, 0x5, 0xC3, 0x1, 0xE7, SOF_MARKER };
|
||||||
|
term->write(frame, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMux::send_disc(size_t i)
|
||||||
|
{
|
||||||
|
uint8_t frame[6];
|
||||||
|
frame[0] = SOF_MARKER;
|
||||||
|
frame[1] = (i << 2) | 0x3;
|
||||||
|
frame[2] = FT_DISC | PF;
|
||||||
|
frame[3] = 1;
|
||||||
|
frame[4] = 0xFF - fcs_crc(frame);
|
||||||
|
frame[5] = SOF_MARKER;
|
||||||
|
term->write(frame, 6);
|
||||||
|
}
|
||||||
|
|
||||||
void CMux::send_sabm(size_t i)
|
void CMux::send_sabm(size_t i)
|
||||||
{
|
{
|
||||||
uint8_t frame[6];
|
uint8_t frame[6];
|
||||||
@ -305,6 +324,31 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CMux::exit_cmux_protocol()
|
||||||
|
{
|
||||||
|
sabm_ack = -1;
|
||||||
|
for (size_t i = 1; i < 3; i++) {
|
||||||
|
int timeout = 0;
|
||||||
|
send_disc(i);
|
||||||
|
while (true) {
|
||||||
|
usleep(10'000);
|
||||||
|
Scoped<Lock> l(lock);
|
||||||
|
if (sabm_ack == i) {
|
||||||
|
sabm_ack = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (timeout++ > 100) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close_down();
|
||||||
|
usleep(100'000);
|
||||||
|
term->set_read_cb(nullptr);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool CMux::init()
|
bool CMux::init()
|
||||||
{
|
{
|
||||||
frame_header_offset = 0;
|
frame_header_offset = 0;
|
||||||
@ -370,3 +414,11 @@ void CMux::set_read_cb(int inst, std::function<bool(uint8_t *, size_t)> f)
|
|||||||
read_cb[inst] = std::move(f);
|
read_cb[inst] = std::move(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<std::unique_ptr<Terminal>, std::unique_ptr<uint8_t[]>, size_t> esp_modem::CMux::deinit_and_eject()
|
||||||
|
{
|
||||||
|
if (exit_cmux_protocol()) {
|
||||||
|
return std::make_tuple(std::move(term), std::move(buffer), buffer_size);
|
||||||
|
}
|
||||||
|
return std::tuple(nullptr, nullptr, 0);
|
||||||
|
}
|
||||||
|
@ -33,6 +33,15 @@ bool DCE_Mode::set(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m)
|
|||||||
if (mode == modem_mode::COMMAND_MODE) {
|
if (mode == modem_mode::COMMAND_MODE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (mode == modem_mode::CMUX_MODE) {
|
||||||
|
netif.stop();
|
||||||
|
netif.wait_until_ppp_exits();
|
||||||
|
if (!dte->set_mode(modem_mode::COMMAND_MODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mode = m;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
netif.stop();
|
netif.stop();
|
||||||
SignalGroup signal;
|
SignalGroup signal;
|
||||||
dte->set_read_cb([&](uint8_t *data, size_t len) -> bool {
|
dte->set_read_cb([&](uint8_t *data, size_t len) -> bool {
|
||||||
@ -90,7 +99,17 @@ bool DCE_Mode::set(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m)
|
|||||||
if (!dte->set_mode(modem_mode::CMUX_MODE)) {
|
if (!dte->set_mode(modem_mode::CMUX_MODE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mode = modem_mode::COMMAND_MODE;
|
mode = modem_mode::CMUX_MODE;
|
||||||
|
if (!device->setup_data_mode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!device->set_mode(modem_mode::DATA_MODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!dte->set_mode(modem_mode::DATA_MODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
netif.start();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -69,6 +69,23 @@ command_result DTE::command(const std::string &cmd, got_line_cb got_line, uint32
|
|||||||
return command(cmd, got_line, time_ms, '\n');
|
return command(cmd, got_line, time_ms, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DTE::exit_cmux()
|
||||||
|
{
|
||||||
|
auto cmux_term = static_cast<CMuxInstance*>(term.get())->get_cmux();
|
||||||
|
auto ejected = cmux_term->deinit_and_eject();
|
||||||
|
if (ejected == std::tuple(nullptr, nullptr, 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// deinit succeeded -> swap the internal terminals with those ejected from cmux
|
||||||
|
auto term_orig = std::move(term);
|
||||||
|
auto other_term_orig = std::move(other_term);
|
||||||
|
term = std::move(std::get<0>(ejected));
|
||||||
|
buffer = std::move(std::get<1>(ejected));
|
||||||
|
buffer_size = std::get<2>(ejected);
|
||||||
|
command_term = term.get(); // use command terminal as previously
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DTE::setup_cmux()
|
bool DTE::setup_cmux()
|
||||||
{
|
{
|
||||||
auto original_term = std::move(term);
|
auto original_term = std::move(term);
|
||||||
@ -94,7 +111,16 @@ bool DTE::setup_cmux()
|
|||||||
|
|
||||||
bool DTE::set_mode(modem_mode m)
|
bool DTE::set_mode(modem_mode m)
|
||||||
{
|
{
|
||||||
mode = m;
|
if (mode == modem_mode::CMUX_MODE && m == modem_mode::COMMAND_MODE) {
|
||||||
|
if (exit_cmux()) {
|
||||||
|
mode = m;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mode != modem_mode::CMUX_MODE) { // keep CMUX internally, it's CMD+PPP
|
||||||
|
mode = m;
|
||||||
|
}
|
||||||
if (m == modem_mode::DATA_MODE) {
|
if (m == modem_mode::DATA_MODE) {
|
||||||
term->set_read_cb(on_data);
|
term->set_read_cb(on_data);
|
||||||
if (other_term) { // if we have the other terminal, let's use it for commands
|
if (other_term) { // if we have the other terminal, let's use it for commands
|
||||||
|
Reference in New Issue
Block a user