1212#include <zephyr/ipc/pbuf.h>
1313#include <zephyr/init.h>
1414
15+ #define LOCAL_SID_REQ_FROM_RX (rx_handshake ) ((rx_handshake) & 0xFFFF)
16+ #define REMOTE_SID_ACK_FROM_RX (rx_handshake ) ((rx_handshake) >> 16)
17+ #define REMOTE_SID_REQ_FROM_TX (tx_handshake ) ((tx_handshake) & 0xFFFF)
18+ #define LOCAL_SID_ACK_FROM_TX (tx_handshake ) ((tx_handshake) >> 16)
19+ #define MAKE_RX_HANDSHAKE (local_sid_req , remote_sid_ack ) ((local_sid_req) | ((remote_sid_ack) << 16))
20+ #define MAKE_TX_HANDSHAKE (remote_sid_req , local_sid_ack ) ((remote_sid_req) | ((local_sid_ack) << 16))
21+
22+ #define SID_DISCONNECTED_BIT 0x8000
23+
1524#define BOND_NOTIFY_REPEAT_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS)
1625#define SHMEM_ACCESS_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS)
1726
@@ -259,10 +268,10 @@ int icmsg_open(const struct icmsg_config_t *conf,
259268 struct icmsg_data_t * dev_data ,
260269 const struct ipc_service_cb * cb , void * ctx )
261270{
262- if (! atomic_cas ( & dev_data -> state , ICMSG_STATE_OFF , ICMSG_STATE_BUSY )) {
263- /* Already opened. */
264- return - EALREADY ;
265- }
271+ int ret ;
272+ enum icmsg_state old_state ;
273+
274+ old_state = atomic_set ( & dev_data -> state , ICMSG_STATE_INITIALIZING );
266275
267276 dev_data -> cb = cb ;
268277 dev_data -> ctx = ctx ;
@@ -272,55 +281,95 @@ int icmsg_open(const struct icmsg_config_t *conf,
272281 k_mutex_init (& dev_data -> tx_lock );
273282#endif
274283
275- int ret = pbuf_tx_init (dev_data -> tx_pb );
284+ if (conf -> unbound_mode != ICMSG_UNBOUND_MODE_DISABLE ) {
285+ // Increment local session id without conflicts with forbidden values.
286+ uint32_t local_session_ack =
287+ LOCAL_SID_ACK_FROM_TX (pbuf_handshake_read (dev_data -> tx_pb ));
288+ dev_data -> local_session =
289+ LOCAL_SID_REQ_FROM_RX (pbuf_handshake_read (dev_data -> tx_pb ));
290+ dev_data -> remote_session = 0 ;
291+ 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 );
294+ // Write local session id request without remote acknowledge
295+ pbuf_handshake_write (MAKE_RX_HANDSHAKE (dev_data -> local_session , 0 ));
296+ // We can now initialize TX, since we know that remote, during receiving,
297+ // will first read FIFO indexes and later, it will check if session has changed
298+ // before using indexes to receive the message.
299+ // TODO: above not treue, We should reinit TX just before sending remote acknowledgement, because
300+ // remote may change read index!
301+ // Sending magic packet should be after local acknowledgement.
302+ } else {
303+ // Initialization of RX and sending magic bytes must be postponed
304+ // if unbound mode enabled. We need to wait until remote is ready.
276305
277- if (ret < 0 ) {
278- __ASSERT (false, "Incorrect configuration" );
279- return ret ;
280- }
306+ ret = pbuf_tx_init (dev_data -> tx_pb );
281307
282- (void )pbuf_rx_init (dev_data -> rx_pb );
308+ if (ret < 0 ) {
309+ __ASSERT (false, "Incorrect Tx configuration" );
310+ return ret ;
311+ }
283312
284- ret = pbuf_write (dev_data -> tx_pb , magic , sizeof ( magic ) );
313+ ret = pbuf_rx_init (dev_data -> rx_pb );
285314
286- if (ret < 0 ) {
287- __ASSERT_NO_MSG (false);
288- return ret ;
289- }
315+ if (ret < 0 ) {
316+ __ASSERT (false, "Incorrect Rx configuration" );
317+ return ret ;
318+ }
290319
291- if (ret < (int )sizeof (magic )) {
292- __ASSERT_NO_MSG (ret == sizeof (magic ));
293- return ret ;
320+ ret = pbuf_write (dev_data -> tx_pb , magic , sizeof (magic ));
321+
322+ if (ret < 0 ) {
323+ __ASSERT_NO_MSG (false);
324+ return ret ;
325+ }
326+
327+ if (ret < (int )sizeof (magic )) {
328+ __ASSERT_NO_MSG (ret == sizeof (magic ));
329+ return ret ;
330+ }
294331 }
295332
296- ret = mbox_init (conf , dev_data );
297- if (ret ) {
298- return ret ;
333+ if (old_state == ICMSG_STATE_UNINITIALIZED ) {
334+ // Initialize mbox only if we are doing first-time open (not re-open after unbound)
335+ ret = mbox_init (conf , dev_data );
336+ if (ret ) {
337+ return ret ;
338+ }
299339 }
340+
341+ if (conf -> unbound_mode == ICMSG_UNBOUND_MODE_DISABLE ) {
342+ // Polling is only when unbound mode is disabled.
300343#ifdef CONFIG_MULTITHREADING
301344 ret = k_work_schedule_for_queue (workq , & dev_data -> notify_work , K_NO_WAIT );
302- if (ret < 0 ) {
303- return ret ;
304- }
305345#else
306346 notify_process (dev_data );
347+ ret = 0 ;
307348#endif
308- return 0 ;
349+ } else {
350+ // We need to send a notification to remote, it may not be delivered
351+ // since it may be uninitialized yet, but when it finishes the initialization
352+ // we get a notification from it. We need to send this notification in callback
353+ // again to make sure that it arrived.
354+ ret = mbox_send_dt (& conf -> mbox_tx , NULL );
355+ }
356+ return ret ;
309357}
310358
311359int icmsg_close (const struct icmsg_config_t * conf ,
312360 struct icmsg_data_t * dev_data )
313361{
314- int ret ;
362+ int ret = 0 ;
315363
316- ret = mbox_deinit (conf , dev_data );
317- if (ret ) {
318- return ret ;
319- }
364+ enum icmsg_state old_state ;
320365
321- atomic_set (& dev_data -> state , ICMSG_STATE_OFF );
366+ old_state = atomic_set (& dev_data -> state , ICMSG_STATE_UNINITIALIZED );
322367
323- return 0 ;
368+ if (old_state != ICMSG_STATE_UNINITIALIZED ) {
369+ ret = mbox_deinit (conf , dev_data );
370+ }
371+
372+ return ret ;
324373}
325374
326375int icmsg_send (const struct icmsg_config_t * conf ,
0 commit comments