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
2727static 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 ) {
0 commit comments