Use latest version of conf.d/templates submodule.
[apps/agl-service-unicens.git] / ucs2-lib / src / ucs_rtm.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 the Route Management.
25  *
26  * \cond UCS_INTERNAL_DOC
27  * \addtogroup G_RTM
28  * @{
29  */
30
31 /*------------------------------------------------------------------------------------------------*/
32 /* Includes                                                                                       */
33 /*------------------------------------------------------------------------------------------------*/
34 #include "ucs_rtm.h"
35
36 /*------------------------------------------------------------------------------------------------*/
37 /* Service parameters                                                                             */
38 /*------------------------------------------------------------------------------------------------*/
39 /*! \brief Priority of the RSM service used by scheduler */
40 static const uint8_t RTM_SRV_PRIO = 250U;   /* parasoft-suppress  MISRA2004-8_7 "Value shall be part of the module, not part of a function." */
41 /*! \brief Event for resuming the handling of routes */
42 static const Srv_Event_t RTM_EVENT_HANDLE_NEXTROUTE = 0x01U;
43 /*! \brief Event for pausing the processing of routes */
44 static const Srv_Event_t RTM_EVENT_PROCESS_PAUSE    = 0x02U;
45 /*! \brief Interval (in ms) for checking the RoutingJob queue */
46 static const uint16_t RTM_JOB_CHECK_INTERVAL = 50U;   /* parasoft-suppress  MISRA2004-8_7 "Value shall be part of the module, not part of a function." */
47
48 /*------------------------------------------------------------------------------------------------*/
49 /* Internal Constants                                                                             */
50 /*------------------------------------------------------------------------------------------------*/
51 /*! \brief Mask for the Network Availability Info */
52 static const uint32_t RTM_MASK_NETWORK_AVAILABILITY = 0x0002U;
53
54 /*------------------------------------------------------------------------------------------------*/
55 /* Internal prototypes                                                                            */
56 /*------------------------------------------------------------------------------------------------*/
57 static void Rtm_Service(void *self);
58 static void Rtm_HandleNextRoute(CRouteManagement * self);
59 static void Rtm_BuildRoute(CRouteManagement * self);
60 static void Rtm_DestroyRoute(CRouteManagement * self);
61 static bool Rtm_SetNextRouteIndex(CRouteManagement * self);
62 static void Rtm_HandleRoutingError(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr);
63 static void Rtm_ApiLocking(CRouteManagement *self, bool status);
64 static bool Rtm_IsApiFree(CRouteManagement *self);
65 static Ucs_Return_t Rtm_BuildEndPoint(CRouteManagement * self, Ucs_Rm_EndPoint_t * endpoint_ptr);
66 static Ucs_Return_t Rtm_DeactivateRouteEndPoint(CRouteManagement * self, Ucs_Rm_EndPoint_t * endpoint_ptr);
67 static Ucs_Rm_Route_t * Rtm_GetNextRoute(CRouteManagement * self);
68 static bool Rtm_IsRouteBuildable(CRouteManagement * self);
69 static bool Rtm_IsRouteDestructible(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr);
70 static bool Rtm_IsRouteActivatable(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr);
71 static void Rtm_DisableRoute(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr);
72 static void Rtm_EnableRoute(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr);
73 static bool Rtm_CheckEpResultSeverity(CRouteManagement * self, Ucs_Rm_Route_t * tgt_route_ptr, Ucs_Rm_EndPoint_t * endpoint_ptr);
74 static void Rtm_EndPointDeterioredCb(void *self, void *result_ptr);
75 static void Rtm_StartTmr4HandlingRoutes(CRouteManagement * self);
76 static void Rtm_ExecRoutesHandling(void * self);
77 static void Rtm_HandleProcessTermination(CRouteManagement * self);
78 static void Rtm_StopRoutesHandling(CRouteManagement * self);
79 static void Rtm_StartRoutingTimer (CRouteManagement * self);
80 static void Rtm_ResetNodesAvailable(CRouteManagement * self);
81 static bool Rtm_AreRouteNodesAvailable(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr);
82 static bool Rtm_UnlockPossibleBlockings(CRouteManagement * self, Ucs_Rm_Route_t * tgt_route_ptr, Ucs_Rm_EndPoint_t * endpoint_ptr);
83 static void Rtm_ReleaseSuspendedRoutes(CRouteManagement * self,  Ucs_Rm_Node_t *node_ptr);
84 static void Rtm_ForcesRouteToIdle(CRouteManagement * self,  Ucs_Rm_Route_t * route_ptr);
85 static void Rtm_UcsInitSucceededCb(void *self, void *event_ptr);
86 static void Rtm_MnsNwStatusInfosCb(void *self, void *event_ptr);
87 static void Rtm_UninitializeService(void *self, void *error_code_ptr);
88
89 /*------------------------------------------------------------------------------------------------*/
90 /* Implementation of class CRouteManagement                                                       */
91 /*------------------------------------------------------------------------------------------------*/
92 /*------------------------------------------------------------------------------------------------*/
93 /* Initialization Methods                                                                         */
94 /*------------------------------------------------------------------------------------------------*/
95 /*! \brief Constructor of the Remote Sync Manager class.
96  *  \param self        Instance pointer
97  *  \param init_ptr    init data_ptr
98  */
99 void Rtm_Ctor(CRouteManagement *self, Rtm_InitData_t *init_ptr)
100 {
101     MISC_MEM_SET(self, 0, sizeof(CRouteManagement));
102
103     /* Init all reference instances */
104     self->base_ptr = init_ptr->base_ptr;
105     self->epm_ptr  = init_ptr->epm_ptr;
106     self->tm_ptr   = &init_ptr->base_ptr->tm;
107     self->net_ptr  = init_ptr->net_ptr;
108     self->report_fptr = init_ptr->report_fptr;
109
110     /* Initialize Route Management service */
111     Srv_Ctor(&self->rtm_srv, RTM_SRV_PRIO, self, &Rtm_Service);
112
113     /* Add Observer for UCS initialization Result */
114     Mobs_Ctor(&self->ucsinit_observer, self, EH_E_INIT_SUCCEEDED, &Rtm_UcsInitSucceededCb);
115     Eh_AddObsrvInternalEvent(&self->base_ptr->eh, &self->ucsinit_observer);
116
117     /* Init and Add observer to the UCS termination event */
118     Mobs_Ctor(&self->ucstermination_observer, self, EH_M_TERMINATION_EVENTS, &Rtm_UninitializeService);
119     Eh_AddObsrvInternalEvent(&self->base_ptr->eh, &self->ucstermination_observer);
120
121     /* Add RTM service to scheduler */
122     (void)Scd_AddService(&self->base_ptr->scd, &self->rtm_srv);
123 }
124
125 /*------------------------------------------------------------------------------------------------*/
126 /* Service                                                                                        */
127 /*------------------------------------------------------------------------------------------------*/
128 /*! \brief Starts the process to buildup the given routes list.
129  *    
130  *  This function shall only be called once.
131  *  \param self                  Instance pointer
132  *  \param routes_list           Routes list to be built 
133  *  \param size                  Size of the routes list
134  *  \return Possible return values are
135  *          - \c UCS_RET_ERR_API_LOCKED the API is locked. 
136  *          - \c UCS_RET_SUCCESS if the transmission was started successfully
137  *          - \c UCS_RET_ERR_BUFFER_OVERFLOW if no TxHandles available
138  *          - \c UCS_RET_ERR_PARAM At least one parameter is wrong
139  */
140 Ucs_Return_t Rtm_StartProcess(CRouteManagement * self,  Ucs_Rm_Route_t routes_list[], uint16_t size)
141 {
142     Ucs_Return_t result = UCS_RET_ERR_API_LOCKED;
143
144     if (Rtm_IsApiFree(self) != false)
145     {
146         result = UCS_RET_ERR_PARAM;
147         if ((self != NULL) && (routes_list != NULL) && (size > 0U))
148         {
149             uint8_t k = 0U;
150             /* Function remains from now locked */
151             Rtm_ApiLocking(self, true);
152
153             /* Initializes private variables */
154             self->routes_list_size = size;
155             self->curr_route_index = 0U;
156             self->routes_list_ptr  = &routes_list[0];
157
158             /* Initializes internal data structure */
159             for (; k < size; k++)
160             {
161                 MISC_MEM_SET(&routes_list[k].internal_infos, 0, sizeof(Ucs_Rm_RouteInt_t));
162             }
163
164             Rtm_StartTmr4HandlingRoutes(self);
165             result = UCS_RET_SUCCESS;
166         }
167     }
168
169     return result;
170 }
171
172 /*! \brief Deactivates respectively destroys the given route reference
173  *  \param self                 Instance pointer
174  *  \param route_ptr            Reference to the route to be destroyed 
175  *  \return Possible return values are
176  *          - \c UCS_RET_SUCCESS if the transmission was started successfully
177  *          - \c UCS_RET_ERR_PARAM At least one parameter is NULL
178  *          - \c UCS_RET_ERR_ALREADY_SET Route is already inactive
179  */
180 Ucs_Return_t Rtm_DeactivateRoute (CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
181 {
182     Ucs_Return_t result = UCS_RET_ERR_PARAM;
183
184     if ((self != NULL) && (route_ptr != NULL))
185     {
186         if (Rtm_IsRouteDestructible(self, route_ptr))
187         {
188             Rtm_DisableRoute(self, route_ptr);
189             Rtm_StartTmr4HandlingRoutes(self);
190             result = UCS_RET_SUCCESS;
191         }
192         else
193         {
194             result = UCS_RET_ERR_ALREADY_SET;
195         }
196     }
197
198     return result;
199 }
200
201 /*! \brief Builds respectively activates the given route reference
202  *  \param self                 Instance pointer
203  *  \param route_ptr            Reference to the route to be destroyed 
204  *  \return Possible return values are
205  *          - \c UCS_RET_SUCCESS if the transmission was started successfully
206  *          - \c UCS_RET_ERR_PARAM At least one parameter is NULL
207  *          - \c UCS_RET_ERR_ALREADY_SET Route is already active
208  */
209 Ucs_Return_t Rtm_ActivateRoute(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
210 {
211     Ucs_Return_t result = UCS_RET_ERR_PARAM;
212
213     if ((self != NULL) && (route_ptr != NULL))
214     {
215         if (Rtm_IsRouteActivatable(self, route_ptr))
216         {
217             Rtm_EnableRoute(self, route_ptr);
218             Rtm_StartTmr4HandlingRoutes(self);
219             result = UCS_RET_SUCCESS;
220         }
221         else
222         {
223             result = UCS_RET_ERR_ALREADY_SET;
224         }
225     }
226
227     return result;
228 }
229
230 /*! \brief   Sets the given node to \c available or \c not \c available and triggers the routing process to handle this change.
231  *  \details In case of \c Available the function starts the routing process that checks whether there are endpoints to build on this node.
232  *  In case of \c Unavailable the function informs sub modules like XRM to check whether there are resources to release and simultaneously unlock \c suspended routes that
233  *  link to this node.
234  *  \param   self                   The routing instance pointer
235  *  \param   node_ptr               Reference to the node to be looked for.
236  *  \param   available              Specifies whether the node is available or not
237  *  \return  Possible return values are shown in the table below.
238  *           Value                       | Description 
239  *           --------------------------- | ---------------------------------------------------------------------
240  *           UCS_RET_SUCCESS             | No error
241  *           UCS_RET_ERR_ALREADY_SET     | Node is already set to "available" or "not available"
242  *           UCS_RET_ERR_PARAM           | At least one parameter is NULL.
243  *           UCS_RET_ERR_NOT_INITIALIZED | UNICENS is not initialized
244  *           UCS_RET_ERR_NOT_AVAILABLE   | The function cannot be processed because the network is not available
245  */
246 Ucs_Return_t Rtm_SetNodeAvailable(CRouteManagement * self, Ucs_Rm_Node_t *node_ptr, bool available)
247 {
248     Ucs_Return_t ret_val = UCS_RET_ERR_PARAM;
249
250     if ((self != NULL) && (node_ptr != NULL) && (node_ptr->signature_ptr != NULL))
251     {
252         ret_val = UCS_RET_ERR_NOT_AVAILABLE;
253         if (self->nw_available)
254         {
255             ret_val = UCS_RET_ERR_ALREADY_SET;
256             if (available)
257             {
258                 if (node_ptr->internal_infos.available == 0x00U)
259                 {
260                     TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Node with Addr {%X} is available", 1U, node_ptr->signature_ptr->node_address));
261                     node_ptr->internal_infos.available = 0x01U;
262                     Rtm_StartRoutingTimer(self);
263                     ret_val = UCS_RET_SUCCESS;
264                 }
265             }
266             else
267             {
268                 if (node_ptr->internal_infos.available == 0x01U)
269                 {
270                     TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Node with Addr {%X} is not available", 1U, node_ptr->signature_ptr->node_address));
271                     node_ptr->internal_infos.available = 0x00U;
272                     Rtm_ReleaseSuspendedRoutes(self, node_ptr);
273                     Epm_ReportInvalidDevice (self->epm_ptr, node_ptr->signature_ptr->node_address);
274                     ret_val = UCS_RET_SUCCESS;
275                 }
276             }
277         }
278     }
279
280     return ret_val;
281 }
282
283 /*! \brief   Retrieves the "available" flag of the given node.
284  *  \param   self                   The routing instance pointer
285  *  \param   node_ptr               Reference to the node to be looked for.
286  *  \return  The "available" flag of the node. 
287  */
288 bool Rtm_GetNodeAvailable(CRouteManagement * self, Ucs_Rm_Node_t *node_ptr)
289 {
290     bool ret_val = false;
291
292     MISC_UNUSED (self);
293
294     if (node_ptr != NULL)
295     {
296         ret_val = (node_ptr->internal_infos.available == 0x01U) ? true:false;
297     }
298
299     return ret_val;
300 }
301
302 /*! \brief   Retrieves currently references of all routes attached to the given endpoint and stores It into an external routes table provided by user application.
303  *           Thus, User application should provide an external reference to an empty routes table where the potential routes will be stored.
304  *           That is, user application is responsible to allocate enough space to store the found routes. Otherwise, the max routes found will 
305  *           equal the list size.
306  *  \param   self                    The routing instance pointer
307  *  \param   ep_inst                 Reference to the endpoint to be looked for.
308  *  \param   ext_routes_list         External empty table allocated by user application
309  *  \param   size_list               Size of the provided list
310  *  \return  Possible return values are shown in the table below.
311  *           Value                       | Description 
312  *           --------------------------- | ---------------------------------------------------------------------
313  *           UCS_RET_SUCCESS             | No error
314  *           UCS_RET_ERR_PARAM           | At least one parameter is NULL.
315  */
316 Ucs_Return_t Rtm_GetAttachedRoutes(CRouteManagement * self, Ucs_Rm_EndPoint_t * ep_inst, 
317                                    Ucs_Rm_Route_t * ext_routes_list[], uint16_t size_list)
318 {
319     Ucs_Return_t ret_val = UCS_RET_ERR_PARAM;
320
321     MISC_UNUSED (self);
322
323     if ((ep_inst != NULL) && (ext_routes_list != NULL) && (size_list > 0U))
324     {
325         bool curr_index_empty = true;
326         uint8_t k = 0U, num_attached_routes = Sub_GetNumObservers(&ep_inst->internal_infos.subject_obj);
327         CDlNode *n_tmp = (&(ep_inst->internal_infos.subject_obj))->list.head;
328         Ucs_Rm_Route_t * tmp_rt = NULL;
329         ret_val = UCS_RET_SUCCESS;
330
331         for (; ((k < size_list) && (num_attached_routes > 0U) && (n_tmp != NULL)); k++)
332         {
333             ext_routes_list[k] = NULL;
334             do 
335             {
336                 CObserver *o_tmp = (CObserver *)n_tmp->data_ptr;
337                 tmp_rt = (Ucs_Rm_Route_t *)o_tmp->inst_ptr;
338                 if ((tmp_rt != NULL) && ((tmp_rt->internal_infos.route_state == UCS_RM_ROUTE_BUILT) ||
339                     (tmp_rt->internal_infos.route_state == UCS_RM_ROUTE_CONSTRUCTION) ||
340                     (tmp_rt->internal_infos.route_state == UCS_RM_ROUTE_DESTRUCTION)))
341                 {
342                     curr_index_empty   = false;
343                     ext_routes_list[k] = tmp_rt;
344                 }
345                 n_tmp = n_tmp->next;
346                 num_attached_routes--;
347                
348             } while ((curr_index_empty) && (num_attached_routes > 0U));
349             curr_index_empty = true;
350         }
351
352         if (k < size_list)
353         {
354             ext_routes_list[k] = NULL;
355         }
356     }
357
358     return ret_val;
359 }
360
361 /*! \brief   Retrieves the \c ConnectionLabel of the given route.
362  *  \param   self        The routing instance pointer
363  *  \param   route_ptr   Reference to the route to be looked for.
364  *  \return  The "ConnectionLabel" of this route.
365  */
366 uint16_t Rtm_GetConnectionLabel (CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
367 {
368     uint16_t conn_label = 0U;
369
370     if ((self != NULL) && (route_ptr != NULL) && (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_BUILT))
371     {
372         conn_label = Epm_GetConnectionLabel(self->epm_ptr, route_ptr->source_endpoint_ptr);
373     }
374
375     return conn_label;
376 }
377
378 /*------------------------------------------------------------------------------------------------*/
379 /* Private Methods                                                                                */
380 /*------------------------------------------------------------------------------------------------*/
381 /*! \brief Service function of the Sync management.
382  *  \param self    Instance pointer
383  */
384 static void Rtm_Service(void *self)
385 {
386     CRouteManagement *self_ = (CRouteManagement *)self;
387     Srv_Event_t event_mask;
388     Srv_GetEvent(&self_->rtm_srv, &event_mask);
389
390     /* Event to process list of routes */
391     if((event_mask & RTM_EVENT_HANDLE_NEXTROUTE) == RTM_EVENT_HANDLE_NEXTROUTE)
392     {
393         Srv_ClearEvent(&self_->rtm_srv, RTM_EVENT_HANDLE_NEXTROUTE);
394         Rtm_HandleNextRoute(self_);
395     }
396
397     /* Event to pause processing of routes list */
398     if ((event_mask & RTM_EVENT_PROCESS_PAUSE) == RTM_EVENT_PROCESS_PAUSE)
399     {
400         Srv_ClearEvent(&self_->rtm_srv, RTM_EVENT_PROCESS_PAUSE);
401         Rtm_StopRoutesHandling(self_);
402     }
403 }
404
405 /*! \brief This function starts the routing timer.
406  *
407  *  Whenever this function is called the routing management process will resume in case it has been paused.
408  *  \param self Instance pointer
409  */
410 static void Rtm_StartRoutingTimer (CRouteManagement * self)
411 {
412     if ((NULL != self) && (NULL != self->routes_list_ptr) &&
413         (0U < self->routes_list_size))
414     {
415         Rtm_StartTmr4HandlingRoutes(self);
416     }
417 }
418
419 /*! \brief Handles the next route in the list.
420  *  \param self    Instance pointer
421  */
422 static void Rtm_HandleNextRoute(CRouteManagement * self)
423 {
424     Ucs_Rm_Route_t * tmp_route;
425     self->curr_route_ptr = Rtm_GetNextRoute(self);
426     tmp_route = self->curr_route_ptr; 
427
428     switch (tmp_route->internal_infos.route_state)
429     {
430     case UCS_RM_ROUTE_IDLE:
431         if (Rtm_IsRouteBuildable(self) == true)
432         {
433             Rtm_BuildRoute(self);
434         }
435         break;
436
437     case UCS_RM_ROUTE_CONSTRUCTION:
438         Rtm_BuildRoute(self);
439         break;
440
441     case UCS_RM_ROUTE_DETERIORATED:
442         Rtm_HandleRoutingError(self, tmp_route);
443         break;
444
445     case UCS_RM_ROUTE_DESTRUCTION:
446         Rtm_DestroyRoute(self);
447         break;
448
449     case UCS_RM_ROUTE_SUSPENDED:
450     case UCS_RM_ROUTE_BUILT:
451         if (tmp_route->active == false) 
452         {
453             Rtm_DestroyRoute(self);
454         }
455         break;
456
457     default:
458         break;
459     }
460 }
461
462 /*! \brief  Checks whether the given route is buildable.
463  *  \param  self        Instance pointer
464  *  \return \c true if the route is buildable, otherwise \c false.
465  */
466 static bool Rtm_IsRouteBuildable(CRouteManagement * self)
467 {
468     bool result_check = false;
469
470     if (self->curr_route_ptr != NULL)
471     {
472         if ((self->curr_route_ptr->internal_infos.route_state == UCS_RM_ROUTE_IDLE) &&
473             (self->curr_route_ptr->active == true) &&
474             (self->curr_route_ptr->source_endpoint_ptr != NULL) && 
475             (self->curr_route_ptr->sink_endpoint_ptr != NULL))
476         {
477             result_check = true;
478         }
479     }
480
481     return result_check;
482 }
483
484 /*! \brief  Checks whether the given route is destructible.
485  *  \param  self        Instance pointer
486  *  \param  route_ptr   Reference route to be checked
487  *  \return \c true if the route is destructible, otherwise \c false.
488  */
489 static bool Rtm_IsRouteDestructible(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
490 {
491     bool result_check = false;
492     MISC_UNUSED (self);
493
494     if ((route_ptr != NULL) && (route_ptr->active == 0x01U) && ((route_ptr->internal_infos.route_state == UCS_RM_ROUTE_BUILT) ||
495         (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_SUSPENDED)))
496     {
497         result_check = true;
498     }
499
500     return result_check;
501 }
502
503 /*! \brief  Checks whether the given route can be activated.
504  *  \param  self        Instance pointer
505  *  \param  route_ptr   Reference route to be checked
506  *  \return \c true if the route is destructible, otherwise \c false.
507  */
508 static bool Rtm_IsRouteActivatable(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
509 {
510     bool result_check = false;
511     MISC_UNUSED (self);
512
513     if ((route_ptr != NULL)  && (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_IDLE) && (route_ptr->active == 0x0U))
514     {
515         result_check = true;
516     }
517
518     return result_check;
519 }
520
521 /*! \brief  Deactivates the given route reference.
522  *  \param  self        Instance pointer
523  *  \param  route_ptr   Reference route to be deactivated
524  */
525 static void Rtm_DisableRoute(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
526 {
527     MISC_UNUSED (self);
528
529     if (route_ptr != NULL)
530     {
531         route_ptr->active = false;
532     }
533 }
534
535 /*! \brief  Activates the given route reference.
536  *  \param  self        Instance pointer
537  *  \param  route_ptr   Reference route to be activated
538  */
539 static void Rtm_EnableRoute(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
540 {
541     MISC_UNUSED (self);
542
543     if (route_ptr != NULL)
544     {
545         route_ptr->active = true;
546     }
547 }
548
549 /*! \brief Builds the current Route.
550  *  \param self    Instance pointer
551  */
552 static void Rtm_BuildRoute(CRouteManagement * self)
553 {
554     bool result_critical = false;
555     Ucs_Rm_EndPointState_t ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr);
556     switch (ep_state)
557     {
558     case UCS_RM_EP_IDLE:
559         result_critical = Rtm_CheckEpResultSeverity(self, self->curr_route_ptr, self->curr_route_ptr->source_endpoint_ptr);
560         if (!result_critical)
561         {
562             if (self->curr_route_ptr->internal_infos.src_obsvr_initialized == 0U)
563             {
564                 self->curr_route_ptr->internal_infos.src_obsvr_initialized = 1U;
565                 Epm_DelObserver(self->curr_route_ptr->source_endpoint_ptr, &self->curr_route_ptr->internal_infos.source_ep_observer);
566                 Obs_Ctor(&self->curr_route_ptr->internal_infos.source_ep_observer, self->curr_route_ptr, &Rtm_EndPointDeterioredCb);
567                 /* Initializes source endpoint internal data */
568                 Epm_InitInternalInfos (self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr);
569             }
570             (void)Rtm_BuildEndPoint(self, self->curr_route_ptr->source_endpoint_ptr);
571         }
572         break;
573
574     case UCS_RM_EP_BUILT:
575         /* In case of shared source endpoint by another route */
576         if (self->curr_route_ptr->internal_infos.src_obsvr_initialized == 0U)
577         {
578             self->curr_route_ptr->internal_infos.src_obsvr_initialized = 1U;
579             Epm_DelObserver(self->curr_route_ptr->source_endpoint_ptr, &self->curr_route_ptr->internal_infos.source_ep_observer);
580             Obs_Ctor(&self->curr_route_ptr->internal_infos.source_ep_observer, self->curr_route_ptr, &Rtm_EndPointDeterioredCb);
581             Epm_AddObserver(self->curr_route_ptr->source_endpoint_ptr, &self->curr_route_ptr->internal_infos.source_ep_observer);
582         }
583         ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr);
584         switch(ep_state)
585         {
586             case UCS_RM_EP_IDLE:
587                 result_critical = Rtm_CheckEpResultSeverity(self, self->curr_route_ptr, self->curr_route_ptr->sink_endpoint_ptr);
588                 if (!result_critical)
589                 {
590                     if (self->curr_route_ptr->internal_infos.sink_obsvr_initialized == 0U)
591                     {
592                         self->curr_route_ptr->internal_infos.sink_obsvr_initialized = 1U;
593                         Obs_Ctor(&self->curr_route_ptr->internal_infos.sink_ep_observer, self->curr_route_ptr, &Rtm_EndPointDeterioredCb);
594                         /* Initializes sink endpoint internal data */
595                         Epm_InitInternalInfos (self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr);
596                     }
597                     Epm_SetConnectionLabel(self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr, Epm_GetConnectionLabel(self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr));
598                     (void)Rtm_BuildEndPoint(self, self->curr_route_ptr->sink_endpoint_ptr);
599                 }
600                 break;
601
602             case UCS_RM_EP_BUILT:
603                 TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is built", 1U, self->curr_route_ptr->route_id));
604                 self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_BUILT;
605                 if (self->report_fptr != NULL)
606                 {
607                     self->report_fptr(self->curr_route_ptr, UCS_RM_ROUTE_INFOS_BUILT, self->base_ptr->ucs_user_ptr);
608                 }
609                 break;
610
611             case UCS_RM_EP_XRMPROCESSING:
612             default:
613                 result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->sink_endpoint_ptr);
614                 break;
615         }
616         break;
617
618     case UCS_RM_EP_XRMPROCESSING:
619     default:
620         result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->source_endpoint_ptr);
621         break;
622     }
623
624     if (result_critical)
625     {
626         self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_DETERIORATED;
627     }
628 }
629
630 /*! \brief Destroys the current Route.
631  *  \param self    Instance pointer
632  */
633 static void Rtm_DestroyRoute(CRouteManagement * self)
634 {
635     bool result_critical = false;
636     bool destruction_completed = false;
637
638     Ucs_Rm_EndPointState_t ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr);
639     switch (ep_state)
640     {
641     case UCS_RM_EP_BUILT:
642         (void)Rtm_DeactivateRouteEndPoint(self, self->curr_route_ptr->sink_endpoint_ptr);
643         break;
644
645     case UCS_RM_EP_IDLE:
646         ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr);
647         switch(ep_state)
648         {
649             case UCS_RM_EP_BUILT:
650                 /* if source endpoint cannot be built since it's used in another route(s), however consider that the route is destroyed. */
651                 if (Rtm_DeactivateRouteEndPoint(self, self->curr_route_ptr->source_endpoint_ptr) == UCS_RET_ERR_INVALID_SHADOW)
652                 {
653                     destruction_completed = true;
654                 }
655                 break;
656
657             case UCS_RM_EP_IDLE:
658                 destruction_completed = true;
659                 break;
660
661             case UCS_RM_EP_XRMPROCESSING:
662             default:
663                 result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->source_endpoint_ptr);
664                 break;
665         }
666         break;
667
668     case UCS_RM_EP_XRMPROCESSING:
669     default:
670         result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->sink_endpoint_ptr);
671         break;
672     }
673
674     if (result_critical)
675     {
676         self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_DETERIORATED;
677     }
678     else if (destruction_completed)
679     {
680         TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} has been destroyed", 1U, self->curr_route_ptr->route_id));
681         self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_IDLE;
682         self->curr_route_ptr->internal_infos.src_obsvr_initialized = 0U;
683
684         if (self->report_fptr != NULL)
685         {
686             self->report_fptr(self->curr_route_ptr, UCS_RM_ROUTE_INFOS_DESTROYED, self->base_ptr->ucs_user_ptr);
687         }
688     }
689 }
690
691 /*! \brief  Builds the given endpoint.
692  *  \param  self           Instance pointer
693  *  \param  endpoint_ptr   Reference to the endpoint to be looked for
694  *  \return Possible return values are
695  *          - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed.
696  *          - \c UCS_RET_SUCCESS the build process was set successfully
697  *          - \c UCS_RET_ERR_PARAM NULL pointer detected in the parameter list
698  *          - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set
699  */
700 static Ucs_Return_t Rtm_BuildEndPoint(CRouteManagement * self, Ucs_Rm_EndPoint_t * endpoint_ptr)
701 {
702     Ucs_Return_t result = UCS_RET_ERR_PARAM;
703
704     if ((self != NULL)  && (endpoint_ptr != NULL))
705     {
706         result = Epm_SetBuildProcess(self->epm_ptr, endpoint_ptr);
707         if (result == UCS_RET_SUCCESS)
708         {
709             Epm_AddObserver (endpoint_ptr,  (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? &self->curr_route_ptr->internal_infos.source_ep_observer: &self->curr_route_ptr->internal_infos.sink_ep_observer);
710             self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_CONSTRUCTION;
711             TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Start Building Endpoint {%X} of type %s for route id %X", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id));
712         }
713         else if (result == UCS_RET_ERR_ALREADY_SET)
714         {
715             TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X has already been built", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id));
716         }
717     }
718
719     return result;
720 }
721
722 /*! \brief  Destroys the given endpoint.
723  *  \param  self           Instance pointer
724  *  \param  endpoint_ptr   Reference to the endpoint to be looked for
725  *  \return Possible return values are
726  *          - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed.
727  *          - \c UCS_RET_SUCCESS the build process was set successfully
728  *          - \c UCS_RET_ERR_PARAM NULL pointer detected in the parameter list
729  *          - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set
730  *          - \c UCS_RET_ERR_NOT_AVAILABLE the endpoint is no more available.
731  *          - \c UCS_RET_ERR_INVALID_SHADOW the endpoint cannot be destroyed since it's still in use by another routes.
732  */
733 static Ucs_Return_t Rtm_DeactivateRouteEndPoint(CRouteManagement * self, Ucs_Rm_EndPoint_t * endpoint_ptr)
734 {
735     Ucs_Return_t result = UCS_RET_ERR_PARAM;
736
737     if ((self != NULL) && (endpoint_ptr != NULL) && (endpoint_ptr->node_obj_ptr != NULL) &&
738         (endpoint_ptr->node_obj_ptr->signature_ptr != NULL))
739     {
740         if ((endpoint_ptr->node_obj_ptr->internal_infos.available == 1U) ||
741             (endpoint_ptr->node_obj_ptr->signature_ptr->node_address == UCS_ADDR_LOCAL_DEV))
742         {
743             result = Epm_SetDestroyProcess(self->epm_ptr, endpoint_ptr);
744             if (result == UCS_RET_SUCCESS)
745             {
746                 self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_DESTRUCTION;
747                 TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Start Destroying Endpoint {%X} of type %s for route id %X", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id));
748             }
749             else if (result == UCS_RET_ERR_ALREADY_SET)
750             {
751                 TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X has already been destroyed", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id));
752             }
753             else if (result == UCS_RET_ERR_INVALID_SHADOW)
754             {
755                 TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X cannot be destroyed since it's still used", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id));
756             }
757             else if (result == UCS_RET_ERR_NOT_AVAILABLE)
758             {
759                 TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X is no more available", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source" : "Sink", self->curr_route_ptr->route_id));
760             }
761         }
762         else
763         {
764             /* Completed */
765             Epm_ResetState(self->epm_ptr, endpoint_ptr);
766         }
767     }
768
769     return result;
770 }
771
772 /*! \brief Classifies and sets the corresponding route error and then informs user about the new state.
773  *  \param self       Instance pointer
774  *  \param route_ptr  Reference to the route to be looked for
775  */
776 static void Rtm_HandleRoutingError(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
777 {
778     Ucs_Rm_Route_t * tmp_route = route_ptr;
779     Ucs_Rm_RouteInfos_t result_route = UCS_RM_ROUTE_INFOS_DESTROYED;
780     Ucs_Rm_RouteResult_t res_rt = tmp_route->internal_infos.last_route_result;
781
782     tmp_route->internal_infos.route_state = UCS_RM_ROUTE_IDLE;
783     tmp_route->internal_infos.last_route_result = UCS_RM_ROUTE_NOERROR;
784
785     if (res_rt != UCS_RM_ROUTE_CRITICAL)
786     {
787         if (tmp_route->source_endpoint_ptr->internal_infos.endpoint_state == UCS_RM_EP_IDLE)
788         {
789             if (Rtm_CheckEpResultSeverity(self, tmp_route, tmp_route->source_endpoint_ptr))
790             {
791                 Epm_ResetState(self->epm_ptr, tmp_route->source_endpoint_ptr);
792                 tmp_route->internal_infos.route_state = UCS_RM_ROUTE_SUSPENDED;
793                 result_route = UCS_RM_ROUTE_INFOS_SUSPENDED;
794                 TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is suspended", 1U, tmp_route->route_id));
795             }
796         }
797         else if (tmp_route->sink_endpoint_ptr->internal_infos.endpoint_state == UCS_RM_EP_IDLE)
798         {
799             if (Rtm_CheckEpResultSeverity(self, tmp_route, tmp_route->sink_endpoint_ptr))
800             {
801                 Epm_ResetState(self->epm_ptr, tmp_route->sink_endpoint_ptr);
802                 tmp_route->internal_infos.route_state = UCS_RM_ROUTE_SUSPENDED;
803                 result_route = UCS_RM_ROUTE_INFOS_SUSPENDED;
804                 TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is suspended", 1U, tmp_route->route_id));
805             }
806         }
807         else
808         {
809             TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is destroyed", 1U, tmp_route->route_id));
810         }
811     }
812     else
813     {
814         Epm_ResetState(self->epm_ptr, tmp_route->source_endpoint_ptr);
815         Epm_ResetState(self->epm_ptr, tmp_route->sink_endpoint_ptr);
816         tmp_route->internal_infos.route_state = UCS_RM_ROUTE_SUSPENDED;
817         result_route = UCS_RM_ROUTE_INFOS_SUSPENDED;
818         TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is suspended", 1U, tmp_route->route_id));
819     }
820
821     if (self->report_fptr != NULL)
822     {
823         self->report_fptr(tmp_route, result_route, self->base_ptr->ucs_user_ptr);
824     }
825 }
826
827 /*! \brief  Checks whether the endpoint's result is critical or not and stores the result into the target route.
828  *  \param  self           Instance pointer
829  *  \param  tgt_route_ptr  Reference to the route that contains the endpoint to be looked for
830  *  \param  endpoint_ptr   Reference to the endpoint to be looked for
831  *  \return \c true if the endpoint result is critical, otherwise \c false.
832  */
833 static bool Rtm_CheckEpResultSeverity(CRouteManagement * self, Ucs_Rm_Route_t * tgt_route_ptr, Ucs_Rm_EndPoint_t * endpoint_ptr)
834 {
835     bool result_check = false;
836     Ucs_Rm_RouteResult_t result = UCS_RM_ROUTE_NOERROR;
837     /*! \brief Maximum number of retries allowed in error situation */
838     uint8_t RTM_MAX_NUM_RETRIES_IN_ERR = 0xFFU;
839
840     if ((endpoint_ptr != NULL) && (tgt_route_ptr != NULL))
841     {
842         switch (endpoint_ptr->internal_infos.xrm_result.code)
843         {
844         case UCS_XRM_RES_ERR_BUILD:
845         case UCS_XRM_RES_ERR_DESTROY:
846         case UCS_XRM_RES_ERR_SYNC:
847             switch (endpoint_ptr->internal_infos.xrm_result.details.result_type)
848             {
849             case UCS_XRM_RESULT_TYPE_TX:
850                 if ((UCS_MSG_STAT_ERROR_CFG_NO_RCVR == endpoint_ptr->internal_infos.xrm_result.details.tx_result) ||
851                     (UCS_MSG_STAT_ERROR_FATAL_OA == endpoint_ptr->internal_infos.xrm_result.details.tx_result)    ||
852                     (endpoint_ptr->internal_infos.num_retries == RTM_MAX_NUM_RETRIES_IN_ERR))
853                 {
854                     result = UCS_RM_ROUTE_CRITICAL;
855                     TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "Critical error occurred on route id {%X} due to the transmission error code {Ucs_MsgTxStatus_t:0x%02X} observed in XRM.", 2U,
856                         tgt_route_ptr->route_id, endpoint_ptr->internal_infos.xrm_result.details.tx_result));
857                 }
858                 else if ((UCS_MSG_STAT_ERROR_UNKNOWN == endpoint_ptr->internal_infos.xrm_result.details.tx_result)     ||
859                          (UCS_MSG_STAT_ERROR_FATAL_WT == endpoint_ptr->internal_infos.xrm_result.details.tx_result)    ||
860                          (UCS_MSG_STAT_ERROR_TIMEOUT == endpoint_ptr->internal_infos.xrm_result.details.tx_result)     ||                     
861                          (UCS_MSG_STAT_ERROR_BF  == endpoint_ptr->internal_infos.xrm_result.details.tx_result)         ||
862                          (UCS_MSG_STAT_ERROR_CRC == endpoint_ptr->internal_infos.xrm_result.details.tx_result)         ||
863                          (UCS_MSG_STAT_ERROR_NA_TRANS == endpoint_ptr->internal_infos.xrm_result.details.tx_result)    ||
864                          (UCS_MSG_STAT_ERROR_ACK == endpoint_ptr->internal_infos.xrm_result.details.tx_result)         ||
865                          (UCS_MSG_STAT_ERROR_ID == endpoint_ptr->internal_infos.xrm_result.details.tx_result))
866                 {
867                     endpoint_ptr->internal_infos.num_retries++;
868                     result = UCS_RM_ROUTE_UNCRITICAL;
869                 }
870                 break;
871
872             case UCS_XRM_RESULT_TYPE_TGT:
873                 if ((UCS_RES_ERR_CONFIGURATION == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code) ||
874                     (UCS_RES_ERR_MOST_STANDARD == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code) ||
875                     (UCS_RES_ERR_SYSTEM == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code)        ||
876                     (endpoint_ptr->internal_infos.num_retries == RTM_MAX_NUM_RETRIES_IN_ERR))
877                 {
878                     result = UCS_RM_ROUTE_CRITICAL;
879                     TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "Critical error occurred on route id {%X} due to the INIC result code {Ucs_Result_t:0x%02X} observed in XRM.", 2U,
880                         tgt_route_ptr->route_id, endpoint_ptr->internal_infos.xrm_result.details.inic_result.code));
881                 }
882                 else if ((UCS_RES_ERR_BUSY == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code)       ||
883                          (UCS_RES_ERR_TIMEOUT == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code)    ||
884                          (UCS_RES_ERR_PROCESSING == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code))
885                 {
886                     endpoint_ptr->internal_infos.num_retries++;
887                     result = UCS_RM_ROUTE_UNCRITICAL;
888                 }
889                 break;
890
891             case UCS_XRM_RESULT_TYPE_INT:
892                 if ((endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_NOT_AVAILABLE)   ||
893                     (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_NOT_SUPPORTED)   ||
894                     (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_PARAM)           ||
895                     (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_NOT_INITIALIZED) ||
896                     (endpoint_ptr->internal_infos.num_retries == RTM_MAX_NUM_RETRIES_IN_ERR))
897                 {
898                     result = UCS_RM_ROUTE_CRITICAL;
899                     TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "Critical error occurred on route id {%X} due to the internal error code {Ucs_Return_t:0x%02X} observed in XRM.", 2U,
900                         tgt_route_ptr->route_id, endpoint_ptr->internal_infos.xrm_result.details.int_result));
901                 }
902                 else if ((endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_BUFFER_OVERFLOW) ||
903                          (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_API_LOCKED)      ||
904                          (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_INVALID_SHADOW))
905                 {
906                     endpoint_ptr->internal_infos.num_retries++;
907                     result = UCS_RM_ROUTE_UNCRITICAL;
908                 }
909                 break;
910
911             default:
912                 break;
913             }
914             break;
915
916         case UCS_XRM_RES_ERR_CONFIG:
917             result = UCS_RM_ROUTE_CRITICAL;
918             break;
919
920         case UCS_XRM_RES_SUCCESS_BUILD:
921         case UCS_XRM_RES_SUCCESS_DESTROY:
922             endpoint_ptr->internal_infos.num_retries = 0U;
923             break;
924
925         default:
926             break;
927         }
928
929         /* Sets route result */
930         tgt_route_ptr->internal_infos.last_route_result = result;
931         if (result == UCS_RM_ROUTE_CRITICAL)
932         {
933             result_check = true;
934         }
935     }
936
937     MISC_UNUSED(self);
938
939     return result_check;
940 }
941
942 /*! \brief Sets curr_route_ptr to the next route.
943  *  \param self    Instance pointer
944  *  \return \c true if the endpoint result is critical, otherwise \c false.
945  */
946 static bool Rtm_SetNextRouteIndex(CRouteManagement * self)
947 {
948     bool found = false;
949
950     if ((self->routes_list_size > 0U) && (self->nw_available))
951     {
952         uint16_t tmp_idx;
953         self->curr_route_index++;
954         self->curr_route_index = self->curr_route_index%self->routes_list_size;
955         tmp_idx = self->curr_route_index;
956
957         do
958         {
959             if  (((self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_SUSPENDED) && 
960                 (self->routes_list_ptr[self->curr_route_index].active == true)) ||
961                 ((self->routes_list_ptr[self->curr_route_index].active == true) &&
962                 (self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_BUILT)) ||
963                 ((self->routes_list_ptr[self->curr_route_index].active == false) && 
964                 (self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_IDLE)) || 
965                 ((Rtm_AreRouteNodesAvailable(self, &self->routes_list_ptr[self->curr_route_index]) == false) && 
966                 (self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_IDLE)))
967             {
968                 self->curr_route_index++;
969                 self->curr_route_index = self->curr_route_index%self->routes_list_size;
970             }
971             else
972             {
973                 found = true;
974             }
975         }
976         while ((tmp_idx != self->curr_route_index) &&
977                (found == false));
978     }
979
980     return found;
981 }
982
983 /*! \brief Starts the timer for handling routes.
984  *  \param self    Instance pointer
985  */
986 static void Rtm_StartTmr4HandlingRoutes(CRouteManagement * self)
987 {
988     if((T_IsTimerInUse(&self->route_check) == false) &&
989        (!self->ucs_is_stopping))
990     {
991         Tm_SetTimer(self->tm_ptr,
992                     &self->route_check,
993                     &Rtm_ExecRoutesHandling,
994                     self,
995                     RTM_JOB_CHECK_INTERVAL,
996                     RTM_JOB_CHECK_INTERVAL);
997     }
998 }
999
1000 /*! \brief Gets the next route.
1001  *  \param self    Instance pointer
1002  *  \return the next route to be handled
1003  */
1004 static Ucs_Rm_Route_t * Rtm_GetNextRoute(CRouteManagement * self)
1005 {
1006     self->routes_list_ptr[self->curr_route_index].internal_infos.rtm_inst = (Rtm_Inst_t *)(void *)self;
1007     return &self->routes_list_ptr[self->curr_route_index];
1008 }
1009
1010 /*! \brief Checks if the API is locked.
1011  *  \param self     Instance pointer
1012  *  \return \c true if the API is not locked and the UCS are initialized, otherwise \c false.
1013  */
1014 static bool Rtm_IsApiFree(CRouteManagement *self)
1015 {
1016     return (self->lock_api == false);
1017 }
1018
1019 /*! \brief Locks/Unlocks the RTM API.
1020  *  \param self     Instance pointer
1021  *  \param status   Locking status. \c true = Lock, \c false = Unlock
1022  */
1023 static void Rtm_ApiLocking(CRouteManagement *self, bool status)
1024 {
1025     self->lock_api = status;
1026 }
1027
1028 /*! \brief  Checks whether the nodes (source and sink) of the current route is available.
1029  *  \param  self       Instance pointer
1030  *  \param  route_ptr  Reference to the Route to be looked for
1031  *  \return \c true if the source endpoint's node is available, otherwise \c false.
1032  */
1033 static bool Rtm_AreRouteNodesAvailable(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr)
1034 {
1035     bool result = false;
1036     MISC_UNUSED (self);
1037
1038     if ((route_ptr->source_endpoint_ptr != NULL) && (route_ptr->sink_endpoint_ptr != NULL))
1039     {
1040         if ((route_ptr->source_endpoint_ptr->node_obj_ptr != NULL) &&
1041             (route_ptr->source_endpoint_ptr->node_obj_ptr->signature_ptr != NULL) &&
1042             (route_ptr->sink_endpoint_ptr->node_obj_ptr != NULL) &&
1043             (route_ptr->sink_endpoint_ptr->node_obj_ptr->signature_ptr != NULL))
1044         {
1045             if (((1U == route_ptr->source_endpoint_ptr->node_obj_ptr->internal_infos.available) ||
1046                 (route_ptr->source_endpoint_ptr->node_obj_ptr->signature_ptr->node_address == UCS_ADDR_LOCAL_DEV) ||
1047                 (Net_IsOwnAddress(self->net_ptr, route_ptr->source_endpoint_ptr->node_obj_ptr->signature_ptr->node_address) == NET_IS_OWN_ADDR_NODE)) &&
1048                 ((Net_IsOwnAddress(self->net_ptr, route_ptr->sink_endpoint_ptr->node_obj_ptr->signature_ptr->node_address) == NET_IS_OWN_ADDR_NODE) || 
1049                 (route_ptr->sink_endpoint_ptr->node_obj_ptr->signature_ptr->node_address == UCS_ADDR_LOCAL_DEV) ||
1050                 (1U == route_ptr->sink_endpoint_ptr->node_obj_ptr->internal_infos.available)))
1051             {
1052                 result = true;
1053             }
1054         }
1055     }
1056     else
1057     {
1058         TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "ERROR PARAMETER on route id {%X}: At least one endpoint is NULL.", 1U, route_ptr->route_id));
1059     }
1060
1061     return result;
1062 }
1063
1064 /*! \brief  Checks if we encountered a deadlock situation with the given route and if we do, resolves It by resetting the endpoint concerned.
1065  *
1066  *   Since we can encounter the situation that the construction of an endpoint fails and the routing management is not aware of that (synchronous vs asynchronous response)
1067  *   and still consider that the route is processing. In such a case the RTM process will never get a response and will wait in vain for It.
1068  *   Therefore, the role of this function is to release the blocking situation in resetting the concerned endpoint.
1069  *  \param  self           Instance pointer
1070  *  \param  tgt_route_ptr  Reference to the route that contains the endpoint to be looked for
1071  *  \param  endpoint_ptr   Reference to the endpoint to be looked for
1072  *  \return \c true if the endpoint's result is critical, otherwise \c false
1073  */
1074 static bool Rtm_UnlockPossibleBlockings(CRouteManagement * self, Ucs_Rm_Route_t * tgt_route_ptr, Ucs_Rm_EndPoint_t * endpoint_ptr)
1075 {
1076     bool result_critical = Rtm_CheckEpResultSeverity(self, tgt_route_ptr, endpoint_ptr);
1077     if (!result_critical)
1078     {
1079         if (UCS_RM_ROUTE_UNCRITICAL == self->curr_route_ptr->internal_infos.last_route_result)
1080         {
1081             Epm_ResetState(self->epm_ptr, endpoint_ptr);
1082         }
1083     }
1084     return result_critical;
1085 }
1086
1087 /*! \brief  Stops routes handling.
1088  *  \param  self    Instance pointer
1089  */
1090 static void Rtm_StopRoutesHandling(CRouteManagement * self)
1091 {
1092     Tm_ClearTimer(self->tm_ptr, &self->route_check);
1093 }
1094
1095 /*! \brief  Releases all routes endpoints and notifies that the process is terminated for all "active" routes, which are not built or suspended.
1096  *  \param  self    Instance pointer
1097  */
1098 static void Rtm_HandleProcessTermination(CRouteManagement * self)
1099 {
1100     if ((self->routes_list_ptr != NULL) && (self->routes_list_size > 0U))
1101     {
1102         uint8_t k = 0U;
1103
1104         for (; k < self->routes_list_size; k++)
1105         {
1106             Epm_ClearIntInfos(self->epm_ptr, self->routes_list_ptr[k].source_endpoint_ptr);
1107             Epm_ClearIntInfos(self->epm_ptr, self->routes_list_ptr[k].sink_endpoint_ptr);
1108
1109             if ((self->routes_list_ptr[k].active == 1U) &&
1110                 (self->routes_list_ptr[k].internal_infos.notify_termination == 0U) &&
1111                 (self->routes_list_ptr[k].internal_infos.route_state != UCS_RM_ROUTE_BUILT) &&
1112                 (self->routes_list_ptr[k].internal_infos.route_state != UCS_RM_ROUTE_SUSPENDED))
1113             {
1114                 if ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_CONSTRUCTION) ||
1115                     (self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_DESTRUCTION))
1116                 {
1117                     self->routes_list_ptr[k].internal_infos.route_state = UCS_RM_ROUTE_IDLE;
1118                 }
1119
1120                 self->routes_list_ptr[k].internal_infos.notify_termination = 0x01U;
1121                 if (self->report_fptr != NULL)
1122                 {
1123                     self->report_fptr(&self->routes_list_ptr[k], UCS_RM_ROUTE_INFOS_PROCESS_STOP, self->base_ptr->ucs_user_ptr); 
1124                 }
1125             }
1126         }
1127     }
1128 }
1129
1130 /*! \brief  Resets the availability flag of all nodes involved in routing process.
1131  *  \param  self    Instance pointer
1132  */
1133 static void Rtm_ResetNodesAvailable(CRouteManagement * self)
1134 {
1135     uint8_t k = 0U;
1136
1137     if ((self->routes_list_ptr != NULL) && (self->routes_list_size > 0U))
1138     {
1139         for (; k < self->routes_list_size; k++)
1140         {
1141             if ((self->routes_list_ptr[k].sink_endpoint_ptr != NULL) &&
1142                 (self->routes_list_ptr[k].sink_endpoint_ptr->node_obj_ptr != NULL))
1143             {
1144                 self->routes_list_ptr[k].sink_endpoint_ptr->node_obj_ptr->internal_infos.available   = 0U;
1145             }
1146
1147             if ((self->routes_list_ptr[k].source_endpoint_ptr != NULL) &&
1148                 (self->routes_list_ptr[k].source_endpoint_ptr->node_obj_ptr != NULL))
1149             {
1150                 self->routes_list_ptr[k].source_endpoint_ptr->node_obj_ptr->internal_infos.available = 0U;
1151             }
1152         }
1153     }
1154 }
1155
1156 /*! \brief  Releases all suspended routes of the given node.
1157  *  \details This function should only be called when the provided node, on which the suspended routes are, 
1158  *  is set to "not available".
1159  *  \param  self        Instance pointer
1160  *  \param  node_ptr    Reference to the node to be looked for
1161  */
1162 static void Rtm_ReleaseSuspendedRoutes(CRouteManagement * self, Ucs_Rm_Node_t *node_ptr)
1163 {
1164     uint8_t k = 0U;
1165     bool is_ep_result_critical = false;
1166
1167     if ((self != NULL) && (self->routes_list_ptr != NULL) && 
1168         (self->routes_list_size > 0U) && (node_ptr != NULL))
1169     {
1170         for (; k < self->routes_list_size; k++)
1171         {
1172             is_ep_result_critical = Rtm_CheckEpResultSeverity(self, &self->routes_list_ptr[k], self->routes_list_ptr[k].sink_endpoint_ptr);
1173             if ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_SUSPENDED) ||
1174                 ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_DETERIORATED) &&
1175                 (self->routes_list_ptr[k].internal_infos.last_route_result == UCS_RM_ROUTE_CRITICAL)) ||
1176                 ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_CONSTRUCTION) &&
1177                 (is_ep_result_critical)))
1178             {
1179                 if (((self->routes_list_ptr[k].source_endpoint_ptr != NULL) && 
1180                     (self->routes_list_ptr[k].source_endpoint_ptr->node_obj_ptr == node_ptr)) || 
1181                     ((self->routes_list_ptr[k].sink_endpoint_ptr != NULL) && 
1182                     (self->routes_list_ptr[k].sink_endpoint_ptr->node_obj_ptr == node_ptr)))
1183                 {
1184                     Rtm_ForcesRouteToIdle(self, &self->routes_list_ptr[k]);
1185                 }
1186             }
1187         }
1188     }
1189 }
1190
1191 /*! \brief  Sets the given routes to the "Idle" state and resets its internal variables.
1192  *  \details This function is risky and should only be used in Rtm_ReleaseSuspendedRoutes(). Because it forces a route's state to "Idle" 
1193  *  without any external events.
1194  *  \param  self        Instance pointer
1195  *  \param  route_ptr   Reference to the route to be set
1196  */
1197 static void Rtm_ForcesRouteToIdle(CRouteManagement * self,  Ucs_Rm_Route_t * route_ptr)
1198 {
1199     if ((self != NULL) && (route_ptr != NULL))
1200     {
1201         route_ptr->internal_infos.route_state = UCS_RM_ROUTE_IDLE;
1202         route_ptr->internal_infos.last_route_result = UCS_RM_ROUTE_NOERROR;
1203         if (route_ptr->source_endpoint_ptr != NULL)
1204         {
1205             if (Rtm_CheckEpResultSeverity(self, route_ptr, route_ptr->source_endpoint_ptr))
1206             {
1207                 Epm_ResetState(self->epm_ptr, route_ptr->source_endpoint_ptr);
1208             }
1209         }
1210         if (route_ptr->sink_endpoint_ptr != NULL)
1211         {
1212             if (Rtm_CheckEpResultSeverity(self, route_ptr, route_ptr->sink_endpoint_ptr))
1213             {
1214                 Epm_ResetState(self->epm_ptr, route_ptr->sink_endpoint_ptr);
1215             }
1216         }
1217     }
1218 }
1219
1220 /*------------------------------------------------------------------------------------------------*/
1221 /* Callback Functions                                                                             */
1222 /*------------------------------------------------------------------------------------------------*/
1223 /*! \brief  Called if UCS initialization has been succeeded.
1224  *  \param  self        Instance pointer
1225  *  \param  event_ptr   Reference to reported event
1226  */
1227 static void Rtm_UcsInitSucceededCb(void *self, void *event_ptr)
1228 {
1229     CRouteManagement *self_ = (CRouteManagement *)self;
1230     MISC_UNUSED(event_ptr);
1231
1232     /* Remove ucsinit_observer */
1233     Eh_DelObsrvInternalEvent(&self_->base_ptr->eh, &self_->ucsinit_observer);
1234
1235     /* Add network status observer */
1236     Mobs_Ctor(&self_->nwstatus_observer, self, RTM_MASK_NETWORK_AVAILABILITY, &Rtm_MnsNwStatusInfosCb);
1237     Net_AddObserverNetworkStatus(self_->net_ptr, &self_->nwstatus_observer);
1238 }
1239
1240 /*! \brief  Handle internal errors and un-initialize RTM service.
1241  *  \param  self            Instance pointer
1242  *  \param  error_code_ptr  Reference to internal error code
1243  */
1244 static void Rtm_UninitializeService(void *self, void *error_code_ptr)
1245 {
1246     CRouteManagement *self_ = (CRouteManagement *)self;
1247     MISC_UNUSED(error_code_ptr);
1248
1249     self_->ucs_is_stopping = true;
1250
1251     /* Notify destruction of current routes */
1252     Rtm_HandleProcessTermination(self_);
1253
1254     /* Remove RTM service from schedulers list */
1255     (void)Scd_RemoveService(&self_->base_ptr->scd, &self_->rtm_srv);
1256     /* Remove error/event observers */
1257     Eh_DelObsrvInternalEvent(&self_->base_ptr->eh, &self_->ucstermination_observer);
1258     Net_DelObserverNetworkStatus(self_->net_ptr, &self_->nwstatus_observer);
1259
1260     /*  Unlock API */
1261     Rtm_ApiLocking(self_, false);
1262 }
1263
1264 /*! \brief  Event Callback function for the network status.
1265  *  \param  self          Instance pointer
1266  *  \param  event_ptr     Reference to the events
1267  */
1268 static void Rtm_MnsNwStatusInfosCb(void *self, void *event_ptr)
1269 {
1270     CRouteManagement *self_ = (CRouteManagement *)self;
1271     Net_NetworkStatusParam_t *result_ptr_ = (Net_NetworkStatusParam_t *)event_ptr;
1272
1273     if (RTM_MASK_NETWORK_AVAILABILITY == (RTM_MASK_NETWORK_AVAILABILITY & result_ptr_->change_mask))
1274     {
1275         if (UCS_NW_NOT_AVAILABLE == result_ptr_->availability)
1276         {
1277             self_->nw_available = false;
1278             /* Resets Nodes availability flag */
1279             Rtm_ResetNodesAvailable(self_);
1280             /* Reports Network Status "NotAvailabe" */
1281             Epm_ReportShutDown(self_->epm_ptr);
1282         }
1283         else
1284         {
1285             self_->nw_available = true;
1286             /* Check whether there are routes to be processed */
1287             Rtm_StartRoutingTimer (self_);
1288         }
1289     }
1290 }
1291
1292 /*! \brief  Event Callback function that signals that an endpoint is unavailable.
1293  *  \param  self          Instance pointer
1294  *  \param  result_ptr    Reference to the results
1295  */
1296 static void Rtm_EndPointDeterioredCb(void *self, void *result_ptr)
1297 {
1298     Ucs_Rm_Route_t * route_ptr = (Ucs_Rm_Route_t *)self;
1299     Ucs_Rm_EndPoint_t * ep_ptr = (Ucs_Rm_EndPoint_t *)result_ptr;
1300
1301     if ((route_ptr->source_endpoint_ptr == ep_ptr) ||
1302         (route_ptr->sink_endpoint_ptr == ep_ptr))
1303     {
1304         if (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_BUILT)
1305         {
1306             TR_INFO((((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->base_ptr->ucs_user_ptr, "[RTM]", "Route id %X is deteriorated", 1U, route_ptr->route_id));
1307             if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE)
1308             {
1309                 route_ptr->internal_infos.src_obsvr_initialized = 0U;
1310             }
1311
1312             Rtm_HandleRoutingError((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst, route_ptr);
1313
1314             if ((((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->nw_available) &&
1315                 (!((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->ucs_is_stopping))
1316             {
1317                 Rtm_StartTmr4HandlingRoutes((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst);
1318             }
1319             else if (((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->ucs_is_stopping)
1320             {
1321                 Rtm_HandleProcessTermination((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst);
1322             }
1323         }
1324     }
1325     else
1326     {
1327         TR_ERROR((((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->base_ptr->ucs_user_ptr, "[RTM]", "Wrong endpoint {%X} of type %s on route id {%X}.", 3U,
1328             ep_ptr, (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", route_ptr->route_id));
1329     }
1330 }
1331
1332 /*! \brief  Processes the handling of all routes. This method is the callback function of the routing timer
1333  *          \c route_chek.
1334  *  \param  self    Instance pointer
1335  */
1336 static void Rtm_ExecRoutesHandling(void* self)
1337 {
1338     CRouteManagement *self_ = (CRouteManagement *)self;
1339     if (!self_->ucs_is_stopping)
1340     {
1341         bool index_set = Rtm_SetNextRouteIndex(self_);
1342         if (index_set)
1343         {
1344             Srv_SetEvent(&self_->rtm_srv, RTM_EVENT_HANDLE_NEXTROUTE);
1345         }
1346         else
1347         {
1348             Srv_SetEvent(&self_->rtm_srv, RTM_EVENT_PROCESS_PAUSE);
1349             TR_INFO((self_->base_ptr->ucs_user_ptr, "[RTM]", "Handling process of routes is paused", 0U));
1350         }
1351     }
1352     else
1353     {
1354         Rtm_HandleProcessTermination(self_);
1355     }
1356 }
1357
1358 /*!
1359  * @}
1360  * \endcond
1361  */
1362
1363 /*------------------------------------------------------------------------------------------------*/
1364 /* End of file                                                                                    */
1365 /*------------------------------------------------------------------------------------------------*/
1366