Updated GDB ini file to load binding symbols directly from SDK
[apps/agl-service-unicens.git] / ucs2-lib / src / ucs_pmfifos.c
1 /*------------------------------------------------------------------------------------------------*/
2 /* UNICENS V2.1.0-3491                                                                            */
3 /* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG.                              */
4 /*                                                                                                */
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.                                                            */
9 /*                                                                                                */
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.                                                   */
14 /*                                                                                                */
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/>.                          */
17 /*                                                                                                */
18 /* You may also obtain this software under a propriety license from Microchip.                    */
19 /* Please contact Microchip for further information.                                              */
20 /*------------------------------------------------------------------------------------------------*/
21
22 /*!
23  * \file
24  * \brief Implementation of class CPmFifos
25  *
26  * \cond UCS_INTERNAL_DOC
27  * \addtogroup  G_PMFIFOS
28  * @{
29  */
30
31 /*------------------------------------------------------------------------------------------------*/
32 /* Includes                                                                                       */
33 /*------------------------------------------------------------------------------------------------*/
34 #include "ucs_pmfifos.h"
35 #include "ucs_misc.h"
36 #include "ucs_trace.h"
37
38 /*------------------------------------------------------------------------------------------------*/
39 /* Internal Constants                                                                             */
40 /*------------------------------------------------------------------------------------------------*/
41 /*! \brief The initialization value of sync_count. It is incremented for each sync or un-sync attempt. */
42 static const uint8_t     FIFOS_SYNC_CNT_INITIAL = 0xFFU;
43
44 /*------------------------------------------------------------------------------------------------*/
45 /* Internal typedefs                                                                              */
46 /*------------------------------------------------------------------------------------------------*/
47
48 /*------------------------------------------------------------------------------------------------*/
49 /* Internal prototypes                                                                            */
50 /*------------------------------------------------------------------------------------------------*/
51 static void Fifos_Cleanup(CPmFifos *self);
52 static void Fifos_OnSyncTimeout(void *self);
53 static void Fifos_OnUnsyncTimeout(void *self);
54 static void Fifos_OnFifoEvent(void *self, void *fifo_id_ptr);
55
56 static void Fifos_HandleFifoStateChange(CPmFifos *self, Pmp_FifoId_t fifo_id);
57 static bool Fifos_AreAllFifosInState(CPmFifos *self, Fifo_SyncState_t target_state);
58
59 /*------------------------------------------------------------------------------------------------*/
60 /* Implementation                                                                                 */
61 /*------------------------------------------------------------------------------------------------*/
62 /*! \brief  Constructor of class CPmFifos
63  *  \param  self         The instance
64  *  \param  base_ptr     Reference to basic services
65  *  \param  channel_ptr  Reference to the port message channel
66  *  \param  icm_fifo_ptr Reference to ICM FIFO, or NULL.
67  *  \param  mcm_fifo_ptr Reference to MCM FIFO, or NULL.
68  *  \param  rcm_fifo_ptr Reference to RCM FIFO, or NULL.
69  *  \details At least one FIFO (MCM or ICM) must be provided.
70  */
71 void Fifos_Ctor(CPmFifos *self, CBase *base_ptr, CPmChannel *channel_ptr, CPmFifo *icm_fifo_ptr, CPmFifo *mcm_fifo_ptr, CPmFifo *rcm_fifo_ptr)
72 {
73     MISC_MEM_SET(self, 0, sizeof(*self));
74
75     self->base_ptr      = base_ptr;
76     self->channel_ptr   = channel_ptr;
77     self->state         = FIFOS_S_UNSYNCED;
78
79     self->unsync_initial = false;
80     Fifos_ConfigureSyncParams(self, FIFOS_SYNC_RETRIES, FIFOS_SYNC_TIMEOUT);
81
82     self->fifos[PMP_FIFO_ID_ICM] = icm_fifo_ptr;
83     self->fifos[PMP_FIFO_ID_RCM] = rcm_fifo_ptr;
84     self->fifos[PMP_FIFO_ID_MCM] = mcm_fifo_ptr;
85
86     T_Ctor(&self->init_timer); 
87     Sub_Ctor(&self->event_subject, self->base_ptr->ucs_user_ptr);
88     Obs_Ctor(&self->obs_icm, self, &Fifos_OnFifoEvent);
89     Obs_Ctor(&self->obs_rcm, self, &Fifos_OnFifoEvent);
90     Obs_Ctor(&self->obs_mcm, self, &Fifos_OnFifoEvent);
91
92     TR_ASSERT(self->base_ptr->ucs_user_ptr, "[FIFOS]", (!((icm_fifo_ptr == NULL) && (mcm_fifo_ptr == NULL))));
93
94     if (icm_fifo_ptr != NULL)
95     {
96         Fifo_AddStateObserver(icm_fifo_ptr, &self->obs_icm);
97     }
98
99     if (rcm_fifo_ptr != NULL)
100     {
101         Fifo_AddStateObserver(rcm_fifo_ptr, &self->obs_rcm);
102     }
103
104     if (mcm_fifo_ptr != NULL)
105     {
106         Fifo_AddStateObserver(mcm_fifo_ptr, &self->obs_mcm);
107     }
108
109     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_Ctor(): FIFOS created, state %d", 1U, self->state));
110 }
111
112 /*! \brief          Adds an observer of synchronization events
113  *  \param self     The instance
114  *  \param obs_ptr  The observer. The notification result type is Fifos_Event_t.
115  */
116 void Fifos_AddEventObserver(CPmFifos *self, CObserver *obs_ptr)
117 {
118     TR_ASSERT(self->base_ptr->ucs_user_ptr, "[FIFOS]", (obs_ptr != 0));
119     (void)Sub_AddObserver(&self->event_subject, obs_ptr);
120 }
121
122 /*! \brief          Removes an observer of synchronization events
123  *  \param self     The instance
124  *  \param obs_ptr  The observer.
125  */
126 void Fifos_RemoveEventObserver(CPmFifos *self, CObserver *obs_ptr)
127 {
128     TR_ASSERT(self->base_ptr->ucs_user_ptr, "[FIFOS]", (obs_ptr != 0));
129     (void)Sub_RemoveObserver(&self->event_subject, obs_ptr);
130 }
131
132 /*! \brief          Forces all FIFOs to state UNSYNCED without waiting for INIC responses and
133  *                  without throwing events
134  *  \details        Stops the LLD interface and releases all pending message resources.
135  *                  This function shall be called if the UCS requires a un-normal termination
136  *                  which is not detected by port message protocol.
137  *  \param self     The instance
138  */
139 void Fifos_ForceTermination(CPmFifos *self)
140 {
141     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_ForceTermination(): Termination started, state: %d", 1U, self->state));
142     Fifos_Cleanup(self);
143     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_ForceTermination(): Termination done, state: %d", 1U, self->state));
144 }
145
146 /*! \brief          Configures retries and timeout for synchronize or un-synchronize
147  *                  operation
148  *  \details        This method shall be called before starting a synchronization or un-synchronization
149  *                  or after it has finished. The current counter of synchronization attempts is reset.
150  *  \param self     The instance
151  *  \param retries  The number of retries until event FIFOS_EV_SYNC_FAILED or 
152  *                  FIFOS_EV_UNSYNC_FAILED will be notified
153  *  \param timeout  The timeout in milliseconds when the retry is performed
154  */
155 void Fifos_ConfigureSyncParams(CPmFifos *self, uint8_t retries, uint16_t timeout)
156 {
157     self->cmd_retries = retries;
158     self->cmd_timeout = timeout;
159     self->sync_cnt = FIFOS_SYNC_CNT_INITIAL;
160 }
161
162 /*------------------------------------------------------------------------------------------------*/
163 /* Synchronization                                                                                */
164 /*------------------------------------------------------------------------------------------------*/
165 /*! \brief    Initializes all port message FIFOs
166  *  \details  Possible results of the operation are the following events which are fired
167  *            asynchronously. Refer also Fifos_AddEventObserver() and \ref Fifos_Event_t.
168  *            - \ref FIFOS_EV_SYNC_ESTABLISHED
169  *            - \ref FIFOS_EV_SYNC_FAILED
170  *  \param    self        The instance
171  *  \param    reset_cnt   If \c true resets the synchronization counter. In this case an automatic
172  *                        retries will be done after the first synchronization timeout.
173  *  \param    force_sync  If \c true the method will also trigger the synchronization of already 
174  *                        synced \ref CPmFifo objects.
175  */
176 void Fifos_Synchronize(CPmFifos *self, bool reset_cnt, bool force_sync)
177 {
178     uint8_t cnt;
179     self->state = FIFOS_S_SYNCING;
180     self->unsync_initial = false;
181     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_Synchronize(): Synchronization started, state: %d", 1U, self->state));
182
183     if (reset_cnt)
184     {
185         self->sync_cnt = FIFOS_SYNC_CNT_INITIAL;
186     }
187
188     self->sync_cnt++;
189     Pmch_Initialize(self->channel_ptr);                     /* Start LLD if not already done */
190
191     for (cnt = 0U; cnt < PMP_MAX_NUM_FIFOS; cnt++)
192     {
193         if (self->fifos[cnt] != NULL)
194         {
195             if (force_sync || (Fifo_GetState(self->fifos[cnt]) != FIFO_S_SYNCED))
196             {
197                 Fifo_Synchronize(self->fifos[cnt]);
198             }
199         }
200     }
201
202     Tm_SetTimer(&self->base_ptr->tm, &self->init_timer, 
203                 &Fifos_OnSyncTimeout, self, 
204                 self->cmd_timeout, 0U);
205 }
206
207 /*! \brief      Un-initializes all port message FIFOs
208  *  \details    Possible results of the operation are the following events which are fired
209  *              asynchronously. Refer also Fifos_AddEventObserver() and \ref Fifos_Event_t.
210  *              - \ref FIFOS_EV_UNSYNC_COMPLETE
211  *              - \ref FIFOS_EV_UNSYNC_FAILED
212  *  \param      self       The instance
213  *  \param      reset_cnt  If \c true resets the synchronization counter. In this case an automatic
214  *                         retries will be done after the first synchronization timeout.
215  *  \param      initial    If the un-synchronization shall be executed prior to a initial synchronization
216  *                         it is recommended to set the argument to \c true. After notifying the event 
217  *                         FIFOS_EV_UNSYNC_COMPLETE the LLD interface will not be stopped. The subsequent 
218  *                         call of Fifos_Synchronize() will not start the LLD interface un-necessarily.
219  *                         To trigger a final un-synchronization \c initial shall be set to \c false.
220  *                         I.e., FIFOS_EV_UNSYNC_COMPLETE stops the LLD interface.
221  */
222 void Fifos_Unsynchronize(CPmFifos *self, bool reset_cnt, bool initial)
223 {
224     uint8_t cnt;
225     self->state = FIFOS_S_UNSYNCING;
226     self->unsync_initial = initial;
227     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_Unsynchronize(): Un-synchronization started, state: %d", 1U, self->state));
228
229     if (reset_cnt)
230     {
231         self->sync_cnt = FIFOS_SYNC_CNT_INITIAL;
232     }
233
234     self->sync_cnt++;
235     Pmch_Initialize(self->channel_ptr);                     /* Start LLD if not already done */
236
237     for (cnt = 0U; cnt < PMP_MAX_NUM_FIFOS; cnt++)
238     {
239         if (self->fifos[cnt] != NULL)
240         {
241             if (initial || (Fifo_GetState(self->fifos[cnt]) != FIFO_S_UNSYNCED_READY))
242             {
243                 Fifo_Unsynchronize(self->fifos[cnt]);
244             }
245         }
246     }
247
248     Tm_SetTimer(&self->base_ptr->tm, &self->init_timer, 
249                 &Fifos_OnUnsyncTimeout, self, 
250                 self->cmd_timeout, 0U);
251 }
252
253 /*! \brief  Handles the synchronization timeout
254  *  \param  self    The instance
255  */
256 static void Fifos_OnSyncTimeout(void *self)
257 {
258     CPmFifos *self_ = (CPmFifos*)self;
259     Fifos_Event_t the_event = FIFOS_EV_SYNC_FAILED;
260
261     self_->state = FIFOS_S_UNSYNCED;
262
263     TR_INFO((self_->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_OnSyncTimeout(): state: %d", 1U, self_->state));
264
265     if (self_->sync_cnt < self_->cmd_retries)
266     {
267         Fifos_Synchronize(self_, false, false);             /* retry synchronization after first timeout */
268     }
269     else
270     {
271         Fifos_Cleanup(self_);
272         Sub_Notify(&self_->event_subject, &the_event);
273     }
274 }
275
276 /*! \brief  Handles the un-synchronization timeout
277  *  \param  self    The instance
278  */
279 static void Fifos_OnUnsyncTimeout(void *self)
280 {
281     CPmFifos *self_ = (CPmFifos*)self;
282     Fifos_Event_t the_event = FIFOS_EV_UNSYNC_FAILED;
283
284     self_->state = FIFOS_S_UNSYNCED;
285     TR_INFO((self_->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_OnUnsyncTimeout(): state: %d", 1U, self_->state));
286
287     if (self_->sync_cnt < self_->cmd_retries)
288     {
289         Fifos_Unsynchronize(self_, false, self_->unsync_initial);   /* retry synchronization after first timeout */
290     }
291     else
292     {
293         self_->unsync_initial = false;                              /* un-sync timeout will lead to termination - stop LLD */
294         Fifos_Cleanup(self_);
295         Sub_Notify(&self_->event_subject, &the_event);
296     }
297 }
298
299 /*! \brief      Performs a cleanup of the Port Message Channel and the dedicated FIFOs
300  *  \details    Releases all message objects which are currently in use.
301  *  \param      self            The instance
302  */
303 static void Fifos_Cleanup(CPmFifos *self)
304 {
305     uint8_t count;
306     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_Cleanup(): Channel cleanup started", 0U));
307
308     if (self->unsync_initial == false)
309     {
310         Pmch_Uninitialize(self->channel_ptr);
311     }
312
313     for (count = 0U; count < PMP_MAX_NUM_FIFOS; count++)    /* stop & cleanup all FIFOs */
314     {
315         if (self->fifos[count] != NULL)
316         {                                                   /* stop and avoid recursion */
317             Fifo_Stop(self->fifos[count], FIFO_S_UNSYNCED_INIT, false);
318             Fifo_Cleanup(self->fifos[count]);
319         }
320     }
321
322     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_Cleanup(): Channel cleanup completed", 0U));
323
324     /* notify external event after message objects were released */
325     self->state = FIFOS_S_UNSYNCED;
326 }
327
328 /*------------------------------------------------------------------------------------------------*/
329 /* FIFO observation                                                                               */
330 /*------------------------------------------------------------------------------------------------*/
331
332 /*! \brief  Notifies an event to the host class
333  *  \param  self        The instance
334  *  \param  fifo_id_ptr Specific event identifier, pointer to "fifo_id"
335  */
336 static void Fifos_OnFifoEvent(void *self, void *fifo_id_ptr)
337 {
338     CPmFifos *self_ = (CPmFifos*)self;
339     Fifos_HandleFifoStateChange(self_, *((Pmp_FifoId_t*)fifo_id_ptr));
340 }
341
342 /*! \brief  Executes transition to new synchronization states
343  *  \param  self        The instance
344  *  \param  fifo_id     The FIFO identifier
345  */
346 static void Fifos_HandleFifoStateChange(CPmFifos *self, Pmp_FifoId_t fifo_id)
347 {
348     Fifos_Event_t the_event;
349
350     TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_HandleFifoStateChange(): FIFOs state: %d, FIFO: %d, FIFO State: %d", 3U, 
351              self->state, fifo_id, Fifo_GetState(self->fifos[fifo_id])));
352
353     switch (self->state)
354     {
355         case FIFOS_S_SYNCING:
356             if (Fifos_AreAllFifosInState(self, FIFO_S_SYNCED))
357             {
358                 self->state = FIFOS_S_SYNCED;                           /* now the complete channel is synced */
359                 Tm_ClearTimer(&self->base_ptr->tm, &self->init_timer);
360                 Fifos_ConfigureSyncParams(self, FIFOS_UNSYNC_RETRIES, FIFOS_UNSYNC_TIMEOUT);
361                 the_event = FIFOS_EV_SYNC_ESTABLISHED;
362                 Sub_Notify(&self->event_subject, &the_event);
363                 TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_HandleFifoStateChange(): Synchronization of Port Message channel completed", 0U));
364             }
365             break;
366
367         case FIFOS_S_UNSYNCING:
368             if (Fifos_AreAllFifosInState(self, FIFO_S_UNSYNCED_READY))
369             {
370                 Fifos_Cleanup(self);
371                 self->state = FIFOS_S_UNSYNCED;                         /* now the complete channel is un-synced */
372                 Tm_ClearTimer(&self->base_ptr->tm, &self->init_timer);
373                 the_event = FIFOS_EV_UNSYNC_COMPLETE;
374                 Sub_Notify(&self->event_subject, &the_event);
375                 TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_HandleFifoStateChange(): Un-synchronization of Port Message channel completed", 0U));
376             }
377             break;
378
379         case FIFOS_S_SYNCED:
380             if (!Fifos_AreAllFifosInState(self, FIFO_S_SYNCED))
381             {
382                 self->state = FIFOS_S_UNSYNCING;                        /* set state to 'unsyncing' and wait until all FIFOs are unsynced */
383                 self->sync_cnt = 0U;                                    /* pretend having triggered an un-sync which starts the timer */
384                 Tm_SetTimer(&self->base_ptr->tm, &self->init_timer, 
385                             &Fifos_OnUnsyncTimeout, self, 
386                             FIFOS_UNSYNC_TIMEOUT, 0U);
387                 the_event = FIFOS_EV_SYNC_LOST;
388                 Sub_Notify(&self->event_subject, &the_event);
389                 TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_HandleFifoStateChange(): Lost synchronization of Port Message channel", 0U));
390             }
391             if (Fifos_AreAllFifosInState(self, FIFO_S_UNSYNCED_READY))
392             {
393                 Fifos_Cleanup(self);
394                 self->state = FIFOS_S_UNSYNCED;                         /* the complete channel suddenly goes unsynced_complete */
395                 Tm_ClearTimer(&self->base_ptr->tm, &self->init_timer);
396                 the_event = FIFOS_EV_UNSYNC_COMPLETE;
397                 Sub_Notify(&self->event_subject, &the_event);
398                 TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_HandleFifoStateChange(): Sudden un-synchronization of Port Message channel completed", 0U));
399             }
400             break;
401
402         case FIFOS_S_UNSYNCED:
403             TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_HandleFifoStateChange(): Unexpected FIFO event in state unsynced", 0U));
404             break;
405
406         default:
407             TR_INFO((self->base_ptr->ucs_user_ptr, "[FIFOS]", "Fifos_HandleFifoStateChange(): Unexpected FIFOs state", 0U));
408             break;
409     }
410
411     MISC_UNUSED(fifo_id);
412 }
413
414 /*! \brief  Helper function that evaluates if all configured FIFOs are in a given state 
415  *  \param  self            The instance
416  *  \param  target_state    The required state that is evaluated for all FIFOs
417  *  \return \c true if all FIFOs are in the given \c target_state, otherwise \c false.
418  */
419 static bool Fifos_AreAllFifosInState(CPmFifos *self, Fifo_SyncState_t target_state)
420 {
421     bool ret = true;
422     uint8_t cnt;
423
424     for (cnt = 0U; cnt < PMP_MAX_NUM_FIFOS; cnt++)
425     {
426         if (self->fifos[cnt] != NULL)
427         {
428             Fifo_SyncState_t state = Fifo_GetState(self->fifos[cnt]);
429
430             if (state != target_state)
431             {
432                 ret = false;
433             }
434         }
435     }
436
437     return ret;
438 }
439
440 /*!
441  * @}
442  * \endcond
443  */
444
445 /*------------------------------------------------------------------------------------------------*/
446 /* End of file                                                                                    */
447 /*------------------------------------------------------------------------------------------------*/
448