Skip to content

Commit 3908faa

Browse files
committed
Draft of mbox callback handler
1 parent 9fa48fe commit 3908faa

File tree

4 files changed

+208
-40
lines changed

4 files changed

+208
-40
lines changed

include/zephyr/ipc/icmsg.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@ extern "C" {
2929
enum icmsg_state {
3030
// TODO: rename as it was before
3131
ICMSG_STATE_UNINITIALIZED, /**< Instance is not initialized yet. Sending will fail. Opening allowed. */
32-
ICMSG_STATE_INITIALIZING, /**< Instance is initializing - waiting for remote to acknowledge. Sending will fail. Opening allowed, session will change and remote may or may not get unbound() callback. */
33-
ICMSG_STATE_CONNECTED, /**< Instance is connected. Sending will be successful. Opening allowed, session will change and remote will get unbound() callback. */
34-
ICMSG_STATE_DISCONNECTED, /**< Instance was connected, but get disconnected. Sending will be silently discarded, because it there may be old sends. Opening allowed. */
32+
ICMSG_STATE_INITIALIZING_SID_DISABLED, /**< Instance is initializing - waiting for remote to acknowledge. Sending will fail. Opening allowed, session will change and remote may or may not get unbound() callback. */
33+
ICMSG_STATE_INITIALIZING_SID_ENABLED, /**< Instance is initializing - waiting for remote to acknowledge. Sending will fail. Opening allowed, session will change and remote may or may not get unbound() callback. */
34+
ICMSG_STATE_INITIALIZING_SID_COMPAT, /**< Instance is initializing - waiting for remote to acknowledge. Sending will fail. Opening allowed, session will change and remote may or may not get unbound() callback. */
35+
ICMSG_STATE_CONNECTED_SID_DISABLED, /**< Instance is connected. Sending will be successful. Opening allowed, session will change and remote will get unbound() callback. */
36+
ICMSG_STATE_CONNECTED_SID_ENABLED, /**< Instance is connected. Sending will be successful. Opening allowed, session will change and remote will get unbound() callback. */
37+
ICMSG_STATE_DISCONNECTED_SID_ENABLED, /**< Instance was connected, but get disconnected. Sending will be silently discarded, because it there may be old sends. Opening allowed. */
38+
// TODO: ICMSG_STATE_COMPATIBILITY
3539
};
3640

3741
enum icmsg_unbound_mode {

include/zephyr/ipc/pbuf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ int pbuf_read(struct pbuf *pb, char *buf, uint16_t len);
233233
uint32_t pbuf_handshake_read(struct pbuf *pb);
234234
void pbuf_handshake_write(struct pbuf *pb, uint32_t value);
235235

236+
int pbuf_get_initial_buf(struct pbuf *pb, volatile char **buf, uint16_t *len);
237+
236238
/**
237239
* @}
238240
*/

subsys/ipc/ipc_service/lib/icmsg.c

Lines changed: 176 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@
1919
#define MAKE_RX_HANDSHAKE(local_sid_req, remote_sid_ack) ((local_sid_req) | ((remote_sid_ack) << 16))
2020
#define MAKE_TX_HANDSHAKE(remote_sid_req, local_sid_ack) ((remote_sid_req) | ((local_sid_ack) << 16))
2121

22-
#define SID_DISCONNECTED_BIT 0x8000
22+
#define SID_DISCONNECTED 0
2323

2424
#define BOND_NOTIFY_REPEAT_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS)
2525
#define SHMEM_ACCESS_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS)
2626

2727
static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, 0x30,
28-
0x72, 0x6e, 0x33, 0x6c, 0x69, 0x34, 0x01 };
29-
30-
#define OLD_MAGIC_LENGTH (sizeof(magic) - 1)
28+
0x72, 0x6e, 0x33, 0x6c, 0x69, 0x34,};
3129

3230
#ifdef CONFIG_MULTITHREADING
3331
#if defined(CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE)
@@ -187,47 +185,184 @@ static void mbox_callback_process(struct icmsg_data_t *dev_data)
187185
#ifdef CONFIG_MULTITHREADING
188186
struct icmsg_data_t *dev_data = CONTAINER_OF(item, struct icmsg_data_t, mbox_work);
189187
#endif
188+
int ret;
190189
uint8_t rx_buffer[CONFIG_PBUF_RX_READ_BUF_SIZE] __aligned(4);
191-
190+
uint32_t len;
191+
bool rerun = false;
192+
bool notify_remote = false;
192193
atomic_t state = atomic_get(&dev_data->state);
193194

194-
uint32_t len = data_available(dev_data);
195+
uint32_t tx_handshake = pbuf_handshake_read(dev_data->tx_pb);
196+
uint32_t remote_sid_req = REMOTE_SID_REQ_FROM_TX(tx_handshake);
197+
uint32_t local_sid_ack = LOCAL_SID_ACK_FROM_TX(tx_handshake);
198+
199+
volatile char *magic_buf;
200+
uint16_t *magic_len;
201+
202+
switch (state) {
203+
case ICMSG_STATE_INITIALIZING_SID_COMPAT:
204+
// Initialization with detection of remote session awareness
205+
206+
ret = pbuf_get_initial_buf(dev_data->rx_pb, &buf, &len); // TODO: You forget about header!!!
207+
208+
if (ret == 0 && len == sizeof(magic) && memcmp((void*)buf, magic, sizeof(magic)) == 0) {
209+
// Remote initalized in session-unaware mode, so we do old way of initialization.
210+
ret = pbuf_tx_init(dev_data->tx_pb); // TODO: maybe extract to common function with "open".
211+
if (ret < 0) {
212+
if (dev_data->cb->error) { // TODO: goto cleanup
213+
dev_data->cb->error("Incorrect Tx configuration", dev_data->ctx);
214+
}
215+
__ASSERT(false, "Incorrect Tx configuration");
216+
atomic_set(&dev_data->state, ICMSG_STATE_DISCONNECTED);
217+
return;
218+
}
219+
ret = pbuf_write(dev_data->tx_pb, magic, sizeof(magic));
220+
if (ret < 0) {
221+
if (dev_data->cb->error) { // TODO: goto cleanup
222+
dev_data->cb->error("Incorrect Tx configuration", dev_data->ctx);
223+
}
224+
__ASSERT(false, "Incorrect Tx configuration");
225+
atomic_set(&dev_data->state, ICMSG_STATE_DISCONNECTED);
226+
return;
227+
}
228+
// We got magic data, so we can handle it later.
229+
notify_remote = true;
230+
rerun = true;
231+
atomic_set(&dev_data->state, ICMSG_STATE_INITIALIZING_SID_DISABLED);
232+
break;
233+
}
234+
// If remote did not initialize the RX in session-unaware mode, we can try
235+
// with session-aware initialization.
236+
__fallthrough;
237+
238+
case ICMSG_STATE_INITIALIZING_SID_ENABLED:
239+
if (remote_sid_req != dev_data->remote_session && remote_sid_req != SID_DISCONNECTED) {
240+
// We can now initialize TX, since we know that remote, during receiving,
241+
// will first read FIFO indexes and later, it will check if session has changed
242+
// before using indexes to receive the message. Additionally, we know that
243+
// remote after session request change will no try to receive more data.
244+
ret = pbuf_tx_init(dev_data->tx_pb);
245+
if (ret < 0) {
246+
if (dev_data->cb->error) {
247+
dev_data->cb->error("Incorrect Tx configuration", dev_data->ctx);
248+
}
249+
__ASSERT(false, "Incorrect Tx configuration");
250+
atomic_set(&dev_data->state, ICMSG_STATE_DISCONNECTED);
251+
return;
252+
}
253+
// Acknowledge the remote session.
254+
dev_data->remote_session = remote_sid_req;
255+
pbuf_handshake_write(dev_data->rx_pb, MAKE_RX_HANDSHAKE(dev_data->local_session, dev_data->remote_session));
256+
notify_remote = true;
257+
}
195258

196-
if (len == 0) {
197-
/* Unlikely, no data in buffer. */
198-
return;
199-
}
259+
if (local_sid_ack == dev_data->local_session &&
260+
dev_data->remote_session != SID_DISCONNECTED) {
261+
// We send acknowledge to remote, receive acknowledge from remote,
262+
// so we are ready.
263+
atomic_set(&dev_data->state, ICMSG_STATE_CONNECTED);
264+
265+
if (dev_data->cb->bound) {
266+
dev_data->cb->bound(dev_data->ctx);
267+
}
268+
// Re-run this handler, because remote may already send something.
269+
rerun = true;
270+
notify_remote = true;
271+
}
200272

201-
__ASSERT_NO_MSG(len <= sizeof(rx_buffer));
273+
break;
202274

203-
if (sizeof(rx_buffer) < len) {
204-
return;
205-
}
275+
case ICMSG_STATE_CONNECTED_SID_ENABLED: { // TODO: Later, consider combining with ICMSG_STATE_CONNECTED_SID_DISABLED
276+
uint32_t read_index;
277+
uint32_t write_index;
278+
279+
// Get RX indexes and save for later
280+
len = pbuf_read_indexes(dev_data->rx_pb, &read_index, &write_index);
281+
282+
// The indexes are valid only if remote session is as expected, so we need
283+
// to check remote session now.
284+
remote_sid_req = REMOTE_SID_REQ_FROM_TX(pbuf_handshake_read(dev_data->tx_pb));
206285

207-
len = pbuf_read(dev_data->rx_pb, rx_buffer, sizeof(rx_buffer));
286+
if (remote_sid_req != dev_data->remote_session) {
287+
atomic_set(&dev_data->state, ICMSG_STATE_DISCONNECTED_SID_ENABLED);
288+
if (dev_data->cb->unbound) {
289+
dev_data->cb->unbound(dev_data->ctx);
290+
}
291+
return;
292+
}
293+
294+
if (len == 0) {
295+
/* Unlikely, no data in buffer. */
296+
return;
297+
}
298+
299+
__ASSERT_NO_MSG(len <= sizeof(rx_buffer));
300+
301+
if (sizeof(rx_buffer) < len) {
302+
return;
303+
}
304+
305+
len = pbuf_read_from_indexes(dev_data->rx_pb, read_index, write_index, rx_buffer, sizeof(rx_buffer));
208306

209-
if (state == ICMSG_STATE_READY) {
210307
if (dev_data->cb->received) {
211308
dev_data->cb->received(rx_buffer, len, dev_data->ctx);
212309
}
213-
} else {
214-
__ASSERT_NO_MSG(state == ICMSG_STATE_BUSY);
215310

216-
/* Allow magic number longer than sizeof(magic) for future protocol version. */
217-
bool endpoint_invalid = (len < sizeof(magic) ||
218-
memcmp(magic, rx_buffer, sizeof(magic)));
311+
// TODO:
312+
break;
313+
}
219314

220-
if (endpoint_invalid) {
221-
__ASSERT_NO_MSG(false);
315+
case ICMSG_STATE_INITIALIZING_SID_DISABLED:
316+
case ICMSG_STATE_CONNECTED_SID_DISABLED:
317+
318+
len = data_available(dev_data);
319+
320+
if (len == 0) {
321+
/* Unlikely, no data in buffer. */
222322
return;
223323
}
224324

225-
if (dev_data->cb->bound) {
226-
dev_data->cb->bound(dev_data->ctx);
325+
__ASSERT_NO_MSG(len <= sizeof(rx_buffer));
326+
327+
if (sizeof(rx_buffer) < len) {
328+
return;
227329
}
228330

229-
atomic_set(&dev_data->state, ICMSG_STATE_READY);
331+
len = pbuf_read(dev_data->rx_pb, rx_buffer, sizeof(rx_buffer));
332+
333+
if (state == ICMSG_STATE_CONNECTED_SID_DISABLED) {
334+
if (dev_data->cb->received) {
335+
dev_data->cb->received(rx_buffer, len, dev_data->ctx);
336+
}
337+
} else {
338+
/* Allow magic number longer than sizeof(magic) for future protocol version. */
339+
bool endpoint_invalid = (len < sizeof(magic) ||
340+
memcmp(magic, rx_buffer, sizeof(magic)));
341+
342+
if (endpoint_invalid) {
343+
__ASSERT_NO_MSG(false);
344+
return;
345+
}
346+
347+
if (dev_data->cb->bound) {
348+
dev_data->cb->bound(dev_data->ctx);
349+
}
350+
351+
atomic_set(&dev_data->state, ICMSG_STATE_CONNECTED_SID_DISABLED);
352+
}
353+
break;
354+
355+
case ICMSG_STATE_UNINITIALIZED:
356+
case ICMSG_STATE_DISCONNECTED_SID_ENABLED:
357+
default:
358+
// Nothing to do in this state.
359+
return;
360+
}
361+
362+
if (notify_remote) {
363+
(void)mbox_send_dt(&dev_data->conf->mbox_tx, NULL);
230364
}
365+
231366
#ifdef CONFIG_MULTITHREADING
232367
submit_work_if_buffer_free_and_data_available(dev_data);
233368
#else
@@ -281,18 +416,25 @@ int icmsg_open(const struct icmsg_config_t *conf,
281416
k_mutex_init(&dev_data->tx_lock);
282417
#endif
283418

419+
ret = pbuf_rx_init(dev_data->rx_pb);
420+
421+
if (ret < 0) {
422+
__ASSERT(false, "Incorrect Rx configuration");
423+
return ret;
424+
}
425+
284426
if (conf->unbound_mode != ICMSG_UNBOUND_MODE_DISABLE) {
285427
// Increment local session id without conflicts with forbidden values.
286428
uint32_t local_session_ack =
287429
LOCAL_SID_ACK_FROM_TX(pbuf_handshake_read(dev_data->tx_pb));
288430
dev_data->local_session =
289431
LOCAL_SID_REQ_FROM_RX(pbuf_handshake_read(dev_data->tx_pb));
290-
dev_data->remote_session = 0;
432+
dev_data->remote_session = SID_DISCONNECTED;
291433
do {
292-
dev_data->local_session = (dev_data->local_session + 1) & 0x8FFF;
293-
} while (dev_data->local_session == local_session_ack || dev_data->local_session == 0);
434+
dev_data->local_session = (dev_data->local_session + 1) & 0xFFFF;
435+
} while (dev_data->local_session == local_session_ack || dev_data->local_session == SID_DISCONNECTED);
294436
// Write local session id request without remote acknowledge
295-
pbuf_handshake_write(MAKE_RX_HANDSHAKE(dev_data->local_session, 0));
437+
pbuf_handshake_write(dev_data->rx_pb, MAKE_RX_HANDSHAKE(dev_data->local_session, SID_DISCONNECTED));
296438
// We can now initialize TX, since we know that remote, during receiving,
297439
// will first read FIFO indexes and later, it will check if session has changed
298440
// before using indexes to receive the message.
@@ -310,13 +452,6 @@ int icmsg_open(const struct icmsg_config_t *conf,
310452
return ret;
311453
}
312454

313-
ret = pbuf_rx_init(dev_data->rx_pb);
314-
315-
if (ret < 0) {
316-
__ASSERT(false, "Incorrect Rx configuration");
317-
return ret;
318-
}
319-
320455
ret = pbuf_write(dev_data->tx_pb, magic, sizeof(magic));
321456

322457
if (ret < 0) {
@@ -363,6 +498,10 @@ int icmsg_close(const struct icmsg_config_t *conf,
363498

364499
enum icmsg_state old_state;
365500

501+
pbuf_handshake_write(dev_data->rx_pb, MAKE_RX_HANDSHAKE(SID_DISCONNECTED, SID_DISCONNECTED));
502+
503+
(void)mbox_send_dt(&conf->mbox_tx, NULL);
504+
366505
old_state = atomic_set(&dev_data->state, ICMSG_STATE_UNINITIALIZED);
367506

368507
if (old_state != ICMSG_STATE_UNINITIALIZED) {

subsys/ipc/ipc_service/lib/pbuf.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,29 @@ int pbuf_write(struct pbuf *pb, const char *data, uint16_t len)
179179
return len;
180180
}
181181

182+
int pbuf_get_initial_buf(struct pbuf *pb, volatile char **buf, uint16_t *len)
183+
{
184+
uint32_t wr_idx;
185+
186+
if (pb == NULL || pb->data.rd_idx != 0) {
187+
/* Incorrect call. */
188+
return -EINVAL;
189+
}
190+
191+
sys_cache_data_invd_range((void *)(pb->cfg->wr_idx_loc), sizeof(*(pb->cfg->wr_idx_loc)));
192+
__sync_synchronize();
193+
194+
wr_idx = *(pb->cfg->wr_idx_loc);
195+
if (wr_idx >= pb->cfg->len || wr_idx > 0xFFFF || wr_idx == 0) {
196+
/* Incorrect index - probably pbuf was not initialized or message was not send yet. */
197+
return -EINVAL;
198+
}
199+
*buf = pb->cfg->data_loc; // TODO: What about header???
200+
*len = wr_idx; // TODO: len depends on len field in header
201+
202+
return 0;
203+
}
204+
182205
int pbuf_read(struct pbuf *pb, char *buf, uint16_t len)
183206
{
184207
if (pb == NULL) {

0 commit comments

Comments
 (0)