1 /*------------------------------------------------------------------------------------------------*/
2 /* UNICENS V2.1.0-3491 */
3 /* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG. */
5 /* This program is free software: you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation, either version 2 of the License, or */
8 /* (at your option) any later version. */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* You may also obtain this software under a propriety license from Microchip. */
19 /* Please contact Microchip for further information. */
20 /*------------------------------------------------------------------------------------------------*/
24 * \brief Implementation of Port Message FIFO
26 * \cond UCS_INTERNAL_DOC
31 /*------------------------------------------------------------------------------------------------*/
33 /*------------------------------------------------------------------------------------------------*/
34 #include "ucs_pmfifo.h"
36 #include "ucs_pmcmd.h"
39 /*------------------------------------------------------------------------------------------------*/
41 /*------------------------------------------------------------------------------------------------*/
42 /*------------------------------------------------------------------------------------------------*/
43 /* Internal Constants */
44 /*------------------------------------------------------------------------------------------------*/
45 static const uint8_t FIFO_SRV_PRIO = 252U; /* parasoft-suppress MISRA2004-8_7 "configuration property" */
46 static const Srv_Event_t FIFO_SE_RX_SERVICE = 1U; /*!< \brief Event which triggers the Rx service */
47 static const Srv_Event_t FIFO_SE_TX_SERVICE = 2U; /*!< \brief Event which triggers the Rx service */
48 static const Srv_Event_t FIFO_SE_TX_APPLY_STATUS = 4U; /*!< \brief Event which triggers to apply the current INIC status */
49 static const Srv_Event_t FIFO_SE_ALL = 7U; /* parasoft-suppress MISRA2004-8_7 "configuration property" */
51 /*------------------------------------------------------------------------------------------------*/
52 /* Internal prototypes */
53 /*------------------------------------------------------------------------------------------------*/
54 static void Fifo_InitCounters(CPmFifo *self, uint8_t tx_sid_complete, uint8_t tx_credits);
55 static void Fifo_Service(void *self);
57 static void Fifo_RxService(CPmFifo *self);
58 static void Fifo_RxCheckStatusTrigger(CPmFifo *self);
59 static void Fifo_RxGetCredit(CPmFifo *self);
60 static void Fifo_RxReleaseCredit(CPmFifo *self);
61 static bool Fifo_RxProcessData(CPmFifo *self, CMessage *msg_ptr);
62 static void Fifo_RxProcessStatus(CPmFifo *self, CMessage *msg_ptr);
63 static void Fifo_RxProcessCommand(CPmFifo *self, CMessage *msg_ptr);
64 static void Fifo_RxProcessSyncStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code, uint8_t *header_ptr);
65 static uint8_t Fifo_RxCheckFailureCode(CPmFifo *self, uint8_t failure_code);
66 static void Fifo_OnRx(void *self, CMessage *msg_ptr);
68 static void Fifo_TxService(CPmFifo *self);
69 static void Fifo_TxProcessData(CPmFifo *self);
70 static void Fifo_TxProcessStatus(CPmFifo *self);
71 static void Fifo_TxProcessCommand(CPmFifo *self);
73 static void Fifo_TxEnqueueBypassMsg(CPmFifo *self, CDlList *q_ptr, CMessage *msg_ptr);
74 static bool Fifo_FindFirstRegularMsg(void *d_ptr, void *ud_ptr);
76 static void Fifo_TxExecuteCancel(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code);
77 static void Fifo_TxExecuteCancelAll(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code);
78 static void Fifo_TxFinishedCancelAll(CPmFifo *self);
79 static uint8_t Fifo_TxPendingGetFollowerId(CPmFifo *self);
80 static void Fifo_TxCancelFollowers(CPmFifo *self, uint8_t follower_id, Ucs_MsgTxStatus_t status);
82 static bool Fifo_TxHasAccessPending(CPmFifo *self);
83 static void Fifo_TxRestorePending(CPmFifo *self);
85 static void Fifo_TxOnWatchdogTimer(void *self);
86 static void Fifo_TxStartWatchdog(CPmFifo *self);
88 static uint8_t Fifo_TxGetValidAcknowledges(CPmFifo *self, uint8_t sid);
89 static bool Fifo_TxNotifyStatus(CPmFifo *self, uint8_t sid, Ucs_MsgTxStatus_t status);
90 static void Fifo_TxApplyCurrentStatus(CPmFifo *self);
91 static void Fifo_TxUpdateCurrentStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code);
92 static bool Fifo_TxIsIncomingSidValid(CPmFifo *self, uint8_t sid);
94 /*------------------------------------------------------------------------------------------------*/
96 /*------------------------------------------------------------------------------------------------*/
97 /*! \brief Constructor of message FIFO
98 * \param self The instance
99 * \param init_ptr Reference to initialization data
100 * \param config_ptr Reference to configuration
102 void Fifo_Ctor(CPmFifo *self, const Fifo_InitData_t *init_ptr, const Fifo_Config_t *config_ptr)
104 MISC_MEM_SET(self, 0, sizeof(*self));
106 self->init = *init_ptr;
107 self->config = *config_ptr;
109 self->sync_state = FIFO_S_UNSYNCED_INIT; /* initialize members */
110 Sub_Ctor(&self->sync_state_subject, self->init.base_ptr->ucs_user_ptr);
112 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_Ctor(): state: %u", 1U, self->sync_state));
114 Srv_Ctor(&self->service, FIFO_SRV_PRIO, self, &Fifo_Service); /* registration of service */
115 (void)Scd_AddService(&self->init.base_ptr->scd, &self->service);
117 T_Ctor(&self->wd.timer); /* setup watchdog */
118 self->wd.timer_value = self->config.tx_wd_timer_value;
119 Pmcmd_Ctor(&self->wd.wd_cmd, self->config.fifo_id, PMP_MSG_TYPE_CMD);
120 Pmcmd_SetContent(&self->wd.wd_cmd, 0U, PMP_CMD_TYPE_REQ_STATUS, PMP_CMD_CODE_REQ_STATUS, NULL, 0U);
123 Dl_Ctor(&self->rx.queue, self->init.base_ptr->ucs_user_ptr);
124 self->rx.encoder_ptr = self->init.rx_encoder_ptr;
125 self->rx.on_complete_fptr = self->init.rx_cb_fptr;
126 self->rx.on_complete_inst = self->init.rx_cb_inst;
128 self->rx.ack_threshold = self->config.rx_threshold;
130 if (self->config.rx_threshold > self->config.rx_credits)/* configuration error - use single acknowledge */
132 self->rx.ack_threshold = 1U;
133 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]");
136 self->rx.wait_processing = false;
137 Pmcmd_Ctor(&self->rx.status, self->config.fifo_id, PMP_MSG_TYPE_STATUS);
138 Pmcmd_SetContent(&self->rx.status, 0U, PMP_STATUS_TYPE_FLOW, PMP_STATUS_CODE_SUCCESS, NULL, 0U);
141 Dl_Ctor(&self->tx.waiting_queue, self->init.base_ptr->ucs_user_ptr);
142 Dl_Ctor(&self->tx.pending_q, self->init.base_ptr->ucs_user_ptr);
144 Pmcmd_Ctor(&self->tx.cancel_cmd, self->config.fifo_id, PMP_MSG_TYPE_CMD);
145 Pmcmd_SetContent(&self->tx.cancel_cmd, 0U, PMP_CMD_TYPE_MSG_ACTION, PMP_CMD_CODE_ACTION_CANCEL, NULL, 0U);
147 Fifo_InitCounters(self, 0U, 0U); /* values are incremented on each sync attempt */
148 self->tx.encoder_ptr = init_ptr->tx_encoder_ptr;
150 /* FIFO synchronization command */
151 self->sync_cnt = 0xFFU;
152 self->sync_params[0] = config_ptr->rx_credits;
153 self->sync_params[1] = config_ptr->rx_busy_allowed;
154 self->sync_params[2] = config_ptr->rx_ack_timeout;
155 self->sync_params[3] = config_ptr->tx_wd_timeout;
156 Pmcmd_Ctor(&self->tx.sync_cmd, self->config.fifo_id, PMP_MSG_TYPE_CMD);
157 Pmcmd_SetContent(&self->tx.sync_cmd, 0U, PMP_CMD_TYPE_SYNCHRONIZATION, PMP_CMD_CODE_SYNC, self->sync_params, 4U);
159 /* default PM header for Tx */
160 self->tx.pm_header.pml = 6U;
161 self->tx.pm_header.pmhl = self->tx.encoder_ptr->pm_hdr_sz - 3U;
162 Pmh_SetFph(&self->tx.pm_header, self->config.fifo_id, PMP_MSG_TYPE_DATA);
163 self->tx.pm_header.sid = 0U;
164 self->tx.pm_header.ext_type = (uint8_t)self->tx.encoder_ptr->content_type;
166 Lldp_Ctor(&self->tx.lld_pool, self, self->init.base_ptr->ucs_user_ptr);
168 Pmch_RegisterReceiver(self->init.channel_ptr, self->config.fifo_id, &Fifo_OnRx, self);
171 /*! \brief Initializes flow control and related counters
172 * \param self The instance
173 * \param tx_sid_complete Reference to initialization data
174 * \param tx_credits Number of credits for Tx
176 static void Fifo_InitCounters(CPmFifo *self, uint8_t tx_sid_complete, uint8_t tx_credits)
178 self->rx.busy_num = 0U;
179 self->rx.expected_sid = tx_sid_complete + 1U;
180 self->rx.ack_last_ok_sid = tx_sid_complete;
182 self->tx.credits = tx_credits;
183 self->tx.sid_next_to_use = tx_sid_complete +1U;
184 self->tx.sid_last_completed = tx_sid_complete;
186 self->tx.failure_status = 0U;
187 self->tx.failure_sid = 0U;
189 self->tx.current_sid = tx_sid_complete;
190 self->tx.current_type = PMP_STATUS_TYPE_FLOW;
191 self->tx.current_code = (uint8_t)PMP_STATUS_CODE_SUCCESS;
194 /*! \brief Adds an observer of synchronization state changes
195 * \param self The instance
196 * \param obs_ptr The observer. The notification result type is \ref Pmp_FifoId_t.
198 void Fifo_AddStateObserver(CPmFifo *self, CObserver *obs_ptr)
200 (void)Sub_AddObserver(&self->sync_state_subject, obs_ptr);
203 /*! \brief Removes an observer of synchronization state changes
204 * \param self The instance
205 * \param obs_ptr The observer.
207 void Fifo_RemoveStateObserver(CPmFifo *self, CObserver *obs_ptr)
209 (void)Sub_RemoveObserver(&self->sync_state_subject, obs_ptr);
212 /*! \brief Stops execution of a FIFO and notifies sync lost if necessary
213 * \param self The instance
214 * \param new_state The new synchronization state
215 * \param allow_notification Set to \c false in order to avoid recursion
217 void Fifo_Stop(CPmFifo *self, Fifo_SyncState_t new_state, bool allow_notification)
221 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_Stop(): FIFO: %u, state: %u, new_state: %u", 3U, self->config.fifo_id, self->sync_state, new_state));
223 if (self->sync_state != new_state)
228 self->sync_state = new_state;
229 self->tx.credits = 0U;
231 if (self->wd.timer_value != 0U)
233 Tm_ClearTimer(&self->init.base_ptr->tm, &self->wd.timer);
236 if ((notify != false) && (allow_notification != false))
238 Sub_Notify(&self->sync_state_subject, &self->config.fifo_id);
242 /*! \brief Releases all external references
243 * \details It is important to call Fifo_Stop() prior to this functions. The low-level driver
244 * must be stopped as well to avoid concurrent access to message objects.
245 * \param self The instance
247 void Fifo_Cleanup(CPmFifo *self)
249 CMessage *msg_ptr = NULL;
250 CDlNode *node_ptr = NULL;
252 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (self->sync_state == FIFO_S_UNSYNCED_INIT));
253 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_Cleanup(): FIFO: %u", 1U, self->config.fifo_id));
255 /* cleanup pending queue */
256 for (node_ptr = Dl_PopHead(&self->tx.pending_q); node_ptr != NULL; node_ptr = Dl_PopHead(&self->tx.pending_q))
258 msg_ptr = (CMessage*)Dln_GetData(node_ptr);
260 Msg_NotifyTxStatus(msg_ptr, UCS_MSG_STAT_ERROR_SYNC);
261 Lldp_ReturnTxToPool(&self->tx.lld_pool, (Lld_IntTxMsg_t*)Msg_GetLldHandle(msg_ptr));
262 Msg_SetLldHandle(msg_ptr, NULL); /* remove link to LLD message object */
265 /* cleanup waiting queue */
266 for (node_ptr = Dl_PopHead(&self->tx.waiting_queue); node_ptr != NULL; node_ptr = Dl_PopHead(&self->tx.waiting_queue))
268 msg_ptr = (CMessage*)Dln_GetData(node_ptr);
270 Msg_NotifyTxStatus(msg_ptr, UCS_MSG_STAT_ERROR_SYNC);
273 /* cleanup Rx queue */
274 for (node_ptr = Dl_PopHead(&self->rx.queue); node_ptr != NULL; node_ptr = Dl_PopHead(&self->rx.queue))
276 msg_ptr = (CMessage*)Dln_GetData(node_ptr);
278 Pmch_ReturnRxToPool(self->init.channel_ptr, msg_ptr);
281 Srv_ClearEvent(&self->service, FIFO_SE_ALL);
285 /*! \brief Service function of FIFO
286 * \details The processing order of Rx followed by Tx is important for Fifo_RxProcessCommand()
287 * \param self The instance
289 static void Fifo_Service(void *self)
291 CPmFifo *self_ = (CPmFifo*)self;
292 Srv_Event_t event_mask;
294 Srv_GetEvent(&self_->service, &event_mask);
296 if(FIFO_SE_RX_SERVICE == (event_mask & FIFO_SE_RX_SERVICE)) /* Is event pending? */
298 Srv_ClearEvent(&self_->service, FIFO_SE_RX_SERVICE);
299 Fifo_RxService(self_);
302 if((event_mask & FIFO_SE_TX_APPLY_STATUS) == FIFO_SE_TX_APPLY_STATUS)
304 Srv_ClearEvent(&self_->service, FIFO_SE_TX_APPLY_STATUS);
305 Fifo_TxApplyCurrentStatus(self_);
308 if(FIFO_SE_TX_SERVICE == (event_mask & FIFO_SE_TX_SERVICE)) /* Is event pending? */
310 Srv_ClearEvent(&self_->service, FIFO_SE_TX_SERVICE);
311 Fifo_TxService(self_);
315 /*------------------------------------------------------------------------------------------------*/
316 /* Tx Implementation */
317 /*------------------------------------------------------------------------------------------------*/
318 /*! \brief Enqueues a message for transmission
319 * \param self The instance
320 * \param msg_ptr The Tx message object
321 * \param bypass Use \c true if the message shall bypass all other messages
322 * in the FIFO. Otherwise \c false.
324 void Fifo_Tx(CPmFifo *self, CMessage *msg_ptr, bool bypass)
326 uint8_t *msg_hdr_ptr = NULL;
328 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (msg_ptr != NULL));
329 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_Tx(): FIFO: %u, msg_ptr: 0x%p, FuncId: 0x%X, queued Tx message", 3U, self->config.fifo_id, msg_ptr, msg_ptr->pb_msg.id.function_id));
331 Msg_PullHeader(msg_ptr, self->tx.encoder_ptr->msg_hdr_sz);
332 msg_hdr_ptr = Msg_GetHeader(msg_ptr);
333 self->tx.encoder_ptr->encode_fptr(Msg_GetMostTel(msg_ptr), msg_hdr_ptr);
337 Dl_InsertTail(&self->tx.waiting_queue, Msg_GetNode(msg_ptr)); /* enqueue message for asynchronous transmission */
341 Fifo_TxEnqueueBypassMsg(self, &self->tx.waiting_queue, msg_ptr); /* queue before first non-bypass message */
344 Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
347 /*! \brief Enqueues a bypass message between the last bypass and the first regular message in a queue
348 * \param self The instance
349 * \param q_ptr The message queue
350 * \param msg_ptr The Tx message object
352 static void Fifo_TxEnqueueBypassMsg(CPmFifo *self, CDlList *q_ptr, CMessage *msg_ptr)
354 CDlNode *node_ptr = Dl_Foreach(q_ptr, &Fifo_FindFirstRegularMsg, NULL); /* find first "non-bypass" message */
355 Msg_SetTxBypass(msg_ptr, true); /* mark new message as bypass message */
357 if (node_ptr == NULL) /* no message or only bypass messages found */
359 Dl_InsertTail(&self->tx.waiting_queue, Msg_GetNode(msg_ptr)); /* enqueue message to tail */
361 else /* first "non-bypass" message is found */
362 { /* insert the bypass message before the first regular message found */
363 Dl_InsertBefore(&self->tx.waiting_queue, node_ptr, Msg_GetNode(msg_ptr));
367 /*! \brief Required as "for-each" function to find the first "regular message"
368 * \param d_ptr Points to a message object in the queue
369 * \param ud_ptr Unused data reference, always \c NULL
370 * \return Returns \c true if a regular (non-bypass) message is found.
372 static bool Fifo_FindFirstRegularMsg(void *d_ptr, void *ud_ptr)
377 if (Msg_IsTxBypass((CMessage*)d_ptr))
385 /*! \brief Processing of data, status and command messages
386 * \param self The instance
388 static void Fifo_TxService(CPmFifo *self)
390 Fifo_TxProcessCommand(self);
391 Fifo_TxProcessStatus(self);
392 Fifo_TxProcessData(self);
395 /*! \brief Processing of status messages
396 * \param self The instance
398 static void Fifo_TxProcessStatus(CPmFifo *self)
400 if (Pmcmd_IsTriggered(&self->rx.status) != false)
402 if (Pmcmd_Reserve(&self->rx.status) != false)
404 Pmcmd_SetTrigger(&self->rx.status, false);
405 self->rx.ack_last_ok_sid = (self->rx.expected_sid - self->rx.busy_num) - 1U;
406 self->rx.wait_processing = false;
408 if (self->rx.busy_num == 0U) /* currently no processing of data messages active */
409 { /* notify the latest with SUCCESS */
410 Pmcmd_UpdateContent(&self->rx.status, self->rx.expected_sid - 1U, PMP_STATUS_TYPE_FLOW, PMP_STATUS_CODE_SUCCESS);
412 else /* message processing is active */
413 { /* notify code busy according to remaining credits */
414 Pmcmd_UpdateContent(&self->rx.status, self->rx.expected_sid - self->rx.busy_num, PMP_STATUS_TYPE_FLOW, PMP_STATUS_CODE_BUSY);
417 Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->rx.status));
422 /*! \brief Processing of queued data messages
423 * \param self The instance
425 static void Fifo_TxProcessData(CPmFifo *self)
427 /* process all queued messages as long as credits are available,
428 * process all queued messages if FIFO is not synced
430 while ((self->tx.cancel_all_running == false) && (self->tx.credits > 0U))
432 CMessage *msg_ptr = NULL;
433 CDlNode *node_ptr = NULL;
434 uint8_t *msg_hdr_ptr = NULL;
435 Lld_IntTxMsg_t *lld_tx_ptr = NULL;
437 node_ptr = Dl_PopHead(&self->tx.waiting_queue); /* get message node */
438 if (node_ptr == NULL)
440 msg_ptr = NULL; /* stop processing - no further messages in queue */
444 msg_ptr = (CMessage*)Dln_GetData(node_ptr); /* get message object */
446 if (self->sync_state != FIFO_S_SYNCED)
448 Msg_NotifyTxStatus(msg_ptr, UCS_MSG_STAT_ERROR_SYNC); /* notify sync error while not synced */
452 lld_tx_ptr = Lldp_GetTxFromPool(&self->tx.lld_pool);
453 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (msg_ptr != NULL));
454 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (lld_tx_ptr != NULL));
455 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxProcessData(): FIFO: %u, msg_ptr: 0x%p, FuncId: 0x%X, SID: 0x%02X, queued Tx message", 4U, self->config.fifo_id, msg_ptr, msg_ptr->pb_msg.id.function_id, self->tx.sid_next_to_use));
457 Msg_SetLldHandle(msg_ptr, lld_tx_ptr); /* link message objects */
458 lld_tx_ptr->msg_ptr = msg_ptr;
460 Msg_PullHeader(msg_ptr, self->tx.encoder_ptr->pm_hdr_sz); /* get PM header pointer */
461 msg_hdr_ptr = Msg_GetHeader(msg_ptr);
464 uint8_t tel_length = Msg_GetMostTel(msg_ptr)->tel.tel_len;
465 self->tx.pm_header.pml = (Msg_GetHeaderSize(msg_ptr) + tel_length) - 2U;
468 self->tx.pm_header.sid = self->tx.sid_next_to_use; /* assign SeqID */
469 self->tx.sid_next_to_use++;
471 Pmh_BuildHeader(&self->tx.pm_header, msg_hdr_ptr); /* build PM header */
472 lld_tx_ptr->lld_msg.memory_ptr = Msg_GetMemTx(msg_ptr);
474 Msg_SetTxActive(msg_ptr, true);
475 Dl_InsertTail(&self->tx.pending_q, Msg_GetNode(msg_ptr));
477 Pmch_Transmit(self->init.channel_ptr, (Ucs_Lld_TxMsg_t*)(void*)lld_tx_ptr);
484 /*! \brief Processing of status messages
485 * \param self The instance
487 static void Fifo_TxProcessCommand(CPmFifo *self)
489 if (Pmcmd_IsTriggered(&self->tx.sync_cmd) != false)
491 if (Pmcmd_Reserve(&self->tx.sync_cmd) != false)
493 Pmcmd_SetTrigger(&self->tx.sync_cmd, false);
495 if (self->sync_state == FIFO_S_SYNCING)
498 Pmcmd_SetContent(&self->tx.sync_cmd, self->sync_cnt, PMP_CMD_TYPE_SYNCHRONIZATION, PMP_CMD_CODE_SYNC, self->sync_params, 4U);
499 Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.sync_cmd));
501 else if (self->sync_state == FIFO_S_UNSYNCING)
503 Pmcmd_SetContent(&self->tx.sync_cmd, 0U, PMP_CMD_TYPE_SYNCHRONIZATION, PMP_CMD_CODE_UNSYNC, NULL, 0U);
504 Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.sync_cmd));
508 Pmcmd_Release(&self->tx.sync_cmd);
509 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]");
514 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]");
519 /*! \brief Releases a LLD Tx message object
520 * \param self The instance
521 * \param handle_ptr The unused LLD Tx message object
522 * \details If Fifo_TxApplyStatus() is waiting for a message object
525 void Fifo_TxOnRelease(void *self, Ucs_Lld_TxMsg_t *handle_ptr)
527 CPmFifo *self_ = (CPmFifo*)self;
528 Lld_IntTxMsg_t *tx_ptr = (Lld_IntTxMsg_t*)(void*)handle_ptr;
530 if (tx_ptr->msg_ptr != NULL)
532 Msg_SetTxActive(tx_ptr->msg_ptr, false);
536 TR_FAILED_ASSERT(self_->init.base_ptr->ucs_user_ptr, "[FIFO]");
539 if (self_->tx.status_waiting_release != false)
541 self_->tx.status_waiting_release = false;
542 Srv_SetEvent(&self_->service, (FIFO_SE_TX_APPLY_STATUS | FIFO_SE_TX_SERVICE));
546 /*! \brief Triggers a command CANCEL_ALL and stops further Tx processing
547 * \details CANCEL_ALL shall be called only, if the front-most pending message
548 * has followers (is segmented, i.e. \c cancel_id > 0). Use command CANCEL
549 * if the front-most message has no followers (\c cancel_id == NULL).
550 * \param self The instance
551 * \param failure_sid The failure sid
552 * \param failure_code The failure code reported by the INIC
554 static void Fifo_TxExecuteCancelAll(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code)
556 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxExecuteCancelAll(): FIFO: %u, SID: %u, Code: %u", 3U, self->config.fifo_id, failure_sid, failure_code));
558 if (Pmcmd_Reserve(&self->tx.cancel_cmd) != false) /* prepare cancel command */
560 Pmcmd_UpdateContent(&self->tx.cancel_cmd, self->tx.current_sid,
561 PMP_CMD_TYPE_MSG_ACTION, PMP_CMD_CODE_ACTION_CANCEL_ALL);
562 Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.cancel_cmd));
566 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]"); /* Unable to reserve cancel command */
569 self->tx.cancel_all_running = true;
570 self->tx.failure_sid = failure_sid;
571 self->tx.failure_status = failure_code;
574 /*! \brief Shall be called if the command CANCEL_ALL was processed completely
575 * \param self The instance
576 * \details Since the CANCEL_ALL is used to cancel the front-most message and
577 * all of its followers (same cancel_id)
579 for mid-level retries, the canceled messages
580 * are moved from the processing_q to the waiting_q again. The MLR timer is
581 * started. As soon as the timer elapses, Tx processing is continued again.
582 * If the front-most message has a follower id, all pending messages are
583 * moved to the waiting queue and all messages with the same follower id
584 * are notified as failed.
586 static void Fifo_TxFinishedCancelAll(CPmFifo *self)
588 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxFinishedCancelAll(): FIFO: %u, FailureStatus: %u,", 2U, self->config.fifo_id, self->tx.failure_status));
590 if (self->tx.failure_status != 0U) /* avoid multiple execution of the same CANCELED status */
591 { /* and all of its followers */
592 uint8_t follower_id = Fifo_TxPendingGetFollowerId(self);
593 Fifo_TxRestorePending(self); /* move remaining messages to waiting_q */
594 Fifo_TxCancelFollowers(self, follower_id, (Ucs_MsgTxStatus_t)self->tx.failure_status);
595 /* notify front-most and message and all of its followers */
596 self->tx.cancel_all_running = false; /* continue with Tx processing */
597 self->tx.failure_sid = 0U;
598 self->tx.failure_status = 0U;
599 Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
603 /*! \brief Triggers a command CANCEL while Tx processing continues
604 * \param self The instance
605 * \param failure_sid The failure sid
606 * \param failure_code The failure code reported by the INIC
608 static void Fifo_TxExecuteCancel(CPmFifo *self, uint8_t failure_sid, uint8_t failure_code)
610 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxExecuteCancel(): FIFO: %u, SID: %u, Code: %u", 3U, self->config.fifo_id, failure_sid, failure_code));
612 if (Pmcmd_Reserve(&self->tx.cancel_cmd) != false)
614 Pmcmd_UpdateContent(&self->tx.cancel_cmd, self->tx.current_sid,
615 PMP_CMD_TYPE_MSG_ACTION, PMP_CMD_CODE_ACTION_CANCEL);
616 Pmch_Transmit(self->init.channel_ptr, Pmcmd_GetLldTxObject(&self->tx.cancel_cmd));
620 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]"); /* Unable to reserve cancel command */
623 self->tx.cancel_all_running = false;
624 self->tx.failure_sid = failure_sid;
625 self->tx.failure_status = failure_code;
628 /*! \brief Checks if the LLD has released all messages in the pending_q
629 * \param self The instance
630 * \return Returns \c true if all messages are released by the LLD, otherwise \c false.
632 static bool Fifo_TxHasAccessPending(CPmFifo *self)
635 CDlNode *node_ptr = Dl_PeekTail(&self->tx.pending_q); /* if the tail is not active, then all */
636 /* pending message are not active */
637 if (node_ptr != NULL)
639 CMessage *msg_ptr = (CMessage*)Dln_GetData(node_ptr);
641 if (Msg_IsTxActive(msg_ptr) != false)
643 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxHasAccessPending(): FIFO: %u, msg_ptr: 0x%p, still in use", 2U, self->config.fifo_id, msg_ptr));
644 self->tx.status_waiting_release = true;
652 /*! \brief Moves all pending messages to the waiting_q
653 * \details All messages from pending_q will be moved to the waiting_g and
654 * all consumed credits are restored. The message objects are restored
655 * to the queue in the same order as they have been forwarded to the LLD.
656 * This method is typically called to restore the waiting_q in the correct
657 * order before notifying a
658 * \param self The instance
660 static void Fifo_TxRestorePending(CPmFifo *self)
662 /* take tail from pending_q to the head of waiting_q */
663 CMessage *msg_ptr = NULL;
664 CDlNode *node_ptr = NULL;
666 /* cleanup pending queue */
667 for (node_ptr = Dl_PopTail(&self->tx.pending_q); node_ptr != NULL; node_ptr = Dl_PopTail(&self->tx.pending_q))
669 msg_ptr = (CMessage*)Dln_GetData(node_ptr);
671 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxRestorePending(): FIFO: %u, msg_ptr: 0x%p", 2U, self->config.fifo_id, msg_ptr));
672 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (Msg_IsTxActive(msg_ptr) == false));
674 self->tx.sid_last_completed++;
676 Lldp_ReturnTxToPool(&self->tx.lld_pool, (Lld_IntTxMsg_t*)Msg_GetLldHandle(msg_ptr));
677 Msg_SetLldHandle(msg_ptr, NULL); /* remove link to LLD message object */
678 Msg_PushHeader(msg_ptr, self->tx.encoder_ptr->pm_hdr_sz); /* set index to position of message header */
679 Dl_InsertHead(&self->tx.waiting_queue, node_ptr); /* enqueue message to waiting_q */
683 /*! \brief Retrieves the follower id of the front-most pending message
684 * \param self The instance
685 * \return Returns the follower id of the front-most pending message.
687 static uint8_t Fifo_TxPendingGetFollowerId(CPmFifo *self)
693 node_ptr = Dl_PeekHead(&self->tx.pending_q);
694 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (node_ptr != NULL));
696 if (node_ptr != NULL)
698 tx_ptr = (CMessage*)Dln_GetData(node_ptr);
699 ret = tx_ptr->pb_msg.opts.cancel_id;
705 /*! \brief Aborts the transmission of all messages in the waiting_q with a given follower id
706 * \param self The instance
707 * \param follower_id The follower id a message needs to have to be canceled
708 * \param status The transmission status that shall be notified
710 static void Fifo_TxCancelFollowers(CPmFifo *self, uint8_t follower_id, Ucs_MsgTxStatus_t status)
715 Dl_Ctor(&temp_queue, self->init.base_ptr->ucs_user_ptr);
716 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxCancelFollowers(): FIFO: %u: FollowerId: %u", 2U, self->config.fifo_id, follower_id));
718 for (node_ptr = Dl_PopHead(&self->tx.waiting_queue); node_ptr != NULL; node_ptr = Dl_PopHead(&self->tx.waiting_queue))
720 CMessage *tx_ptr = (CMessage*)Dln_GetData(node_ptr);
722 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (Msg_GetLldHandle(tx_ptr) == NULL));
724 if (tx_ptr->pb_msg.opts.cancel_id == follower_id)
726 Msg_NotifyTxStatus(tx_ptr, status); /* notify failed transmission of message and all followers */
730 Dl_InsertTail(&temp_queue, node_ptr); /* add to temporary queue and keep order of messages */
734 if (Dl_GetSize(&temp_queue) > 0U) /* restore temp_queue to waiting_q */
736 Dl_AppendList(&self->tx.waiting_queue, &temp_queue);/* temp_queue will be empty now */
740 /*------------------------------------------------------------------------------------------------*/
741 /* Tx Message Processing */
742 /*------------------------------------------------------------------------------------------------*/
743 /*! \brief Retrieves the number of (implicit) acknowledges that are related to one SID
744 * \param self The instance
745 * \param sid The sequence ID
746 * \return The number of implicit acknowledges that are related to the SID
748 static uint8_t Fifo_TxGetValidAcknowledges(CPmFifo *self, uint8_t sid)
750 uint8_t diff_s = (uint8_t)(sid - self->tx.sid_last_completed); /* number of implicit acknowledged data */
751 uint8_t diff_b = (uint8_t)(self->tx.sid_next_to_use - self->tx.sid_last_completed); /* number of "sent but un-acknowledged data" + 1 */
753 if (diff_b <= diff_s) /* check valid acknowledges */
762 /*! \brief Checks id an incoming SID of a status message is valid.
763 * \param self The instance
764 * \param sid The sequence ID
765 * \return Returns \c true if the SID is valid, otherwise \c false.
767 static bool Fifo_TxIsIncomingSidValid(CPmFifo *self, uint8_t sid)
770 uint8_t diff_s = (uint8_t)(sid - self->tx.sid_last_completed); /* number of implicit acknowledged data */
771 uint8_t diff_b = (uint8_t)(self->tx.sid_next_to_use - self->tx.sid_last_completed); /* number of "sent but un-acknowledged data" + 1 */
772 uint8_t diff_p = (uint8_t)(self->tx.current_sid - self->tx.sid_last_completed); /* pending/known acknowledges */
774 if (diff_b > diff_s) /* check if SID fits in valid range */
776 if (diff_s >= diff_p) /* avoid overwriting with smaller values */
785 /*! \brief Implicitly notifies transmission status to calling classes
786 * \param self The instance
787 * \param sid The sequence ID until the status shall be notified
788 * \param status The status which is notified
789 * \return Returns \c true if all desired messages had been notified,
790 * otherwise \c false.
792 static bool Fifo_TxNotifyStatus(CPmFifo *self, uint8_t sid, Ucs_MsgTxStatus_t status)
795 uint8_t acks = Fifo_TxGetValidAcknowledges(self, sid);
797 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxNotifyStatus(): FIFO: %u, calculated_acks: %u", 2U, self->config.fifo_id, acks));
801 CDlNode *node_ptr = Dl_PopHead(&self->tx.pending_q);
803 if (node_ptr != NULL)
805 CMessage *tx_ptr = (CMessage*)node_ptr->data_ptr;
807 if (!Msg_IsTxActive(tx_ptr))
809 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (tx_ptr != NULL));
810 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxNotifyStatus(): FIFO: %u, FuncId: 0x%X, notified status: %u", 3U, self->config.fifo_id, tx_ptr->pb_msg.id.function_id, status));
811 Msg_NotifyTxStatus(tx_ptr, status);
812 Lldp_ReturnTxToPool(&self->tx.lld_pool, (Lld_IntTxMsg_t*)Msg_GetLldHandle(tx_ptr));
813 Msg_SetLldHandle(tx_ptr, NULL); /* remove link to LLD message object */
815 self->tx.credits++; /* increment credits */
816 self->tx.sid_last_completed++; /* update last acknowledge SID */
820 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxNotifyStatus(): FIFO: %u, LLD objects still occupied", 1U, self->config.fifo_id));
821 Dl_InsertHead(&self->tx.pending_q, node_ptr);
822 self->tx.status_waiting_release = true;
829 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]"); /* not yet handled */
830 /* trigger sync again */
839 /*! \brief Updates the current Tx status with the content of a received FIFO status
840 * \param self The instance
841 * \param sid The sequence id of the FIFO status
842 * \param type The type of the FIFO status. Valid types are only:
843 * - PMP_STATUS_TYPE_FLOW
844 * - PMP_STATUS_TYPE_FAILURE
845 * \param code The code of the FIFO status
847 static void Fifo_TxUpdateCurrentStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code)
849 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (type == (uint8_t)PMP_STATUS_TYPE_FAILURE) || (type == (uint8_t)PMP_STATUS_TYPE_FLOW));
850 if (Fifo_TxIsIncomingSidValid(self, sid)) /* is new or updating status */
852 self->tx.current_sid = sid; /* update current status */
853 self->tx.current_type = (Pmp_StatusType_t)type;
854 self->tx.current_code = code;
858 TR_ERROR((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxUpdateCurrentStatus(): FIFO: %u, sid: %u, type: %u, code: %u, INVALID SID", 4U, self->config.fifo_id, sid, type, code));
862 /*! \brief Analyses the current Tx status, tries to notify statuses to the transmitter and triggers
863 * retry/cancel actions.
864 * \param self The instance
866 static void Fifo_TxApplyCurrentStatus(CPmFifo *self)
868 if ((self->tx.cancel_all_running == false) && (self->tx.failure_status != 0U)) /* Command(CANCEL) is pending */
870 if (Fifo_TxGetValidAcknowledges(self, self->tx.current_sid) > 1U) /* ?>=1? "single cancel" is valid and implicit */
872 if (Fifo_TxNotifyStatus(self, self->tx.failure_sid, (Ucs_MsgTxStatus_t)self->tx.failure_status))
874 self->tx.failure_status = 0U; /* implicit canceled stops retries */
875 self->tx.failure_sid = 0U;
880 if ((self->tx.current_type == PMP_STATUS_TYPE_FAILURE) && (self->tx.status_waiting_release == false))
882 if (self->tx.cancel_all_running == false)
884 if (Fifo_TxNotifyStatus(self, self->tx.current_sid - 1U, UCS_MSG_STAT_OK) != false)
886 /* important: failed message now is front-most message in the tx.pending_q, */
887 /* any implicit acknowledge was done before */
888 if (self->tx.failure_status == 0U) /* failure not yet handled - avoid multiple calls */
890 if (Fifo_TxPendingGetFollowerId(self) == 0U)
892 Fifo_TxExecuteCancel(self, self->tx.current_sid, self->tx.current_code); /* execute simple cancel */
896 Fifo_TxExecuteCancelAll(self, self->tx.current_sid, self->tx.current_code); /* execute cancel all */
897 /* self->tx.cancel_all_running now is 'true' and Tx is stopped */
904 if ((self->tx.current_type == PMP_STATUS_TYPE_FLOW) && (self->tx.status_waiting_release == false))
906 if ((uint8_t)PMP_STATUS_CODE_SUCCESS == self->tx.current_code) /* acknowledge pending messages */
908 /* no further retries possible */
909 (void)Fifo_TxNotifyStatus(self, self->tx.current_sid, UCS_MSG_STAT_OK);
911 else if ((uint8_t)PMP_STATUS_CODE_CANCELED == self->tx.current_code)
913 if (self->tx.cancel_all_running != false)
915 /* wait until the last SID is notified */
916 if (self->tx.current_sid == (uint8_t)(self->tx.sid_next_to_use - (uint8_t)1U))
918 /* cancel done if none of pending messages is active */
919 if (Fifo_TxHasAccessPending(self) != false)
921 Fifo_TxFinishedCancelAll(self);
925 else if (Fifo_TxNotifyStatus(self, self->tx.current_sid, (Ucs_MsgTxStatus_t)self->tx.failure_status))
927 self->tx.failure_status = 0U;
928 self->tx.failure_sid = 0U;
933 if (Fifo_TxNotifyStatus(self, self->tx.current_sid - 1U, UCS_MSG_STAT_OK)) /* just implicitly acknowledge preceding message */
935 if ((uint8_t)PMP_STATUS_CODE_NACK == self->tx.current_code)
937 Fifo_Stop(self, FIFO_S_UNSYNCED_INIT, true);
938 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]");
945 /*------------------------------------------------------------------------------------------------*/
946 /* Rx Implementation */
947 /*------------------------------------------------------------------------------------------------*/
948 /*! \brief Receives a message on the respective FIFO
949 * \param self The instance
950 * \param msg_ptr Reference to the Rx message
952 static void Fifo_OnRx(void *self, CMessage *msg_ptr)
954 CPmFifo *self_ = (CPmFifo*)self;
955 Dl_InsertTail(&self_->rx.queue, Msg_GetNode(msg_ptr)); /* enqueue in rx_queue */
956 Srv_SetEvent(&self_->service, (FIFO_SE_RX_SERVICE | FIFO_SE_TX_APPLY_STATUS | FIFO_SE_TX_SERVICE));
959 /*! \brief Processes the Rx queue completely and triggers possible Tx events
960 * \param self The instance
962 static void Fifo_RxService(CPmFifo *self)
964 while (self->rx.wait_processing == false) /* process all Rx messages if possible */
971 bool free_msg = true; /* default: free every status or command message */
972 CDlNode *node_ptr = Dl_PopHead(&self->rx.queue);
974 if (node_ptr == NULL)
976 msg_ptr = NULL; /* stop processing - no further messages in queue */
980 msg_ptr = (CMessage*)node_ptr->data_ptr;
981 header_ptr = Msg_GetHeader(msg_ptr);
982 type = Pmp_GetMsgType(header_ptr);
983 ok = Pmp_VerifyHeader(header_ptr, MSG_SIZE_RSVD_BUFFER);
989 case PMP_MSG_TYPE_CMD:
990 Fifo_RxProcessCommand(self, msg_ptr);
992 case PMP_MSG_TYPE_STATUS:
993 Fifo_RxProcessStatus(self, msg_ptr);
995 case PMP_MSG_TYPE_DATA:
996 free_msg = Fifo_RxProcessData(self, msg_ptr); /* important: message can be freed */
997 break; /* synchronously */
999 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]"); /* unknown FIFO message type */
1005 TR_FAILED_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]"); /* invalid message header */
1008 if (free_msg != false)
1010 Pmch_ReturnRxToPool(self->init.channel_ptr, msg_ptr);
1015 /*! \brief Evaluates the trigger condition to transmit a Rx status
1016 * \details Needs to be called before and after processing Rx data messages
1017 * \param self The instance
1019 static void Fifo_RxCheckStatusTrigger(CPmFifo *self)
1021 /* calculate the number of credits the INIC has consumed */
1022 /* if less messages are processing, the freed can be acknowledged */
1023 uint8_t consumed_inic_credits = (self->rx.expected_sid - self->rx.ack_last_ok_sid) - 1U;
1024 uint8_t possible_acks = consumed_inic_credits - self->rx.busy_num;
1026 if ((consumed_inic_credits >= self->rx.ack_threshold) && (possible_acks > 0U))
1028 if (Pmcmd_IsTriggered(&self->rx.status) == false)
1030 Pmcmd_SetTrigger(&self->rx.status, true); /* INIC might run out of credits */
1031 Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
1036 /*! \brief This function shall be called before processing a valid FIFO data message
1037 * \param self The instance
1039 static void Fifo_RxGetCredit(CPmFifo *self)
1041 self->rx.busy_num++;
1042 Fifo_RxCheckStatusTrigger(self);
1045 /*! \brief This function shall be called after processing a valid FIFO data message
1046 * \details It is important to call this function after the message object is freed,
1047 * so that the flow control can be updated.
1048 * \param self The instance
1050 static void Fifo_RxReleaseCredit(CPmFifo *self)
1052 self->rx.busy_num--;
1053 Fifo_RxCheckStatusTrigger(self);
1056 /*! \brief Releases a FIFO data message which was received and forwarded by the FIFO
1057 * \details The function returns the message to the channel's Rx message pool and
1058 * has to update the number of credits (processing handles).
1059 * A FIFO data message is initially allocated from the channel's Rx message pool.
1060 * When processing the handle the determined FIFO need to calculate the amount of
1061 * credits. When freeing the message the handle needs to be returned to the channel's
1062 * Rx pool again and the FIFO needs to refresh the status and credits calculation.
1063 * Therefore the message has to be freed to the respective FIFO again.
1064 * \param self The instance
1065 * \param msg_ptr The Rx data message
1067 void Fifo_RxReleaseMsg(CPmFifo *self, CMessage *msg_ptr)
1069 Pmch_ReturnRxToPool(self->init.channel_ptr, msg_ptr);
1070 Fifo_RxReleaseCredit(self);
1073 /*! \brief Processes an Rx data message
1074 * \param self The instance
1075 * \param msg_ptr The Rx data message
1076 * \return \c true if the message object is no longer needed.
1077 * Otherwise \c false.
1079 static bool Fifo_RxProcessData(CPmFifo *self, CMessage *msg_ptr)
1081 bool free_msg = true;
1082 uint8_t content_header_sz = 0U;
1084 uint8_t *header_ptr = Msg_GetHeader(msg_ptr);
1085 sid = Pmp_GetSid(header_ptr);
1087 if (self->sync_state != FIFO_S_SYNCED)
1088 { /* discard Rx messages while FIFO is not synced */
1089 TR_ERROR((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_RxProcessData(): FIFO: %u, state: %u, discards Rx message with SID=0x%02X while not synced (warning)", 3U, self->config.fifo_id, self->sync_state, sid));
1091 else if (sid == self->rx.expected_sid) /* check if SID is ok */
1093 uint8_t pm_header_sz = Pmp_GetPmhl(header_ptr) + 3U;
1094 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (pm_header_sz == self->rx.encoder_ptr->pm_hdr_sz));
1096 self->rx.expected_sid++; /* update SID */
1097 content_header_sz = self->rx.encoder_ptr->msg_hdr_sz;
1099 /* parasoft suppress item MISRA2004-17_4 reason "necessary offset usage" */
1100 self->rx.encoder_ptr->decode_fptr(Msg_GetMostTel(msg_ptr), &(header_ptr[pm_header_sz]));
1101 /* parasoft unsuppress item MISRA2004-17_4 reason "necessary offset usage" */
1103 Msg_ReserveHeader(msg_ptr, content_header_sz + pm_header_sz);
1104 Msg_PullHeader(msg_ptr, content_header_sz + pm_header_sz);
1106 if (Msg_VerifyContent(msg_ptr))
1108 if (self->rx.on_complete_fptr != NULL)
1110 (void)Fifo_RxGetCredit(self);
1111 free_msg = false; /* callback is responsible to free the message */
1112 self->rx.on_complete_fptr(self->rx.on_complete_inst, msg_ptr);
1113 /* Fifo_RxReleaseCredit() is called when message is freed */
1119 TR_ERROR((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_RxProcessData(): FIFO: %u, state: %u, discards Rx message with unexpected SID=0x%02X (warning)", 3U, self->config.fifo_id, self->sync_state, sid));
1125 /*! \brief Processes an Rx status message
1126 * \param self The instance
1127 * \param msg_ptr The Rx status message
1129 static void Fifo_RxProcessStatus(CPmFifo *self, CMessage *msg_ptr)
1132 uint8_t current_sid;
1133 uint8_t current_type;
1134 uint8_t current_code;
1135 uint8_t *header_ptr = Msg_GetHeader(msg_ptr);
1137 Pmh_DecodeHeader(&pm_header, header_ptr);
1138 current_sid = pm_header.sid;
1139 current_type = (uint8_t)Pmh_GetExtStatusType(&pm_header);
1140 current_code = (uint8_t)Pmh_GetExtStatusCode(&pm_header);
1142 self->wd.request_started = false; /* status finishes a wd request */
1144 switch ((Pmp_StatusType_t)current_type)
1146 case PMP_STATUS_TYPE_FAILURE:
1147 Fifo_TxUpdateCurrentStatus(self, current_sid, current_type, Fifo_RxCheckFailureCode(self, current_code)); /* just update status type FAILURE */
1149 case PMP_STATUS_TYPE_FLOW:
1150 Fifo_TxUpdateCurrentStatus(self, current_sid, current_type, current_code); /* just update status type FLOW (codes: BUSY, NACK, SUCCESS, CANCELED) */
1152 case PMP_STATUS_TYPE_SYNCED:
1153 Fifo_RxProcessSyncStatus(self, current_sid, current_type, current_code, header_ptr);
1155 case PMP_STATUS_TYPE_UNSYNCED_BSY:
1156 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_RxProcessStatus(): FIFO: %u, state: %u, received UNSYNCED_BSY", 2U, self->config.fifo_id, self->sync_state));
1157 if (self->sync_state != FIFO_S_SYNCING)
1159 Fifo_Stop(self, FIFO_S_UNSYNCED_BUSY, true);
1162 case PMP_STATUS_TYPE_UNSYNCED_RDY:
1163 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_RxProcessStatus(): FIFO: %u, state: %u, received UNSYNCED_RDY", 2U, self->config.fifo_id, self->sync_state));
1164 if (self->sync_state == FIFO_S_SYNCING)
1166 if (current_code == (uint8_t)PMP_UNSYNC_R_COMMAND)
1168 Fifo_Synchronize(self); /* retry synchronization */
1173 Fifo_Stop(self, FIFO_S_UNSYNCED_READY, true);
1178 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_RxProcessStatus(): FIFO: %u, state: %u, received UNKNOWN TYPE: %u", 3U, self->config.fifo_id, self->sync_state, current_type));
1183 /*! \brief Checks failure_code and sets invalid code to UCS_MSG_STAT_ERROR_UNKNOWN
1184 * \param self The instance
1185 * \param failure_code The INIC failure code
1186 * \return Returns the checked failure code
1188 static uint8_t Fifo_RxCheckFailureCode(CPmFifo *self, uint8_t failure_code)
1193 switch (failure_code)
1195 case (uint8_t)UCS_MSG_STAT_ERROR_CFG_NO_RCVR:
1196 case (uint8_t)UCS_MSG_STAT_ERROR_BF:
1197 case (uint8_t)UCS_MSG_STAT_ERROR_CRC:
1198 case (uint8_t)UCS_MSG_STAT_ERROR_ID:
1199 case (uint8_t)UCS_MSG_STAT_ERROR_ACK:
1200 case (uint8_t)UCS_MSG_STAT_ERROR_TIMEOUT:
1201 case (uint8_t)UCS_MSG_STAT_ERROR_FATAL_WT:
1202 case (uint8_t)UCS_MSG_STAT_ERROR_FATAL_OA:
1203 case (uint8_t)UCS_MSG_STAT_ERROR_NA_TRANS:
1204 case (uint8_t)UCS_MSG_STAT_ERROR_NA_OFF:
1208 ret = (uint8_t)UCS_MSG_STAT_ERROR_UNKNOWN;
1215 /*! \brief Processes an Rx command message
1216 * \param self The instance
1217 * \param msg_ptr The Rx command message
1219 static void Fifo_RxProcessCommand(CPmFifo *self, CMessage *msg_ptr)
1221 MISC_UNUSED(msg_ptr);
1222 /* be aware that PMHL might vary */
1223 Pmcmd_SetTrigger(&self->rx.status, true); /* just trigger latest Rx status now */
1226 /*! \brief Processes a status SYNCED from the INIC
1227 * \param self The instance
1228 * \param sid The sid of the sync status
1229 * \param type The type of the sync status
1230 * \param code The code of the sync status
1231 * \param header_ptr Pointer to the raw port message
1232 * \return The current synchronization state
1234 static void Fifo_RxProcessSyncStatus(CPmFifo *self, uint8_t sid, uint8_t type, uint8_t code, uint8_t *header_ptr)
1237 uint8_t tx_credits = 0U;
1239 TR_ASSERT(self->init.base_ptr->ucs_user_ptr, "[FIFO]", (type==(uint8_t)PMP_STATUS_TYPE_SYNCED));
1243 if (Pmp_GetDataSize(header_ptr) == 4U)
1245 tx_credits = Pmp_GetData(header_ptr, 0U) & (uint8_t)PMP_CREDITS_MASK;
1247 if ((tx_credits >= PMP_CREDITS_MIN) &&
1248 (Pmp_GetData(header_ptr, 1U) == self->sync_params[1]) &&
1249 (Pmp_GetData(header_ptr, 2U) == self->sync_params[2]) &&
1250 (Pmp_GetData(header_ptr, 3U) == self->sync_params[3]) &&
1251 (sid == (self->sync_cnt)))
1253 check = true; /* the sync status parameters are correct */
1257 if ((check != false) && (self->sync_state == FIFO_S_SYNCING))
1259 Fifo_InitCounters(self, sid, tx_credits); /* values are incremented on each sync attempt */
1260 self->sync_state = FIFO_S_SYNCED; /* sync status shall have 4 bytes message body */
1261 self->rx.wait_processing = false;
1262 Fifo_TxStartWatchdog(self);
1263 Sub_Notify(&self->sync_state_subject, &self->config.fifo_id);
1267 /*------------------------------------------------------------------------------------------------*/
1268 /* Synchronization */
1269 /*------------------------------------------------------------------------------------------------*/
1271 /*! \brief Synchronizes the FIFO
1272 * \param self The instance
1274 void Fifo_Synchronize(CPmFifo *self)
1276 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_Synchronize(): FIFO: %u, state: %u", 2U, self->config.fifo_id, self->sync_state));
1277 self->sync_state = FIFO_S_SYNCING;
1278 Pmcmd_SetTrigger(&self->tx.sync_cmd, true);
1279 Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
1282 /*! \brief Un-synchronizes the FIFO
1283 * \param self The instance
1285 void Fifo_Unsynchronize(CPmFifo *self)
1287 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_Unsynchronize(): FIFO: %u, state: %u", 2U, self->config.fifo_id, self->sync_state));
1288 if (self->sync_state != FIFO_S_UNSYNCED_READY)
1290 self->sync_state = FIFO_S_UNSYNCING;
1291 Pmcmd_SetTrigger(&self->tx.sync_cmd, true);
1292 Srv_SetEvent(&self->service, FIFO_SE_TX_SERVICE);
1296 /*! \brief Retrieves the current synchronization state
1297 * \param self The instance
1298 * \return The current synchronization state
1300 Fifo_SyncState_t Fifo_GetState(CPmFifo *self)
1302 return self->sync_state;
1305 /*------------------------------------------------------------------------------------------------*/
1307 /*------------------------------------------------------------------------------------------------*/
1309 /*! \brief Starts the watchdog handling
1310 * \param self The instance
1312 static void Fifo_TxStartWatchdog(CPmFifo *self)
1314 self->wd.request_started = false;
1316 TR_INFO((self->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxStartWatchdog(): fifo_id: %u, timeout: %u", 2U, self->config.fifo_id, self->wd.timer_value));
1318 if (self->wd.timer_value != 0U)
1320 Tm_SetTimer(&self->init.base_ptr->tm, &self->wd.timer, &Fifo_TxOnWatchdogTimer,
1322 self->wd.timer_value,
1323 self->wd.timer_value
1328 /*! \brief Callback function which is invoked if the watchdog timer expires
1329 * \param self The instance
1331 static void Fifo_TxOnWatchdogTimer(void *self)
1333 CPmFifo *self_ = (CPmFifo*)self;
1335 TR_INFO((self_->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxOnWatchdogTimer(): FIFO: %u, state: %u", 2U, self_->config.fifo_id, self_->sync_state));
1337 if (self_->wd.request_started == false)
1339 if (Pmcmd_Reserve(&self_->wd.wd_cmd) != false)
1341 self_->wd.request_started = true; /* indicate that a status is expected */
1342 Pmcmd_UpdateContent(&self_->wd.wd_cmd, self_->tx.sid_next_to_use - 1U, PMP_CMD_TYPE_REQ_STATUS, PMP_CMD_CODE_REQ_STATUS);
1343 Pmch_Transmit(self_->init.channel_ptr, Pmcmd_GetLldTxObject(&self_->wd.wd_cmd));
1347 TR_ERROR((self_->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxOnWatchdogTimer(): Unable to reserve watchdog command ", 0U));
1348 Fifo_Stop(self_, FIFO_S_UNSYNCED_INIT, true);
1351 else /* status not received in time - notify communication error */
1353 TR_ERROR((self_->init.base_ptr->ucs_user_ptr, "[FIFO]", "Fifo_TxOnWatchdogTimer(): Missing response on status request", 0U));
1354 Fifo_Stop(self_, FIFO_S_UNSYNCED_INIT, true);
1363 /*------------------------------------------------------------------------------------------------*/
1365 /*------------------------------------------------------------------------------------------------*/