zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.34k stars 6.33k forks source link

MODEM subsystem: Parse fixed-length messages that are not terminated by a delimiter #66515

Open mayankmahajan-nxp opened 8 months ago

mayankmahajan-nxp commented 8 months ago

Is your enhancement proposal related to a problem? Please describe. Yes, we need to receive UBLOX messages from UBX-NEO-M8 GNSS device, and UBLOX messages are not terminated by a delimiter, but rather they are fixed length in nature.

Describe the solution you'd like The CHAT in MODEM could include an option for parsing fixed length messages. Ex: UBLOX messages are identified by starting two bytes: 0xb5 and 0x62; After this "match" we could ask CHAT to return the next n bytes (say 8, as in the case of UBX-ACK-ACK message).

Describe alternatives you've considered Apart from this I couldn't think of anything.

@bjarki-trackunit

mayankmahajan-nxp commented 8 months ago

PFA the format of a UBX frame. The fourth parameter determines the length of the current message and the message is ended by a checksum. Screenshot from 2023-12-14 14-26-52

bjarki-andreasen commented 8 months ago

Hi. The chat module is designed specifically for char based messages, which are terminated and split by common chars. The UBX frames do not fit this description.

The solution I propose is to create a new modem module, modem_ubx which like modem_cmux, is designed specifically for said protocol :)

The API for the module would include the following:

struct modem_ubx_message {
        uint8_t message_class;
        uint8_t message_id;
        uint8_t payload;
        size_t payload_size;
};

typedef void (*modem_ubx_frame_handler)(const struct modem_ubx_frame *frame);

struct modem_ubx_config {
        modem_ubx_frame_handler frame_handler;
        modem_ubx_event_handler event_handler;
        uint8_t receive_buf;
        size_t receive_buf_size;
        uint8_t transmit_buf;
        size_t transmit_buf_size;
};

int modem_ubx_init(struct modem_ubx *ubx, const struct modem_ubx_config *config);
int modem_ubx_attach(struct modem_ubx *ubx, modem_pipe *pipe);
void modem_ubx_release(struct modem_ubx *ubx);
int modem_ubx_transmit_async(struct modem_ubx *ubx, const struct modem_ubx_message *message);
int modem_ubx_transmit(struct modem_ubx *ubx, const struct modem_ubx_message *message);

This keeps the separation of responsibilities clear between the modules and keeps them simpler :)

mayankmahajan-nxp commented 8 months ago

@bjarki-trackunit Thank you for the response.

Hi. The chat module is designed specifically for char based messages, which are terminated and split by common chars. The UBX frames do not fit this description.

Would it be possible to add support for ubx-like messages in modem_chat? Because we don't need a specific module like modem_ubx. We need a generic module (like modem_chat) that would allow processing of ubx-like messages, i.e. messages whose 'start' is indicated by a unique sub-string and then 'length' is indicated in the message itself. Hence, we need a module like modem_chat to match the unique 'start' in the incoming byte stream and then return the next 'n' bytes from there (that would be our desired message).

Sorry, but I couldn't understand why we would need to create a modem module like modem_cmux. Could you please help me understand this? I thought we would need to create a modem module like modem_chat, because modem_chat determines which type of messages could be processed/parsed from the incoming byte stream.

bjarki-andreasen commented 8 months ago

@mayankmahajan-nxp modem_chat does not determine the type of byte stream, rather it works exclusively with one type of byte stream, ascii encoded text. Just like CMUX works with CMUX frames, and PPP works with PPP frames. If you have a byte stream containing UBX frames, you need a module specifically for said byte stream.

If you are sending both text and UBX frames on the same pipe, you need to switch between the appropriates module depending on what you are sending/receiving ATM. This is how the cellular modem drivers work, they start sending text (AT commands) using the modem_chat module, then switch it out for CMUX, then later PPP connected through CMUX. See the *_release() and *_attach() calls in the modem_cellular.c driver to see examples of this :)