mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-24 07:47:30 +02:00
fix(modem): More error handling in cmux protocol
Add error path to all CMUX protocol potential issues, checks for consistency and add recovery.
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -86,9 +86,30 @@ public:
|
||||
*/
|
||||
int write(int i, uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Recovers the protocol
|
||||
*
|
||||
* This restarts the CMUX state machine, which could have been in a wrong state due to communication
|
||||
* issue on a lower layer.
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool recover();
|
||||
|
||||
private:
|
||||
|
||||
enum class protocol_mismatch_reason {
|
||||
MISSED_LEAD_SOF,
|
||||
MISSED_TRAIL_SOF,
|
||||
WRONG_CRC,
|
||||
UNEXPECTED_HEADER,
|
||||
UNEXPECTED_DATA,
|
||||
READ_BEHIND_BUFFER,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
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 */
|
||||
bool data_available(uint8_t *data, size_t len); /*!< Called when valid data available (returns false on unexpected data format) */
|
||||
void send_sabm(size_t i); /*!< Sending initial SABM */
|
||||
void send_disconnect(size_t i); /*!< Sending closing request for each virtual or control terminal */
|
||||
bool on_cmux_data(uint8_t *data, size_t len); /*!< Called from terminal layer when raw CMUX protocol data available */
|
||||
@ -105,6 +126,7 @@ private:
|
||||
bool on_header(CMuxFrame &frame);
|
||||
bool on_payload(CMuxFrame &frame);
|
||||
bool on_footer(CMuxFrame &frame);
|
||||
void recover_protocol(protocol_mismatch_reason reason);
|
||||
|
||||
std::function<bool(uint8_t *data, size_t len)> read_cb[MAX_TERMINALS_NUM]; /*!< Function pointers to read callbacks */
|
||||
std::shared_ptr<Terminal> term; /*!< The original terminal */
|
||||
|
@ -84,6 +84,11 @@ public:
|
||||
return mode.set(dte.get(), device.get(), netif, m);
|
||||
}
|
||||
|
||||
bool recover()
|
||||
{
|
||||
return dte->recover();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<DTE> dte;
|
||||
std::shared_ptr<SpecificModule> device;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -115,6 +115,13 @@ public:
|
||||
*/
|
||||
command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms, char separator) override;
|
||||
|
||||
/**
|
||||
* @brief Allows this DTE to recover from a generic connection issue
|
||||
*
|
||||
* @return true if success
|
||||
*/
|
||||
bool recover();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Allows for locking the DTE
|
||||
@ -130,6 +137,7 @@ protected:
|
||||
friend class Scoped<DTE>; /*!< Declaring "Scoped<DTE> lock(dte)" locks this instance */
|
||||
private:
|
||||
|
||||
void handle_error(terminal_error err); /*!< Performs internal error handling */
|
||||
[[nodiscard]] bool setup_cmux(); /*!< Internal setup of CMUX mode */
|
||||
[[nodiscard]] bool exit_cmux(); /*!< Exit of CMUX mode and cleanup */
|
||||
void exit_cmux_internal(); /*!< Cleanup CMUX */
|
||||
@ -141,6 +149,7 @@ private:
|
||||
std::shared_ptr<Terminal> secondary_term; /*!< Secondary terminal for this DTE */
|
||||
modem_mode mode; /*!< DTE operation mode */
|
||||
std::function<bool(uint8_t *data, size_t len)> on_data; /*!< on data callback for current terminal */
|
||||
std::function<void(terminal_error err)> user_error_cb; /*!< user callback on error event from attached terminals */
|
||||
|
||||
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
|
||||
/**
|
||||
@ -189,7 +198,10 @@ private:
|
||||
command_result result{}; /*!< Command return code */
|
||||
SignalGroup signal; /*!< Event group used to signal request-response operations */
|
||||
bool process_line(uint8_t *data, size_t consumed, size_t len); /*!< Lets the processing callback handle one line (processing unit) */
|
||||
bool wait_for_line(uint32_t time_ms); /*!< Waiting for command processing */
|
||||
bool wait_for_line(uint32_t time_ms) /*!< Waiting for command processing */
|
||||
{
|
||||
return signal.wait_any(command_cb::GOT_LINE, time_ms);
|
||||
}
|
||||
void set(got_line_cb l, char s = '\n') /*!< Sets the command callback atomically */
|
||||
{
|
||||
Scoped<Lock> lock(line_lock);
|
||||
@ -197,6 +209,11 @@ private:
|
||||
// if we set the line callback, we have to reset the signal and the result
|
||||
signal.clear(GOT_LINE);
|
||||
result = command_result::TIMEOUT;
|
||||
} else {
|
||||
// if we clear the line callback, we check consistency (since we've locked the line processing)
|
||||
if (signal.is_any(command_cb::GOT_LINE) && result == command_result::TIMEOUT) {
|
||||
ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
}
|
||||
got_line = std::move(l);
|
||||
separator = s;
|
||||
|
Reference in New Issue
Block a user