38#define RA8_MODEM_AT_TAG "MODEM_AT"
44typedef enum : uint16_t {
59typedef enum : uint8_t {
127 while ((i < UINT16_MAX) && (s[i] !=
'\0')) {
152 while (needle[i] !=
'\0') {
153 if (hay[i] != needle[i]) {
180 while ((a[i] !=
'\0') && (b[i] !=
'\0')) {
186 return (uint8_t)((a[i] ==
'\0') && (b[i] ==
'\0'));
208 if ((*used + 1U) < out_len) {
240 if ((line_buf !=
nullptr) && (line_buf_len > 0U)) {
273 if ((expected_response !=
nullptr) && (expected_response[0] !=
'\0') &&
306 if ((capture !=
nullptr) && (capture_len > 0U)) {
332 s_mod.cfg.line_buf[0] = (uint8_t)
'\0';
401 if (
s_mod.urcs[i].used == 0U) {
440 if (line[0] ==
'\0') {
451 if ((expected_response ==
nullptr) || (expected_response[0] ==
'\0') ||
479 if ((
byte == (uint8_t)
'\r') || (
byte == (uint8_t)
'\n')) {
480 if (
s_mod.line_len > 0U) {
481 s_mod.cfg.line_buf[
s_mod.line_len] = (uint8_t)
'\0';
482 *line_out = (
const char*)
s_mod.cfg.line_buf;
487 if ((
s_mod.line_len + 1U) >=
s_mod.cfg.line_buf_len) {
489 s_mod.cfg.line_buf[
s_mod.line_len] = (uint8_t)
'\0';
490 *line_out = (
const char*)
s_mod.cfg.line_buf;
517 while (s[i] !=
'\0') {
524 return s_mod.cfg.io.tx_byte(
s_mod.cfg.io.ctx, (uint8_t)
'\r');
544 if (timeout_ms != 0U) {
547 if (
s_mod.cfg.default_timeout_ms != 0U) {
548 return s_mod.cfg.default_timeout_ms;
557typedef enum : uint8_t {
580 if ((capture ==
nullptr) || (capture_len == 0U)) {
587 while (line[k] !=
'\0') {
617 const char* expected_response,
632 if (*seen_exp == 0U) {
688 const char* line =
nullptr;
690 if (line ==
nullptr) {
724 const char* expected_response,
729 const uint32_t start =
s_mod.cfg.io.now_ms(
s_mod.cfg.io.ctx);
731 uint8_t seen_exp = (uint8_t)((expected_response ==
nullptr) || (expected_response[0] ==
'\0'));
741 .expected_response = expected_response,
743 .capture_len = capture_len,
745 .seen_exp = &seen_exp,
758 const uint32_t elapsed =
s_mod.cfg.io.now_ms(
s_mod.cfg.io.ctx) - start;
759 if (elapsed >= (uint32_t)timeout_ms) {
786 s_mod.urcs[i].used = 0U;
787 s_mod.urcs[i].fn =
nullptr;
788 s_mod.urcs[i].ctx =
nullptr;
830 s_mod.initialized = 1U;
838 if (
s_mod.initialized == 0U) {
858 if (
s_mod.initialized == 0U) {
900 if (
s_mod.urcs[i].used == 0U) {
904 s_mod.urcs[i].fn = fn;
905 s_mod.urcs[i].ctx = ctx;
934 if (
s_mod.urcs[i].used != 0U) {
939 s_mod.urcs[i].prefix[k] = (uint8_t)prefix[k];
942 s_mod.urcs[i].prefix[plen] = (uint8_t)
'\0';
943 s_mod.urcs[i].fn = fn;
944 s_mod.urcs[i].ctx = ctx;
945 s_mod.urcs[i].used = 1U;
954 if (
s_mod.initialized == 0U) {
976 if (
s_mod.initialized == 0U) {
985 const char* line =
nullptr;
987 if (line !=
nullptr) {
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Error Code Definitions for ra8-firmware.
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error(tag, message)
RA8 log error.
ra8_modem_line_kind_t priv_modem_classify(const char *line, const char *cmd_echo, const char *expected_response)
Classify a complete (NUL-terminated) line for the FSM.
uint8_t priv_modem_capture_should_clear(const void *capture, size_t capture_len)
Production carrier of the line-664 capture-init AND-decision.
uint8_t priv_modem_starts_with(const char *hay, const char *needle)
Return 1 if hay begins with needle.
static void internal_accumulate(uint8_t byte, const char **line_out)
Push a single received byte into the line accumulator.
ra8_modem_at_state_t
Internal line-accumulator FSM states.
@ k_ra8_modem_at_state_done
Final result code matched.
@ k_ra8_modem_at_state_idle
No command in flight.
@ k_ra8_modem_at_state_await_echo
Sent command, waiting for echo line.
@ k_ra8_modem_at_state_await_resp
Echo seen (or skipped), draining.
ra8_err_t ra8_modem_at_poll(void)
Pump the RX path without sending a command.
static ra8_modem_at_module_t s_mod
Singleton module state (file scope, NASA Rule 6).
static void internal_clear_urc_table(void)
Reset the URC dispatch table to all-empty.
static ra8_modem_line_action_t internal_pump_one(const ra8_modem_wait_ctx_t *wc)
Pull one byte and process any completed line.
static uint8_t internal_urc_insert(const char *prefix, uint16_t plen, ra8_modem_at_urc_fn_t fn, void *ctx)
Allocate the first free URC slot and copy the prefix into it.
static ra8_err_t internal_validate_init_cfg(const ra8_modem_at_cfg_t *cfg)
Validate every required pointer in cfg's IO block.
static ra8_err_t internal_wait_response(const char *cmd, const char *expected_response, uint16_t timeout_ms, char *capture, size_t capture_len)
Inner wait loop shared by send_cmd and send_cmd_capture.
static void internal_reset_line(void)
Reset the line accumulator for a fresh command cycle.
uint8_t priv_modem_str_eq(const char *a, const char *b)
Compare two NUL-terminated strings for exact equality.
ra8_err_t ra8_modem_at_send_cmd_capture(const char *cmd, char *out_buf, size_t buf_len, uint16_t timeout_ms)
Send an AT command and capture the response payload.
ra8_err_t ra8_modem_at_register_unsolicited_handler(const char *prefix, ra8_modem_at_urc_fn_t fn, void *ctx)
Register a URC (unsolicited result code) handler.
static uint8_t internal_urc_replace(const char *prefix, ra8_modem_at_urc_fn_t fn, void *ctx)
Find an existing URC slot for prefix and update its callback.
static ra8_err_t internal_tx_command(const char *s)
Transmit a NUL-terminated string then "\r".
static uint16_t internal_effective_timeout(uint16_t timeout_ms)
Resolve effective timeout in ms, applying default if 0.
ra8_err_t ra8_modem_at_send_cmd(const char *cmd, const char *expected_response, uint16_t timeout_ms)
Send an AT command and wait for OK/ERROR/expected.
uint8_t priv_modem_reset_line_should_clear(const void *line_buf, uint16_t line_buf_len)
Pure helper for the internal_reset_line line-227 AND.
uint16_t priv_modem_str_len(const char *s)
NUL-terminated string length.
static uint8_t internal_dispatch_urc(const char *line)
Dispatch a URC line to any matching registered handler.
static ra8_modem_line_action_t internal_handle_line(const char *line, ra8_modem_line_kind_t kind, const char *expected_response, uint8_t *seen_exp, char *capture, size_t capture_len, size_t *used)
Drive the response FSM by one classified line.
ra8_modem_line_action_t
Outcome of handling one classified line in internal_wait_response.
@ k_ra8_modem_line_action_continue
Keep waiting.
@ k_ra8_modem_line_action_done_err
Final error observed.
@ k_ra8_modem_line_action_done_ok
Final OK observed.
uint8_t priv_modem_payload_prefix_matches(const char *line, const char *expected_response)
Production carrier of the line-573 payload-prefix AND-decision.
void priv_modem_capture_line(const char *line, char *capture, size_t capture_len, size_t *used)
Append a NUL-terminated line into capture (with newline sep).
static uint8_t internal_classify_final(const char *line, uint8_t *is_error)
Test whether line is a final OK/ERROR result code.
static void internal_append_ch(char *out, size_t out_len, size_t *used, char ch)
Append a single character to out if there is room.
#define RA8_MODEM_AT_TAG
Component log tag.
ra8_err_t ra8_modem_at_init(const ra8_modem_at_cfg_t *cfg)
Bind transport, buffer and timeout policy.
ra8_modem_at_internal_const_t
Internal numeric constants used by the AT driver.
@ k_ra8_modem_at_min_line_buf_bytes
Minimum line buffer length.
Cellular modem AT command/response driver layered on UART.
void(* ra8_modem_at_urc_fn_t)(const char *line, void *ctx)
Unsolicited result-code (URC) handler signature.
@ k_ra8_modem_at_default_timeout_ms
RA8 modem at default timeout ms.
@ k_ra8_modem_at_max_prefix_len
Maximum bytes of a URC prefix (including + and :).
@ k_ra8_modem_at_max_unsolicited
Maximum number of registered URC handlers.
Test-access surface for ra8_modem_at internal helpers (MC/DC).
ra8_modem_line_kind_t
Result of processing a single completed line.
@ k_ra8_modem_line_kind_final_err
RA8 modem line kind final error.
@ k_ra8_modem_line_kind_final_ok
RA8 modem line kind final ok.
@ k_ra8_modem_line_kind_urc
RA8 modem line kind urc.
@ k_ra8_modem_line_kind_payload
RA8 modem line kind payload.
@ k_ra8_modem_line_kind_empty
RA8 modem line kind empty.
@ k_ra8_modem_line_kind_echo
RA8 modem line kind echo.
Configuration handed to ra8_modem_at_init.
uint16_t line_buf_len
Bytes in line_buf (>= 16).
uint8_t * line_buf
Caller-owned line accumulator buffer.
ra8_modem_at_io_t io
Byte transport (must be fully populated).
uint32_t(* now_ms)(void *ctx)
Return monotonic time in milliseconds.
ra8_err_t(* rx_byte)(void *ctx, uint8_t *out_byte)
Try to receive a single byte without blocking.
ra8_err_t(* tx_byte)(void *ctx, uint8_t byte)
Transmit a single byte (blocking).
ra8_modem_at_state_t state
FSM state.
uint16_t line_len
Bytes pending in cfg.line_buf.
ra8_modem_at_urc_slot_t urcs[k_ra8_modem_at_max_unsolicited]
URC table.
ra8_modem_at_cfg_t cfg
Cached caller configuration.
uint8_t initialized
1 after ra8_modem_at_init.
void * ctx
Opaque ctx for fn.
uint8_t used
1 if slot occupied.
ra8_modem_at_urc_fn_t fn
Handler callback.
uint8_t prefix[k_ra8_modem_at_max_prefix_len]
NUL-terminated prefix.
Bundled args + state for one iteration of the wait loop.
char * capture
Optional capture buffer.
size_t capture_len
Capacity of capture.
size_t * used
Bytes already populated in capture.
const char * expected_response
Optional expected prefix.
const char * cmd
Command we sent (for echo).
uint8_t * seen_exp
Sticky: prefix observed yet?