1 /*
2 * Copyright 2017, NXP
3 * All rights reserved.
4 *
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include <string.h>
10
11 #include <srtm_heap.h>
12
13 #include "srtm_dispatcher.h"
14 #include "srtm_dispatcher_struct.h"
15 #include "srtm_peercore.h"
16 #include "srtm_peercore_struct.h"
17 #include "srtm_service.h"
18 #include "srtm_service_struct.h"
19 #include "srtm_channel.h"
20 #include "srtm_channel_struct.h"
21 #include "srtm_message.h"
22 #include "srtm_message_struct.h"
23 #include "fsl_common.h"
24
25 /*******************************************************************************
26 * Definitions
27 ******************************************************************************/
28
29 /*******************************************************************************
30 * Prototypes
31 ******************************************************************************/
32
33 /*******************************************************************************
34 * Variables
35 ******************************************************************************/
36
37 /*******************************************************************************
38 * Code
39 ******************************************************************************/
SRTM_DumpMessage(srtm_message_t msg)40 static void SRTM_DumpMessage(srtm_message_t msg)
41 {
42 #ifdef SRTM_DEBUG_MESSAGE_FUNC
43 srtm_packet_head_t *head;
44
45 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, " -- Msg type %d, dir %d, dlen %d, chan 0x%08x, err %d, prio %d\r\n",
46 msg->type, msg->direct, msg->dataLen, msg->channel, msg->error, msg->priority);
47 if (msg->dataLen >= sizeof(struct _srtm_packet_head))
48 {
49 head = (srtm_packet_head_t *)msg->data;
50 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, " -- Data cat %d, majv %d, minv %d, type %d, cmd %d, prio %d\r\n",
51 head->category, head->majorVersion, head->minorVersion, head->type, head->command,
52 head->priority);
53 }
54 else if (msg->type == SRTM_MessageTypeProcedure)
55 {
56 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, " -- Callback 0x%08x, param 0x%x, 0x%x\r\n", msg->procMsg.cb,
57 msg->procMsg.param1, msg->procMsg.param2);
58 }
59 else
60 {
61 /* Do nothing */
62 }
63 #endif
64 }
65
SRTM_Dispatcher_InsertOrderedMessage(srtm_dispatcher_t disp,srtm_message_t msg)66 static void SRTM_Dispatcher_InsertOrderedMessage(srtm_dispatcher_t disp, srtm_message_t msg)
67 {
68 srtm_list_t *list;
69 srtm_message_t message;
70
71 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
72
73 SRTM_DumpMessage(msg);
74 /* Insert message with priority order */
75 for (list = disp->messageQ.prev; list != &disp->messageQ; list = list->prev)
76 {
77 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
78 if (message->priority >= msg->priority)
79 {
80 break;
81 }
82 }
83 SRTM_List_InsertAfter(list, &msg->node);
84 }
85
86 /* Send message to messageQ from ISR or task context */
SRTM_Dispatcher_QueueMessage(srtm_dispatcher_t disp,srtm_message_t msg)87 static void SRTM_Dispatcher_QueueMessage(srtm_dispatcher_t disp, srtm_message_t msg)
88 {
89 uint32_t primask;
90
91 assert(SRTM_List_IsEmpty(&msg->node));
92
93 primask = DisableGlobalIRQ();
94 SRTM_Dispatcher_InsertOrderedMessage(disp, msg);
95 EnableGlobalIRQ(primask);
96
97 (void)SRTM_Sem_Post(disp->queueSig);
98 }
99
100 /* Dequeue message might detach message from messageQ, peer core's pendingQ or waitingReqs */
SRTM_Dispatcher_DequeueMessage(srtm_dispatcher_t disp,srtm_message_t msg)101 static srtm_status_t SRTM_Dispatcher_DequeueMessage(srtm_dispatcher_t disp, srtm_message_t msg)
102 {
103 uint32_t primask;
104 srtm_status_t status = SRTM_Status_ListRemoveFailed;
105
106 (void)SRTM_Mutex_Lock(disp->mutex); /* Protect waitingReqs */
107 primask = DisableGlobalIRQ(); /* Protect messageQ */
108 if (!SRTM_List_IsEmpty(&msg->node))
109 {
110 SRTM_List_Remove(&msg->node);
111 status = SRTM_Status_Success;
112 }
113 EnableGlobalIRQ(primask);
114 (void)SRTM_Mutex_Unlock(disp->mutex);
115
116 return status;
117 }
118
SRTM_Dispatcher_RecvMessage(srtm_dispatcher_t disp)119 static srtm_message_t SRTM_Dispatcher_RecvMessage(srtm_dispatcher_t disp)
120 {
121 uint32_t primask;
122 srtm_list_t *list;
123 srtm_message_t message = NULL;
124
125 primask = DisableGlobalIRQ();
126 if (!SRTM_List_IsEmpty(&disp->messageQ))
127 {
128 list = disp->messageQ.next;
129 SRTM_List_Remove(list);
130 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
131 }
132 EnableGlobalIRQ(primask);
133
134 return message;
135 }
136
SRTM_Dispatcher_FreeRequest(srtm_dispatcher_t disp,srtm_request_t req,srtm_status_t error)137 static void SRTM_Dispatcher_FreeRequest(srtm_dispatcher_t disp, srtm_request_t req, srtm_status_t error)
138 {
139 req->error = error;
140 if (req->reqMsg.isSyncReq)
141 {
142 /* Synchronous request will be freed by user. Here just wakeup user's task. */
143 (void)SRTM_Sem_Post(req->reqMsg.sync.sig);
144 }
145 else
146 {
147 if (req->reqMsg.async.cb != NULL)
148 {
149 req->reqMsg.async.cb(disp, req, NULL, req->reqMsg.async.param);
150 }
151 SRTM_Request_Destroy(req);
152 }
153 }
154
SRTM_Dispatcher_FreeMessage(srtm_dispatcher_t disp,srtm_message_t msg)155 static void SRTM_Dispatcher_FreeMessage(srtm_dispatcher_t disp, srtm_message_t msg)
156 {
157 switch (msg->type)
158 {
159 case SRTM_MessageTypeProcedure:
160 SRTM_Procedure_Destroy(msg);
161 break;
162 case SRTM_MessageTypeRawData:
163 SRTM_RawData_Destroy(msg);
164 break;
165 case SRTM_MessageTypeRequest:
166 if (msg->direct == SRTM_MessageDirectRx)
167 {
168 /* Rx request will be freed after handling */
169 SRTM_Request_Destroy(msg);
170 }
171 else
172 {
173 /* Tx request finalization need to inform user and then free. */
174 SRTM_Dispatcher_FreeRequest(disp, msg, SRTM_Status_TransferNotAvail);
175 }
176 break;
177 case SRTM_MessageTypeResponse:
178 SRTM_Response_Destroy(msg);
179 break;
180 case SRTM_MessageTypeNotification:
181 SRTM_Notification_Destroy(msg);
182 break;
183 default:
184 SRTM_Message_Destroy(msg);
185 break;
186 }
187 }
188
SRTM_Dispatcher_RecycleMessage(srtm_message_t msg,void * param)189 static void SRTM_Dispatcher_RecycleMessage(srtm_message_t msg, void *param)
190 {
191 uint32_t primask;
192 srtm_dispatcher_t disp = (srtm_dispatcher_t)param;
193
194 /* Put RX message back to freeRxMsgs */
195 primask = DisableGlobalIRQ();
196 SRTM_List_AddTail(&disp->freeRxMsgs, &msg->node);
197 EnableGlobalIRQ(primask);
198 }
199
SRTM_Dispatcher_Create(void)200 srtm_dispatcher_t SRTM_Dispatcher_Create(void)
201 {
202 srtm_dispatcher_t disp = (srtm_dispatcher_t)SRTM_Heap_Malloc(sizeof(struct _srtm_dispatcher));
203 #if defined(SRTM_STATIC_API) && SRTM_STATIC_API
204 srtm_mutex_t mutex = SRTM_Mutex_Create(&disp->mutexStatic);
205 srtm_sem_t startSig = SRTM_Sem_Create(1U, 0U, &disp->startSigStatic);
206 srtm_sem_t stopSig = SRTM_Sem_Create(1U, 0U, &disp->stopSigStatic);
207 /* Assume same maximum message number of local and remote in messageQ */
208 srtm_sem_t queueSig = SRTM_Sem_Create(SRTM_DISPATCHER_CONFIG_RX_MSG_NUMBER * 2, 0U, &disp->queueSigStatic);
209 #else
210 srtm_mutex_t mutex = SRTM_Mutex_Create();
211 srtm_sem_t startSig = SRTM_Sem_Create(1U, 0U);
212 srtm_sem_t stopSig = SRTM_Sem_Create(1U, 0U);
213 /* Assume same maximum message number of local and remote in messageQ */
214 srtm_sem_t queueSig = SRTM_Sem_Create(SRTM_DISPATCHER_CONFIG_RX_MSG_NUMBER * 2U, 0U);
215 #endif
216 srtm_message_t msg;
217 uint32_t i;
218
219 assert((disp != NULL) && (mutex != NULL) && (startSig != NULL) && (stopSig != NULL) && (queueSig != NULL));
220
221 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
222
223 SRTM_List_Init(&disp->cores);
224 SRTM_List_Init(&disp->services);
225 SRTM_List_Init(&disp->freeRxMsgs);
226 SRTM_List_Init(&disp->messageQ);
227 SRTM_List_Init(&disp->waitingReqs);
228 disp->mutex = mutex;
229 disp->stopReq = false;
230 disp->started = false;
231 disp->startSig = startSig;
232 disp->stopSig = stopSig;
233 disp->queueSig = queueSig;
234
235 for (i = 0; i < SRTM_DISPATCHER_CONFIG_RX_MSG_NUMBER; i++)
236 {
237 msg = SRTM_Message_Create(SRTM_DISPATCHER_CONFIG_RX_MSG_MAX_LEN);
238 assert(msg);
239 SRTM_Message_SetFreeFunc(msg, SRTM_Dispatcher_RecycleMessage, disp);
240 SRTM_List_AddTail(&disp->freeRxMsgs, &msg->node);
241 }
242
243 return disp;
244 }
245
SRTM_Dispatcher_Destroy(srtm_dispatcher_t disp)246 void SRTM_Dispatcher_Destroy(srtm_dispatcher_t disp)
247 {
248 srtm_list_t *list;
249 srtm_peercore_t core;
250 srtm_service_t service;
251 srtm_message_t msg;
252
253 assert(disp);
254 assert(!disp->started);
255
256 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
257
258 /* Before destroy, all the messages should be well handled */
259 assert(SRTM_List_IsEmpty(&disp->messageQ));
260 /* Before destroy, all the waiting request should responded */
261 assert(SRTM_List_IsEmpty(&disp->waitingReqs));
262
263 while (!SRTM_List_IsEmpty(&disp->cores))
264 {
265 list = disp->cores.next;
266 SRTM_List_Remove(list);
267 core = SRTM_LIST_OBJ(srtm_peercore_t, node, list);
268 SRTM_PeerCore_Destroy(core);
269 }
270
271 while (!SRTM_List_IsEmpty(&disp->services))
272 {
273 list = disp->services.next;
274 SRTM_List_Remove(list);
275 service = SRTM_LIST_OBJ(srtm_service_t, node, list);
276 SRTM_Service_Destroy(service);
277 }
278
279 while (!SRTM_List_IsEmpty(&disp->freeRxMsgs))
280 {
281 list = disp->freeRxMsgs.next;
282 SRTM_List_Remove(list);
283 msg = SRTM_LIST_OBJ(srtm_message_t, node, list);
284 SRTM_Message_SetFreeFunc(msg, NULL, NULL);
285 SRTM_Message_Destroy(msg);
286 }
287
288 SRTM_Mutex_Destroy(disp->mutex);
289 SRTM_Sem_Destroy(disp->startSig);
290 SRTM_Sem_Destroy(disp->stopSig);
291 SRTM_Sem_Destroy(disp->queueSig);
292 SRTM_Heap_Free(disp);
293 }
294
SRTM_Dispatcher_Start(srtm_dispatcher_t disp)295 srtm_status_t SRTM_Dispatcher_Start(srtm_dispatcher_t disp)
296 {
297 assert(disp);
298
299 if (disp->started)
300 {
301 return SRTM_Status_InvalidState;
302 }
303
304 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
305
306 disp->stopReq = false;
307 disp->started = true;
308 (void)SRTM_Sem_Post(disp->startSig);
309
310 return SRTM_Status_Success;
311 }
312
SRTM_Dispatcher_Stop(srtm_dispatcher_t disp)313 srtm_status_t SRTM_Dispatcher_Stop(srtm_dispatcher_t disp)
314 {
315 if (!disp->started)
316 {
317 return SRTM_Status_InvalidState;
318 }
319
320 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
321
322 disp->stopReq = true;
323 /* Wakeup dispatcher to do stop operations */
324 (void)SRTM_Sem_Post(disp->queueSig);
325 /* Wait for dispatcher stopped */
326 (void)SRTM_Sem_Wait(disp->stopSig, SRTM_WAIT_FOR_EVER);
327
328 disp->started = false;
329
330 return SRTM_Status_Success;
331 }
332
SRTM_Dispatcher_Run(srtm_dispatcher_t disp)333 void SRTM_Dispatcher_Run(srtm_dispatcher_t disp)
334 {
335 srtm_list_t *list;
336 srtm_peercore_t core;
337 srtm_message_t message;
338
339 assert(disp);
340
341 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);
342
343 while (true)
344 {
345 /* Wait for start */
346 (void)SRTM_Sem_Wait(disp->startSig, SRTM_WAIT_FOR_EVER);
347
348 /* Start peer cores */
349 for (list = disp->cores.next; list != &disp->cores; list = list->next)
350 {
351 core = SRTM_LIST_OBJ(srtm_peercore_t, node, list);
352 (void)SRTM_PeerCore_Start(core);
353 }
354
355 while (!disp->stopReq)
356 {
357 /* Wait for message putting into Q */
358 (void)SRTM_Sem_Wait(disp->queueSig, SRTM_WAIT_FOR_EVER);
359 /* Handle as many messages as possible */
360 while (!disp->stopReq)
361 {
362 message = SRTM_Dispatcher_RecvMessage(disp);
363 if (message != NULL)
364 {
365 (void)SRTM_Dispatcher_ProcessMessage(disp, message);
366 }
367 else
368 {
369 break;
370 }
371 }
372 }
373
374 /* Stop peer cores */
375 for (list = disp->cores.next; list != &disp->cores; list = list->next)
376 {
377 core = SRTM_LIST_OBJ(srtm_peercore_t, node, list);
378 (void)SRTM_PeerCore_Stop(core);
379 }
380
381 /* Signal dispatcher stopped */
382 (void)SRTM_Sem_Post(disp->stopSig);
383 }
384 }
385
SRTM_Dispatcher_AddPeerCore(srtm_dispatcher_t disp,srtm_peercore_t core)386 srtm_status_t SRTM_Dispatcher_AddPeerCore(srtm_dispatcher_t disp, srtm_peercore_t core)
387 {
388 assert(disp);
389 assert(core);
390 assert(!disp->started); /* Add core when SRTM dispatcher running is forbidden */
391
392 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: 0x%x\r\n", __func__, core);
393
394 if (!SRTM_List_IsEmpty(&core->node))
395 {
396 return SRTM_Status_ListAddFailed;
397 }
398
399 (void)SRTM_Mutex_Lock(disp->mutex);
400 SRTM_List_AddTail(&disp->cores, &core->node);
401 (void)SRTM_Mutex_Unlock(disp->mutex);
402 core->dispatcher = disp;
403
404 return SRTM_Status_Success;
405 }
406
SRTM_Dispatcher_RemovePeerCore(srtm_dispatcher_t disp,srtm_peercore_t core)407 srtm_status_t SRTM_Dispatcher_RemovePeerCore(srtm_dispatcher_t disp, srtm_peercore_t core)
408 {
409 uint32_t primask;
410 srtm_list_t listHead;
411 srtm_list_t *list, *next;
412 srtm_message_t message;
413
414 assert(disp);
415 assert(core);
416 assert(!disp->started); /* Remove core when SRTM dispatcher running is forbidden */
417
418 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: 0x%x\r\n", __func__, core);
419
420 if (SRTM_List_IsEmpty(&core->node))
421 {
422 return SRTM_Status_ListRemoveFailed;
423 }
424
425 (void)SRTM_Mutex_Lock(disp->mutex);
426 SRTM_List_Remove(&core->node);
427 (void)SRTM_Mutex_Unlock(disp->mutex);
428 core->dispatcher = NULL;
429
430 SRTM_List_Init(&listHead);
431
432 /* Clean up all corresponding messages for the peer core */
433 /* First clean up messages in messageQ */
434 primask = DisableGlobalIRQ();
435 for (list = disp->messageQ.next; list != &disp->messageQ; list = next)
436 {
437 next = list->next;
438 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
439 if ((message->channel != NULL) && (message->channel->core == core))
440 {
441 SRTM_List_Remove(list);
442 /* Add to temp list */
443 SRTM_List_AddTail(&listHead, list);
444 }
445 }
446 EnableGlobalIRQ(primask);
447
448 /* Next clean up messages in waitingReqs */
449 (void)SRTM_Mutex_Lock(disp->mutex);
450 for (list = disp->waitingReqs.next; list != &disp->waitingReqs; list = next)
451 {
452 next = list->next;
453 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
454 if ((message->channel != NULL) && (message->channel->core == core))
455 {
456 SRTM_List_Remove(list);
457 /* Add to temp list */
458 SRTM_List_AddTail(&listHead, list);
459 }
460 }
461 (void)SRTM_Mutex_Unlock(disp->mutex);
462
463 /* Now free all the messages on temp list */
464 while (!SRTM_List_IsEmpty(&listHead))
465 {
466 list = listHead.next;
467 SRTM_List_Remove(list);
468 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
469 SRTM_Dispatcher_FreeMessage(disp, message);
470 }
471
472 /* Last clean up messages in PeerCore's pendingQ */
473 /* pendingQ is accessed only in dispatcher context, and now dispatcher is stopped.
474 No need to lock */
475 while (!SRTM_List_IsEmpty(&core->pendingQ))
476 {
477 list = core->pendingQ.next;
478 SRTM_List_Remove(list);
479 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
480 SRTM_Dispatcher_FreeMessage(disp, message);
481 }
482
483 return SRTM_Status_Success;
484 }
485
SRTM_Dispatcher_RegisterService(srtm_dispatcher_t disp,srtm_service_t service)486 srtm_status_t SRTM_Dispatcher_RegisterService(srtm_dispatcher_t disp, srtm_service_t service)
487 {
488 assert(disp);
489 assert(service);
490 assert(!disp->started); /* Register service when SRTM dispatcher running is forbidden */
491
492 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %d\r\n", __func__, service->category);
493
494 if (!SRTM_List_IsEmpty(&service->node))
495 {
496 return SRTM_Status_ListAddFailed;
497 }
498
499 (void)SRTM_Mutex_Lock(disp->mutex);
500 SRTM_List_AddTail(&disp->services, &service->node);
501 (void)SRTM_Mutex_Unlock(disp->mutex);
502
503 service->dispatcher = disp;
504
505 return SRTM_Status_Success;
506 }
507
SRTM_Dispatcher_UnregisterService(srtm_dispatcher_t disp,srtm_service_t service)508 srtm_status_t SRTM_Dispatcher_UnregisterService(srtm_dispatcher_t disp, srtm_service_t service)
509 {
510 assert(disp);
511 assert(service);
512 assert(!disp->started); /* Unregister service when SRTM dispatcher running is forbidden */
513
514 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: %d\r\n", __func__, service->category);
515
516 if (SRTM_List_IsEmpty(&service->node))
517 {
518 return SRTM_Status_ListRemoveFailed;
519 }
520
521 (void)SRTM_Mutex_Lock(disp->mutex);
522 SRTM_List_Remove(&service->node);
523 (void)SRTM_Mutex_Unlock(disp->mutex);
524
525 service->dispatcher = NULL;
526
527 return SRTM_Status_Success;
528 }
529
SRTM_Dispatcher_Request(srtm_dispatcher_t disp,srtm_request_t req,srtm_response_t * pResp,uint32_t timeout)530 srtm_status_t SRTM_Dispatcher_Request(srtm_dispatcher_t disp,
531 srtm_request_t req,
532 srtm_response_t *pResp,
533 uint32_t timeout)
534 {
535 srtm_sem_t signal;
536 srtm_status_t status;
537 srtm_response_t resp;
538 #if defined(SRTM_STATIC_API) && SRTM_STATIC_API
539 srtm_sem_buf_t signalStatic;
540 #endif
541
542 assert(disp);
543 assert(req);
544
545 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
546
547 #if defined(SRTM_STATIC_API) && SRTM_STATIC_API
548 signal = SRTM_Sem_Create(1U, 0U, &signalStatic);
549 #else
550 signal = SRTM_Sem_Create(1U, 0U);
551 #endif
552 if (signal == NULL)
553 {
554 return SRTM_Status_OutOfMemory;
555 }
556
557 req->reqMsg.isSyncReq = true;
558 req->reqMsg.sync.sig = signal;
559 req->reqMsg.sync.resp = NULL;
560
561 req->error = SRTM_Status_Success;
562 SRTM_Dispatcher_QueueMessage(disp, req);
563 status = SRTM_Sem_Wait(signal, timeout);
564 /* Make sure request is no longer in messageQ or waitingReqs list */
565 if (status != SRTM_Status_Success)
566 {
567 while (SRTM_Dispatcher_DequeueMessage(disp, req) != SRTM_Status_Success)
568 {
569 /* If request is not on any list, it means SRTM dispatcher is processing or just going
570 to send the response. Wait again to make sure dispatcher has put it on the
571 waitingReqs queue or properly responded */
572 if ((status = SRTM_Sem_Wait(signal, timeout)) == SRTM_Status_Success)
573 {
574 break;
575 }
576 }
577 }
578
579 /* Clean up */
580 SRTM_Sem_Destroy(signal);
581 req->reqMsg.sync.sig = NULL;
582
583 resp = req->reqMsg.sync.resp;
584 if (pResp != NULL)
585 {
586 *pResp = resp; /* Now application gets response and will destroy it later */
587 }
588
589 if (resp == NULL) /* Failed to get response */
590 {
591 status = status == SRTM_Status_Timeout ? SRTM_Status_TransferTimeout : req->error;
592 }
593 else
594 {
595 if (pResp == NULL) /* Response not needed by application */
596 {
597 SRTM_Response_Destroy(resp);
598 }
599 status = SRTM_Status_Success;
600 }
601
602 return status;
603 }
604
SRTM_Dispatcher_DeliverRequest(srtm_dispatcher_t disp,srtm_request_t req,srtm_dispatcher_resp_cb_t callback,void * param)605 srtm_status_t SRTM_Dispatcher_DeliverRequest(srtm_dispatcher_t disp,
606 srtm_request_t req,
607 srtm_dispatcher_resp_cb_t callback,
608 void *param)
609 {
610 assert(disp);
611 assert(req);
612
613 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
614
615 req->reqMsg.isSyncReq = false;
616 req->reqMsg.async.cb = callback;
617 req->reqMsg.async.param = param;
618
619 return SRTM_Dispatcher_DeliverRawData(disp, req);
620 }
621
SRTM_Dispatcher_DeliverResponse(srtm_dispatcher_t disp,srtm_response_t resp)622 srtm_status_t SRTM_Dispatcher_DeliverResponse(srtm_dispatcher_t disp, srtm_response_t resp)
623 {
624 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
625
626 return SRTM_Dispatcher_DeliverRawData(disp, resp);
627 }
628
SRTM_Dispatcher_DeliverNotification(srtm_dispatcher_t disp,srtm_notification_t notif)629 srtm_status_t SRTM_Dispatcher_DeliverNotification(srtm_dispatcher_t disp, srtm_notification_t notif)
630 {
631 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
632
633 return SRTM_Dispatcher_DeliverRawData(disp, notif);
634 }
635
SRTM_Dispatcher_DeliverRawData(srtm_dispatcher_t disp,srtm_rawdata_t data)636 srtm_status_t SRTM_Dispatcher_DeliverRawData(srtm_dispatcher_t disp, srtm_rawdata_t data)
637 {
638 assert(disp);
639 assert(data);
640
641 SRTM_Dispatcher_QueueMessage(disp, data);
642
643 return SRTM_Status_Success;
644 }
645
SRTM_Dispatcher_DeliverMessages(srtm_dispatcher_t disp,srtm_list_t * msgs)646 srtm_status_t SRTM_Dispatcher_DeliverMessages(srtm_dispatcher_t disp, srtm_list_t *msgs)
647 {
648 uint32_t primask;
649 srtm_list_t *list;
650 srtm_message_t message;
651
652 assert(disp);
653 assert(msgs);
654
655 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
656
657 primask = DisableGlobalIRQ();
658 while (!SRTM_List_IsEmpty(msgs))
659 {
660 list = msgs->next;
661 SRTM_List_Remove(list);
662 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
663 SRTM_Dispatcher_InsertOrderedMessage(disp, message);
664 }
665 EnableGlobalIRQ(primask);
666
667 (void)SRTM_Sem_Post(disp->queueSig);
668
669 return SRTM_Status_Success;
670 }
671
SRTM_Dispatcher_CallProc(srtm_dispatcher_t disp,srtm_procedure_t proc,uint32_t timeout)672 srtm_status_t SRTM_Dispatcher_CallProc(srtm_dispatcher_t disp, srtm_procedure_t proc, uint32_t timeout)
673 {
674 srtm_sem_t signal;
675 #if defined(SRTM_STATIC_API) && SRTM_STATIC_API
676 srtm_sem_buf_t signalStatic;
677 #endif
678 srtm_status_t status;
679
680 assert(disp);
681 assert(proc);
682
683 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
684
685 #if defined(SRTM_STATIC_API) && SRTM_STATIC_API
686 signal = SRTM_Sem_Create(1U, 0U, &signalStatic);
687 #else
688 signal = SRTM_Sem_Create(1U, 0U);
689 #endif
690 if (signal == NULL)
691 {
692 return SRTM_Status_OutOfMemory;
693 }
694
695 proc->procMsg.sig = signal;
696 SRTM_Dispatcher_QueueMessage(disp, proc);
697
698 status = SRTM_Sem_Wait(signal, timeout);
699 /* Make sure proc is no longer in messageQ */
700 if (status != SRTM_Status_Success)
701 {
702 while (SRTM_Dispatcher_DequeueMessage(disp, proc) != SRTM_Status_Success)
703 {
704 /* If request is not on any list, it means SRTM dispatcher is processing.
705 Wait again to make sure dispatcher has finished calling the procedure. */
706 if ((status = SRTM_Sem_Wait(signal, timeout)) == SRTM_Status_Success)
707 {
708 break;
709 }
710 }
711 }
712
713 /* Clean up */
714 SRTM_Sem_Destroy(signal);
715 proc->procMsg.sig = NULL;
716
717 return status;
718 }
719
SRTM_Dispatcher_PostProc(srtm_dispatcher_t disp,srtm_procedure_t proc)720 srtm_status_t SRTM_Dispatcher_PostProc(srtm_dispatcher_t disp, srtm_procedure_t proc)
721 {
722 assert(disp);
723 assert(proc);
724
725 proc->procMsg.sig = NULL;
726 SRTM_Dispatcher_QueueMessage(disp, proc);
727
728 return SRTM_Status_Success;
729 }
730
SRTM_Dispatcher_PostRecvData(srtm_dispatcher_t disp,srtm_channel_t channel,void * buf,uint32_t len)731 srtm_status_t SRTM_Dispatcher_PostRecvData(srtm_dispatcher_t disp, srtm_channel_t channel, void *buf, uint32_t len)
732 {
733 srtm_list_t *list;
734 srtm_message_t message = NULL;
735 uint32_t primask;
736 srtm_packet_head_t *head;
737
738 assert(disp);
739 assert(channel);
740 assert(buf);
741
742 if (len < sizeof(struct _srtm_packet_head) || len > SRTM_DISPATCHER_CONFIG_RX_MSG_MAX_LEN)
743 {
744 return SRTM_Status_InvalidParameter;
745 }
746
747 /* Get free message to save the data */
748 primask = DisableGlobalIRQ();
749 if (!SRTM_List_IsEmpty(&disp->freeRxMsgs))
750 {
751 list = disp->freeRxMsgs.next;
752 SRTM_List_Remove(list);
753 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
754 }
755 EnableGlobalIRQ(primask);
756
757 assert(message); /* For debugging the shortage of RX buffer */
758
759 if (message != NULL)
760 {
761 message->direct = SRTM_MessageDirectRx;
762 (void)memcpy(message->data, buf, len);
763 message->dataLen = len;
764 message->channel = channel;
765 message->error = SRTM_Status_Success;
766
767 head = (srtm_packet_head_t *)buf;
768 message->type = (srtm_message_type_t)head->type;
769 message->priority = head->priority;
770
771 SRTM_Dispatcher_QueueMessage(disp, message);
772
773 return SRTM_Status_Success;
774 }
775
776 return SRTM_Status_OutOfMemory;
777 }
778
SRTM_Dispatcher_CallService(srtm_dispatcher_t disp,srtm_message_t msg)779 static srtm_status_t SRTM_Dispatcher_CallService(srtm_dispatcher_t disp, srtm_message_t msg)
780 {
781 srtm_list_t *list;
782 srtm_service_t service;
783 uint8_t category;
784 srtm_status_t status = SRTM_Status_ServiceNotFound;
785
786 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
787
788 category = SRTM_CommMessage_GetCategory(msg);
789
790 /* Don't need to lock mutex because service will not change when dispatcher is running */
791 for (list = disp->services.next; list != &disp->services; list = list->next)
792 {
793 service = SRTM_LIST_OBJ(srtm_service_t, node, list);
794 if (service->category == category)
795 {
796 if (msg->type == SRTM_MessageTypeRequest)
797 {
798 status = SRTM_Service_Request(service, msg);
799 }
800 else
801 {
802 status = SRTM_Service_Notify(service, msg);
803 }
804 break;
805 }
806 }
807
808 return status;
809 }
810
SRTM_Dispatcher_HandleResponse(srtm_dispatcher_t disp,srtm_message_t msg)811 static srtm_status_t SRTM_Dispatcher_HandleResponse(srtm_dispatcher_t disp, srtm_message_t msg)
812 {
813 srtm_list_t *list;
814 srtm_request_t req = NULL;
815 srtm_response_t resp;
816 uint8_t category;
817 uint8_t command;
818 srtm_status_t status = SRTM_Status_Success;
819
820 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
821
822 category = SRTM_CommMessage_GetCategory(msg);
823 command = SRTM_CommMessage_GetCommand(msg);
824
825 (void)SRTM_Mutex_Lock(disp->mutex);
826 for (list = disp->waitingReqs.next; list != &disp->waitingReqs; list = list->next)
827 {
828 req = SRTM_LIST_OBJ(srtm_request_t, node, list);
829 if (SRTM_CommMessage_GetCategory(req) == category && SRTM_CommMessage_GetCommand(req) == command &&
830 req->channel == msg->channel) /* FIXME: need a UID? */
831 {
832 SRTM_List_Remove(list);
833 break;
834 }
835 }
836 (void)SRTM_Mutex_Unlock(disp->mutex);
837
838 if ((req != NULL) && (list != &disp->waitingReqs)) /* Find corresponding request */
839 {
840 if (req->reqMsg.isSyncReq)
841 {
842 resp = SRTM_Message_Duplicate(msg);
843 if (resp != NULL)
844 {
845 if (msg->dataLen > 0U)
846 {
847 (void)memcpy(resp->data, msg->data, msg->dataLen);
848 }
849 /* Duplicated response will be freed by application */
850 req->reqMsg.sync.resp = resp;
851 }
852 else
853 {
854 req->error = SRTM_Status_OutOfMemory;
855 }
856 (void)SRTM_Sem_Post(req->reqMsg.sync.sig);
857 }
858 else
859 {
860 if (req->reqMsg.async.cb != NULL)
861 {
862 req->reqMsg.async.cb(disp, req, msg, req->reqMsg.async.param);
863 }
864 /* Request is destroyed in dispatcher for async call */
865 SRTM_Request_Destroy(req);
866 }
867 }
868 else
869 {
870 status = SRTM_Status_Error;
871 }
872
873 return status;
874 }
875
SRTM_Dispatcher_SendMessage(srtm_dispatcher_t disp,srtm_message_t msg)876 static srtm_status_t SRTM_Dispatcher_SendMessage(srtm_dispatcher_t disp, srtm_message_t msg)
877 {
878 srtm_status_t status;
879
880 status = SRTM_Channel_SendData(msg->channel, msg->data, msg->dataLen);
881 assert(status == SRTM_Status_Success); /* For debugging the message sending failure */
882
883 switch (msg->type)
884 {
885 case SRTM_MessageTypeRawData:
886 SRTM_RawData_Destroy(msg);
887 break;
888 case SRTM_MessageTypeRequest:
889 if (status == SRTM_Status_Success)
890 {
891 /* Add request to waiting queue to wait for response */
892 (void)SRTM_Mutex_Lock(disp->mutex);
893 SRTM_List_AddTail(&disp->waitingReqs, &msg->node);
894 (void)SRTM_Mutex_Unlock(disp->mutex);
895 }
896 else
897 {
898 SRTM_Dispatcher_FreeRequest(disp, msg, SRTM_Status_TransferFailed);
899 }
900 break;
901 case SRTM_MessageTypeResponse:
902 SRTM_Response_Destroy(msg);
903 break;
904 case SRTM_MessageTypeNotification:
905 SRTM_Notification_Destroy(msg);
906 break;
907 default:
908 /* Do nothing */
909 break;
910 }
911
912 return status;
913 }
914
SRTM_Dispatcher_HandleTxMessage(srtm_dispatcher_t disp,srtm_message_t msg)915 static srtm_status_t SRTM_Dispatcher_HandleTxMessage(srtm_dispatcher_t disp, srtm_message_t msg)
916 {
917 srtm_status_t status = SRTM_Status_Success;
918 srtm_peercore_t core;
919 srtm_peercore_state_t state;
920 srtm_list_t *list;
921 srtm_message_t message;
922
923 assert(msg->channel);
924 assert(msg->channel->core);
925
926 core = msg->channel->core;
927 state = SRTM_PeerCore_GetState(core);
928
929 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
930
931 switch (state)
932 {
933 case SRTM_PeerCore_State_Inactive:
934 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "SRTM_PeerCore_State_Inactive\r\n");
935 /* Peer core not active, discard the message */
936 SRTM_Dispatcher_FreeMessage(disp, msg);
937 break;
938 case SRTM_PeerCore_State_Activating:
939 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "SRTM_PeerCore_State_Activating\r\n");
940 /* Peer core in activating, put message to pendingQ */
941 SRTM_List_AddTail(&core->pendingQ, &msg->node);
942 break;
943 case SRTM_PeerCore_State_Activated:
944 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "SRTM_PeerCore_State_Activated\r\n");
945 /* Peer core working well, first send messages in pendingQ and then send the msg */
946 while (!SRTM_List_IsEmpty(&core->pendingQ))
947 {
948 list = core->pendingQ.next;
949 SRTM_List_Remove(list);
950 message = SRTM_LIST_OBJ(srtm_message_t, node, list);
951 (void)SRTM_Dispatcher_SendMessage(disp, message);
952 }
953 status = SRTM_Dispatcher_SendMessage(disp, msg);
954 break;
955 case SRTM_PeerCore_State_Deactivating:
956 case SRTM_PeerCore_State_Deactivated:
957 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "SRTM_PeerCore_State_Deactivate\r\n");
958 /* Peer core in deactivate state, put message to pendingQ and activate peer core */
959 SRTM_List_AddTail(&core->pendingQ, &msg->node);
960 status = SRTM_PeerCore_Activate(core);
961 break;
962 default:
963 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: wrong peer core state!\r\n", __func__);
964 break;
965 }
966
967 return status;
968 }
969
SRTM_Dispatcher_ProcessMessage(srtm_dispatcher_t disp,srtm_message_t msg)970 srtm_status_t SRTM_Dispatcher_ProcessMessage(srtm_dispatcher_t disp, srtm_message_t msg)
971 {
972 srtm_status_t status = SRTM_Status_Success;
973
974 assert(disp);
975 assert(msg);
976
977 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s\r\n", __func__);
978
979 SRTM_DumpMessage(msg);
980
981 if (msg->direct == SRTM_MessageDirectRx)
982 {
983 switch (msg->type)
984 {
985 case SRTM_MessageTypeRequest:
986 case SRTM_MessageTypeNotification:
987 status = SRTM_Dispatcher_CallService(disp, msg);
988 break;
989 case SRTM_MessageTypeResponse:
990 status = SRTM_Dispatcher_HandleResponse(disp, msg);
991 break;
992 default:
993 /* We cannot handle message other than Communication Message */
994 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: unsupported RX message type %d\r\n", __func__,
995 msg->type);
996 break;
997 }
998 SRTM_Dispatcher_FreeMessage(disp, msg);
999 }
1000 else /* TX message or procedure message */
1001 {
1002 switch (msg->type)
1003 {
1004 case SRTM_MessageTypeProcedure:
1005 SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_DEBUG, "%s: Callback procedure 0x%08x\r\n", __func__,
1006 msg->procMsg.cb);
1007 msg->procMsg.cb(disp, msg->procMsg.param1, msg->procMsg.param2);
1008 if (msg->procMsg.sig != NULL) /* Called by SRTM_Dispatcher_CallProc() */
1009 {
1010 /* Synchronous procedure message will be freed by user. Here just wakeup user's task. */
1011 (void)SRTM_Sem_Post(msg->procMsg.sig);
1012 }
1013 else /* Called by SRTM_Dispatcher_PostProc() */
1014 {
1015 SRTM_Procedure_Destroy(msg);
1016 }
1017 break;
1018 default:
1019 status = SRTM_Dispatcher_HandleTxMessage(disp, msg);
1020 break;
1021 }
1022 }
1023
1024 return status;
1025 }
1026