Skip to content

Commit 8be01c5

Browse files
committed
app: Implement sm_at_host_lock() for multi part responses
Implement sm_at_host_lock() that can be used to block URC handling and RX processing while outputting multi-part responses using rsp_send(), rsp_send_to() and data_send(). Signed-off-by: Seppo Takalo <seppo.takalo@nordicsemi.no>
1 parent f1c4c19 commit 8be01c5

4 files changed

Lines changed: 72 additions & 11 deletions

File tree

app/src/sm_at_host.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ struct sm_at_host_ctx {
152152

153153
/* AT command reception state (for cmd_rx_handler) */
154154
bool inside_quotes;
155-
bool executing;
155+
atomic_t executing_lock;
156156
size_t at_cmd_len;
157157
size_t echo_len;
158158
uint8_t prev_character;
@@ -442,7 +442,7 @@ static void at_pipe_rx_work_fn(struct k_work *work)
442442
}
443443

444444
/* Do not parse more commands, if we are still executing */
445-
if (ctx->executing) {
445+
if (atomic_get(&ctx->executing_lock) > 0) {
446446
return;
447447
}
448448

@@ -1168,7 +1168,8 @@ static void cmd_send(struct sm_at_host_ctx *ctx, uint8_t *buf, size_t cmd_length
11681168
}
11691169

11701170
/* Block CMDs & URCs while command is executing, even if idle timer triggers */
1171-
ctx->executing = true;
1171+
atomic_inc(&ctx->executing_lock);
1172+
11721173
/* Send to modem.
11731174
* Reserve space for CRLF in the response buffer.
11741175
*/
@@ -1178,12 +1179,12 @@ static void cmd_send(struct sm_at_host_ctx *ctx, uint8_t *buf, size_t cmd_length
11781179
if (err == -AT_COMMAND_CONTINUE_RET) {
11791180
return;
11801181
} else if (err == -SILENT_AT_COMMAND_RET) {
1181-
ctx->executing = false;
1182+
atomic_dec(&ctx->executing_lock);
11821183
return;
11831184
} else if (err < 0) {
11841185
LOG_ERR("AT command failed: %d", err);
11851186
rsp_send_error();
1186-
ctx->executing = false;
1187+
atomic_dec(&ctx->executing_lock);
11871188
return;
11881189
} else if (err > 0) {
11891190
LOG_ERR("AT command error (%d), type: %d: value: %d", err,
@@ -1204,22 +1205,36 @@ static void cmd_send(struct sm_at_host_ctx *ctx, uint8_t *buf, size_t cmd_length
12041205
LOG_ERR("AT command response failed: %d", err);
12051206
}
12061207
}
1207-
ctx->executing = false;
1208+
atomic_dec(&ctx->executing_lock);
12081209
}
12091210

12101211
void sm_at_host_cmd_done(struct sm_at_host_ctx *ctx)
12111212
{
12121213
if (!sm_at_ctx_check(ctx)) {
12131214
return;
12141215
}
1215-
ctx->executing = false;
12161216

12171217
/* Continue processing received data, if there is any */
1218-
if (is_open(ctx)) {
1218+
if (atomic_dec(&ctx->executing_lock) == 1 && is_open(ctx)) {
1219+
sm_at_host_event_notify(ctx, SM_EVENT_URC);
12191220
k_work_submit_to_queue(&sm_work_q, &ctx->rx_work);
12201221
}
12211222
}
12221223

1224+
void sm_at_host_lock_ctx(struct sm_at_host_ctx *ctx)
1225+
{
1226+
if (!sm_at_ctx_check(ctx)) {
1227+
LOG_ERR("invalid context");
1228+
return;
1229+
}
1230+
1231+
if (is_idle(ctx)) {
1232+
flush_pipe_urcs(ctx);
1233+
}
1234+
1235+
atomic_inc(&ctx->executing_lock);
1236+
}
1237+
12231238
static size_t cmd_rx_handler(struct sm_at_host_ctx *ctx, uint8_t c)
12241239
{
12251240
bool send = false;
@@ -1618,7 +1633,8 @@ bool in_at_mode_pipe(struct modem_pipe *pipe)
16181633
bool is_idle_ctx(struct sm_at_host_ctx *ctx)
16191634
{
16201635
return (sm_at_ctx_check(ctx) && in_at_mode_ctx(ctx) &&
1621-
ctx->executing == false && k_timer_remaining_ticks(&ctx->idle_timer) == 0);
1636+
atomic_get(&ctx->executing_lock) == 0 &&
1637+
k_timer_remaining_ticks(&ctx->idle_timer) == 0);
16221638
}
16231639

16241640
bool is_idle_pipe(struct modem_pipe *pipe)
@@ -1885,7 +1901,7 @@ static struct sm_at_host_ctx *sm_at_host_create(struct modem_pipe *pipe)
18851901
ctx = sm_at_host_get_urc_ctx();
18861902
if (ctx && atomic_ptr_cas(&ctx->pipe, NULL, pipe)) {
18871903
LOG_DBG("Reusing first AT host instance %p for pipe %p", (void *)ctx, (void *)pipe);
1888-
ctx->executing = false;
1904+
atomic_set(&ctx->executing_lock, 0);
18891905
modem_pipe_attach(pipe, at_pipe_event_handler, ctx);
18901906
if (urcs_queued) {
18911907
sm_at_host_event_notify(ctx, SM_EVENT_URC);

app/src/sm_at_host.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,40 @@ static inline void sm_at_host_cmd_done_pipe(struct modem_pipe *pipe)
342342
struct modem_pipe * : sm_at_host_cmd_done_pipe \
343343
)(X)
344344

345+
/** Lock the AT host context from processing or URC handling.
346+
*
347+
* This blocks RX handling and URC sending until
348+
* sm_at_host_cmd_done() is called.
349+
* This is used for sending multiple messages in a row without
350+
* interleaving URCs or other command responses.
351+
*
352+
* AT context have internal refcount to allow nested locks.
353+
*
354+
* Only safe to call from sm_work_q.
355+
*/
356+
void sm_at_host_lock_ctx(struct sm_at_host_ctx *ctx);
357+
358+
/** See sm_at_host_lock_ctx()
359+
*/
360+
static inline void sm_at_host_lock_pipe(struct modem_pipe *pipe)
361+
{
362+
return sm_at_host_lock_ctx(sm_at_host_get_ctx_from(pipe));
363+
}
364+
365+
/** See sm_at_host_lock_ctx()
366+
*/
367+
#define sm_at_host_lock(X) \
368+
_Generic((X), \
369+
struct sm_at_host_ctx * : sm_at_host_lock_ctx, \
370+
struct modem_pipe * : sm_at_host_lock_pipe \
371+
)(X)
372+
373+
/** Unlock the AT host context from processing or URC handling.
374+
*
375+
* Alias for sm_at_host_cmd_done() to improve readability when the intention is to block/unblock.
376+
*/
377+
#define sm_at_host_unlock(x) cmd_done(x)
378+
345379
/**
346380
* @brief Submit a work to be executed when the current AT command processing is done.
347381
*

app/src/sm_at_mqtt.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ static int handle_mqtt_publish_evt(struct mqtt_client *const c, const struct mqt
9696
/* MQTT client does not track the packet identifiers, so MQTT_QOS_2_EXACTLY_ONCE
9797
* promise is not kept. This deviates from MQTT v3.1.1.
9898
*/
99+
sm_at_host_lock(ctx.pipe);
99100
urc_send_to(ctx.pipe, "\r\n#XMQTTMSG: %d,%d\r\n",
100101
evt->param.publish.message.topic.topic.size,
101102
evt->param.publish.message.payload.len);
@@ -111,7 +112,7 @@ static int handle_mqtt_publish_evt(struct mqtt_client *const c, const struct mqt
111112
} while (ret >= 0 && size_read < evt->param.publish.message.payload.len);
112113
data_send(ctx.pipe, "\r\n", 2);
113114

114-
115+
sm_at_host_unlock(ctx.pipe);
115116
return 0;
116117
}
117118

app/src/sm_at_socket.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ static void auto_reception(struct sm_socket *sock)
242242
return;
243243
}
244244

245+
sm_at_host_lock(sock->pipe);
246+
245247
if (sock->connected || sock->type == SOCK_RAW) {
246248
err = do_recv(sock, 0, MSG_DONTWAIT,
247249
sock->async_poll.adr_hex ? AT_SOCKET_MODE_HEX
@@ -255,12 +257,14 @@ static void auto_reception(struct sm_socket *sock)
255257
}
256258
if (err) {
257259
LOG_ERR("auto_reception() error: %d", err);
260+
sm_at_host_unlock(sock->pipe);
258261
return;
259262
}
260263
if (!in_datamode(sock->pipe)) {
261264
/* <CR><LF> after the data. */
262265
rsp_send_to(sock->pipe, "\r\n");
263266
}
267+
sm_at_host_unlock(sock->pipe);
264268
}
265269

266270
static int update_poll_events(struct sm_socket *sock, uint8_t events, bool update_xapoll)
@@ -1126,19 +1130,22 @@ static int do_recv(struct sm_socket *sock, int timeout, int flags,
11261130
if (ret == 0) {
11271131
LOG_WRN("zsock_recv() return 0");
11281132
} else {
1133+
sm_at_host_lock(sock->pipe);
11291134
if (!in_datamode(sock->pipe)) {
11301135
rsp_send_to(sock->pipe, "\r\n#XRECV: %d,%d,%d\r\n", sock->fd, mode, ret);
11311136
}
11321137

11331138
if (mode == AT_SOCKET_MODE_HEX) {
11341139
ret = data_send_hex(sock, sm_data_buf, ret);
11351140
if (ret) {
1141+
sm_at_host_unlock(sock->pipe);
11361142
return ret;
11371143
}
11381144
} else {
11391145
data_send(sock->pipe, sm_data_buf, ret);
11401146
}
11411147
ret = 0;
1148+
sm_at_host_unlock(sock->pipe);
11421149

11431150
update_poll_events(sock, ZSOCK_POLLIN, true);
11441151
}
@@ -1237,6 +1244,7 @@ static int do_recvfrom(struct sm_socket *sock, int timeout, int flags,
12371244
if (ret == 0) {
12381245
LOG_WRN("zsock_recvfrom() return 0");
12391246
} else {
1247+
sm_at_host_lock(sock->pipe);
12401248
if (!in_datamode(sock->pipe)) {
12411249
char peer_addr[INET6_ADDRSTRLEN] = {0};
12421250
uint16_t peer_port = 0;
@@ -1249,11 +1257,13 @@ static int do_recvfrom(struct sm_socket *sock, int timeout, int flags,
12491257
if (mode == AT_SOCKET_MODE_HEX) {
12501258
ret = data_send_hex(sock, sm_data_buf, ret);
12511259
if (ret) {
1260+
sm_at_host_unlock(sock->pipe);
12521261
return ret;
12531262
}
12541263
} else {
12551264
data_send(sock->pipe, sm_data_buf, ret);
12561265
}
1266+
sm_at_host_unlock(sock->pipe);
12571267

12581268
update_poll_events(sock, ZSOCK_POLLIN, true);
12591269
}

0 commit comments

Comments
 (0)