b9f2f5aa1a4d1e2afac5e1bf3ed7412f7d201f76
[apps/agl-service-unicens.git] / ucs2-lib / src / ucs_nodedis.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 Node Discovery.
25  *
26  * \cond UCS_INTERNAL_DOC
27  * \addtogroup G_NODE_DIS
28  * @{
29
30  */
31
32 /*------------------------------------------------------------------------------------------------*/
33 /* Includes                                                                                       */
34 /*------------------------------------------------------------------------------------------------*/
35 #include "ucs_inic_pb.h"
36 #include "ucs_nodedis.h"
37 #include "ucs_misc.h"
38
39
40
41 /*------------------------------------------------------------------------------------------------*/
42 /* Internal constants                                                                             */
43 /*------------------------------------------------------------------------------------------------*/
44 #define ND_NUM_STATES             5U    /*!< \brief Number of state machine states */
45 #define ND_NUM_EVENTS            14U    /*!< \brief Number of state machine events */
46
47 #define ND_TIMEOUT_PERIODIC     5000U   /*!< \brief 5s timeout */
48 #define ND_TIMEOUT_COMMAND       300U   /*!< \brief supervise EXC commands */
49
50 #define ND_SIGNATURE_VERSION       1U   /*!< \brief signature version used for Node Discovery */
51
52 /*------------------------------------------------------------------------------------------------*/
53 /* Service parameters                                                                             */
54 /*------------------------------------------------------------------------------------------------*/
55 /*! Priority of the Node Discovery service used by scheduler */
56 static const uint8_t ND_SRV_PRIO = 248U;   /* parasoft-suppress  MISRA2004-8_7 "Value shall be part of the module, not part of a function." */
57 /*! Main event for the Node Discovery service */
58 static const Srv_Event_t ND_EVENT_SERVICE = 1U;
59
60
61 /*------------------------------------------------------------------------------------------------*/
62 /* Internal enumerators                                                                           */
63 /*------------------------------------------------------------------------------------------------*/
64 /*! \brief Possible events of the Node Discovery state machine */
65 typedef enum Nd_Events_
66 {
67     ND_E_NIL                = 0U,      /*!< \brief NIL Event */
68     ND_E_START              = 1U,      /*!< \brief API start command was called. */
69     ND_E_STOP               = 2U,      /*!< \brief Stop request occurred. */
70     ND_E_CHECK              = 3U,      /*!< \brief Check conditions in CHECK_HELLO state. */ 
71     ND_E_NET_OFF            = 4U,      /*!< \brief NetOff occurred. */
72     ND_E_HELLO_STATUS       = 5U,      /*!< \brief Hello.Status message available to be processed. */
73     ND_E_RES_NODE_OK        = 6U,      /*!< \brief Evaluation result of node: ok. */
74     ND_E_RES_UNKNOWN        = 7U,      /*!< \brief Evaluation result of node: unknown node. */
75     ND_E_RES_CHECK_UNIQUE   = 8U,      /*!< \brief Evaluation result of node: check if node is unique. */
76     ND_E_WELCOME_SUCCESS    = 9U,      /*!< \brief Welcome command was successful. */
77     ND_E_WELCOME_NOSUCCESS  = 10U,     /*!< \brief Welcome command was not successful. */
78     ND_E_SIGNATURE_SUCCESS  = 11U,     /*!< \brief Signature command was successful. */
79     ND_E_TIMEOUT            = 12U,     /*!< \brief Timeout occurred. */
80     ND_E_ERROR              = 13U      /*!< \brief An unexpected error occurred. */ 
81
82 } Nd_Events_t;
83
84
85 /*! \brief States of the Node Discovery state machine */
86 typedef enum Nd_State_
87 {
88     ND_S_IDLE            =  0U,     /*!< \brief Idle state */
89     ND_S_CHECK_HELLO     =  1U,     /*!< \brief Node Discovery started */
90     ND_S_WAIT_EVAL       =  2U,     /*!< \brief Evaluate next Hello.Status message */
91     ND_S_WAIT_WELCOME    =  3U,     /*!< \brief Wait for Welcome.Status */
92     ND_S_WAIT_PING       =  4U      /*!< \brief Wait for Signature.Status */
93 } Nd_State_t;
94
95
96
97
98 /*------------------------------------------------------------------------------------------------*/
99 /* Internal prototypes                                                                            */
100 /*------------------------------------------------------------------------------------------------*/
101 static void Nd_Service(void *self);
102
103 static void Nd_HelloStatusCb(void *self, void *result_ptr);
104 static void Nd_WelcomeResultCb(void *self, void *result_ptr);
105 static void Nd_SignatureStatusCb(void *self, void *result_ptr);
106 static void Nd_InitCb(void *self, void *result_ptr);
107 static void Nd_TimerCb(void *self);
108 static void Nd_OnTerminateEventCb(void *self, void *result_ptr);
109 static void Nd_NetworkStatusCb(void *self, void *result_ptr);
110
111 static void Nd_Reset_Lists(void *self);
112
113 static void Nd_A_Start(void *self);
114 static void Nd_A_Stop(void *self);
115 static void Nd_A_CheckConditions(void *self);
116 static void Nd_A_Eval_Hello(void *self);
117 static void Nd_A_Welcome(void *self);
118 static void Nd_A_Unknown(void *self);
119 static void Nd_A_CheckUnique(void *self);
120 static void Nd_A_WelcomeSuccess(void *self);
121 static void Nd_A_WelcomeNoSuccess(void *self);
122 static void Nd_A_WelcomeTimeout(void *self);
123 static void Nd_A_Timeout_Hello(void *self);
124 static void Nd_A_NetOff(void *self);
125 static void Nd_A_Signature_Timeout(void *self);
126 static void Nd_A_Signature_Success(void *self);
127 static void Nd_A_Error(void *self);
128
129 static void Nd_Send_Hello_Get(void *self);
130 static void Nd_Start_Periodic_Timer(void *self);
131 static void Nd_Send_Welcome_SR(void *self, Ucs_Signature_t *signature);
132 static void Nd_Send_Signature_Get(void *self, uint16_t target_address);
133
134
135 /*------------------------------------------------------------------------------------------------*/
136 /* State transition table (used by finite state machine)                                          */
137 /*------------------------------------------------------------------------------------------------*/
138 /*! \brief State transition table */
139 static const Fsm_StateElem_t nd_trans_tab[ND_NUM_STATES][ND_NUM_EVENTS] =    /* parasoft-suppress  MISRA2004-8_7 "Value shall be part of the module, not part of a function." */
140 {
141     { /* State ND_S_IDLE */
142         /* ND_E_NIL                */ {NULL,                          ND_S_IDLE            },
143         /* ND_E_START              */ {&Nd_A_Start,                   ND_S_CHECK_HELLO     },
144         /* ND_E_STOP               */ {NULL,                          ND_S_IDLE            },
145         /* ND_E_CHECK              */ {NULL,                          ND_S_IDLE            },
146         /* ND_E_NET_OFF            */ {NULL,                          ND_S_IDLE            },
147         /* ND_E_HELLO_STATUS       */ {NULL,                          ND_S_IDLE            },
148         /* ND_E_RES_NODE_OK        */ {NULL,                          ND_S_IDLE            },
149         /* ND_E_RES_UNKNOWN        */ {NULL,                          ND_S_IDLE            },
150         /* ND_E_RES_CHECK_UNIQUE   */ {NULL,                          ND_S_IDLE            },
151         /* ND_E_WELCOME_SUCCESS    */ {NULL,                          ND_S_IDLE            },
152         /* ND_E_WELCOME_NOSUCCESS  */ {NULL,                          ND_S_IDLE            },
153         /* ND_E_SIGNATURE_SUCCESS  */ {NULL,                          ND_S_IDLE            },
154         /* ND_E_TIMEOUT            */ {NULL,                          ND_S_IDLE            },
155         /* ND_E_ERROR              */ {NULL,                          ND_S_IDLE            }
156
157     },
158     { /* State ND_S_CHECK_HELLO */
159         /* ND_E_NIL                */ {NULL,                          ND_S_CHECK_HELLO     },
160         /* ND_E_START              */ {NULL,                          ND_S_CHECK_HELLO     },
161         /* ND_E_STOP               */ {&Nd_A_Stop,                    ND_S_IDLE            },
162         /* ND_E_CHECK              */ {&Nd_A_CheckConditions,         ND_S_CHECK_HELLO     },
163         /* ND_E_NET_OFF            */ {&Nd_A_NetOff,                  ND_S_CHECK_HELLO     },
164         /* ND_E_HELLO_STATUS       */ {&Nd_A_Eval_Hello,              ND_S_WAIT_EVAL       },
165         /* ND_E_RES_NODE_OK        */ {NULL,                          ND_S_CHECK_HELLO     },
166         /* ND_E_RES_UNKNOWN        */ {NULL,                          ND_S_CHECK_HELLO     },
167         /* ND_E_RES_CHECK_UNIQUE   */ {NULL,                          ND_S_CHECK_HELLO     },
168         /* ND_E_WELCOME_SUCCESS    */ {NULL,                          ND_S_CHECK_HELLO     },
169         /* ND_E_WELCOME_NOSUCCESS  */ {NULL,                          ND_S_CHECK_HELLO     },
170         /* ND_E_SIGNATURE_SUCCESS  */ {NULL,                          ND_S_CHECK_HELLO     },
171         /* ND_E_TIMEOUT            */ {&Nd_A_Timeout_Hello,           ND_S_CHECK_HELLO     },
172         /* ND_E_ERROR              */ {&Nd_A_Error,                   ND_S_IDLE            }
173     },
174     { /* State ND_S_WAIT_EVAL */
175         /* ND_E_NIL                */ {NULL,                          ND_S_WAIT_EVAL       },
176         /* ND_E_START              */ {NULL,                          ND_S_WAIT_EVAL       },
177         /* ND_E_STOP               */ {NULL,                          ND_S_WAIT_EVAL       },
178         /* ND_E_CHECK              */ {NULL,                          ND_S_WAIT_EVAL       },
179         /* ND_E_NET_OFF            */ {&Nd_A_NetOff,                  ND_S_CHECK_HELLO     },
180         /* ND_E_HELLO_STATUS       */ {NULL,                          ND_S_WAIT_EVAL       },
181         /* ND_E_RES_NODE_OK        */ {&Nd_A_Welcome,                 ND_S_WAIT_WELCOME    },
182         /* ND_E_RES_UNKNOWN        */ {&Nd_A_Unknown,                 ND_S_CHECK_HELLO     },
183         /* ND_E_RES_CHECK_UNIQUE   */ {&Nd_A_CheckUnique,             ND_S_WAIT_PING       },
184         /* ND_E_WELCOME_SUCCESS    */ {NULL,                          ND_S_WAIT_EVAL       },
185         /* ND_E_WELCOME_NOSUCCESS  */ {NULL,                          ND_S_WAIT_EVAL       },
186         /* ND_E_SIGNATURE_SUCCESS  */ {NULL,                          ND_S_WAIT_EVAL       },
187         /* ND_E_TIMEOUT            */ {NULL,                          ND_S_WAIT_EVAL       },
188         /* ND_E_ERROR              */ {&Nd_A_Error,                   ND_S_IDLE            }
189     },                             
190
191     {/* ND_S_WAIT_WELCOME */       
192         /* ND_E_NIL                */ {NULL,                          ND_S_WAIT_WELCOME    },
193         /* ND_E_START              */ {NULL,                          ND_S_WAIT_WELCOME    },
194         /* ND_E_STOP               */ {NULL,                          ND_S_WAIT_WELCOME    },
195         /* ND_E_CHECK              */ {NULL,                          ND_S_WAIT_WELCOME    },
196         /* ND_E_NET_OFF            */ {&Nd_A_NetOff,                  ND_S_CHECK_HELLO     },
197         /* ND_E_HELLO_STATUS       */ {NULL,                          ND_S_WAIT_WELCOME    },
198         /* ND_E_RES_NODE_OK        */ {NULL,                          ND_S_WAIT_WELCOME    },
199         /* ND_E_RES_UNKNOWN        */ {NULL,                          ND_S_WAIT_WELCOME    },
200         /* ND_E_RES_CHECK_UNIQUE   */ {NULL,                          ND_S_WAIT_WELCOME    },
201         /* ND_E_WELCOME_SUCCESS    */ {&Nd_A_WelcomeSuccess,          ND_S_CHECK_HELLO     },
202         /* ND_E_WELCOME_NOSUCCESS  */ {&Nd_A_WelcomeNoSuccess,        ND_S_CHECK_HELLO     },
203         /* ND_E_SIGNATURE_SUCCESS  */ {NULL,                          ND_S_WAIT_WELCOME    },
204         /* ND_E_TIMEOUT            */ {&Nd_A_WelcomeTimeout,          ND_S_CHECK_HELLO    },
205         /* ND_E_ERROR              */ {&Nd_A_Error,                   ND_S_IDLE            }
206     },                             
207     {/* ND_S_WAIT_PING */          
208         /* ND_E_NIL                */ {NULL,                          ND_S_WAIT_PING       },
209         /* ND_E_START              */ {NULL,                          ND_S_WAIT_PING       },
210         /* ND_E_STOP               */ {NULL,                          ND_S_WAIT_PING       },
211         /* ND_E_CHECK              */ {NULL,                          ND_S_WAIT_PING       },
212         /* ND_E_NET_OFF            */ {&Nd_A_NetOff,                  ND_S_CHECK_HELLO     },
213         /* ND_E_HELLO_STATUS       */ {NULL,                          ND_S_WAIT_PING       },
214         /* ND_E_RES_NODE_OK        */ {NULL,                          ND_S_WAIT_PING       },
215         /* ND_E_RES_UNKNOWN        */ {NULL,                          ND_S_WAIT_PING       },
216         /* ND_E_RES_CHECK_UNIQUE   */ {NULL,                          ND_S_WAIT_PING       },
217         /* ND_E_WELCOME_SUCCESS    */ {NULL,                          ND_S_WAIT_PING       },
218         /* ND_E_WELCOME_NOSUCCESS  */ {NULL,                          ND_S_WAIT_PING       },
219         /* ND_E_SIGNATURE_SUCCESS  */ {&Nd_A_Signature_Success,       ND_S_CHECK_HELLO     },
220         /* ND_E_TIMEOUT            */ {&Nd_A_Signature_Timeout,       ND_S_WAIT_WELCOME    },
221         /* ND_E_ERROR              */ {&Nd_A_Error,                   ND_S_IDLE            }
222     }
223 };
224
225
226
227
228 /*------------------------------------------------------------------------------------------------*/
229 /* Implementation                                                                                 */
230 /*------------------------------------------------------------------------------------------------*/
231
232 /*! \brief Constructor of class CNodeDiscovery.
233  *  \param self         Reference to CNodeDiscovery instance
234  *  \param inic         Reference to CInic instance
235  *  \param base         Reference to CBase instance
236  *  \param exc          Reference to CExc instance
237  *  \param init_ptr    Report callback function
238  */
239 void Nd_Ctor(CNodeDiscovery *self, CInic *inic, CBase *base, CExc *exc, Nd_InitData_t *init_ptr)
240 {
241     MISC_MEM_SET((void *)self, 0, sizeof(*self));
242
243     self->inic       = inic;
244     self->exc        = exc;
245     self->base       = base;
246     self->cb_inst_ptr = init_ptr->inst_ptr;
247     self->report_fptr = init_ptr->report_fptr;
248     self->eval_fptr   = init_ptr->eval_fptr;
249
250     Fsm_Ctor(&self->fsm, self, &(nd_trans_tab[0][0]), ND_NUM_EVENTS, ND_E_NIL);
251
252     Nd_Reset_Lists(self);
253
254     Sobs_Ctor(&self->nd_hello,          self, &Nd_HelloStatusCb);
255     Sobs_Ctor(&self->nd_welcome,        self, &Nd_WelcomeResultCb);
256     Sobs_Ctor(&self->nd_signature,      self, &Nd_SignatureStatusCb);
257     Sobs_Ctor(&self->nd_init,           self, &Nd_InitCb);
258
259     /* register termination events */
260     Mobs_Ctor(&self->nd_terminate, self, EH_M_TERMINATION_EVENTS, &Nd_OnTerminateEventCb);
261     Eh_AddObsrvInternalEvent(&self->base->eh, &self->nd_terminate);
262
263     /* Register NetOn and MPR events */
264     Obs_Ctor(&self->nd_nwstatus, self, &Nd_NetworkStatusCb);
265     Inic_AddObsrvNwStatus(self->inic,  &self->nd_nwstatus);
266     self->neton = false;
267
268     /* Initialize Node Discovery service */
269     Srv_Ctor(&self->service, ND_SRV_PRIO, self, &Nd_Service);
270     /* Add Node Discovery service to scheduler */
271     (void)Scd_AddService(&self->base->scd, &self->service);
272
273 }
274
275
276 /*! \brief Service function of the Node Discovery service.
277  *  \param self    Reference to Node Discovery object
278  */
279 static void Nd_Service(void *self)
280 {
281     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
282     Srv_Event_t event_mask;
283     Srv_GetEvent(&self_->service, &event_mask);
284     if(ND_EVENT_SERVICE == (event_mask & ND_EVENT_SERVICE))   /* Is event pending? */
285     {
286         Fsm_State_t result;
287         Srv_ClearEvent(&self_->service, ND_EVENT_SERVICE);
288         TR_INFO((self_->base->ucs_user_ptr, "[ND]", "FSM __ %d %d", 2U, self_->fsm.current_state, self_->fsm.event_occured));
289         result = Fsm_Service(&self_->fsm);
290         TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", (result != FSM_STATE_ERROR));
291         TR_INFO((self_->base->ucs_user_ptr, "[ND]", "FSM -> %d", 1U, self_->fsm.current_state));
292         MISC_UNUSED(result);
293     }
294 }
295
296
297
298 /**************************************************************************************************/
299 /* API functions                                                                                  */
300 /**************************************************************************************************/
301 /*! \brief Start the Node Discovery
302  *
303  * \param  *self    Reference to Node Discovery object
304  * \return UCS_RET_SUCCESS              Operation successful
305  * \return UCS_RET_ERR_API_LOCKED       Node Discovery was already started
306  */
307 Ucs_Return_t Nd_Start(CNodeDiscovery *self)
308 {
309     Ucs_Return_t ret_val = UCS_RET_SUCCESS;
310
311
312     if (self->running == false)
313     {
314         Fsm_SetEvent(&self->fsm, ND_E_START);
315         Srv_SetEvent(&self->service, ND_EVENT_SERVICE);
316         self->running = true;
317         TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Start", 0U));
318     }
319     else
320     {
321         ret_val = UCS_RET_ERR_API_LOCKED;
322         TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Start failed", 0U));
323     }
324
325     return ret_val;
326
327
328
329
330 }
331
332 /*! \brief Stops the Node Discovery
333  *
334  * \param *self Reference to Node Discovery object
335  * \return UCS_RET_SUCCESS              Operation successful
336  * \return UCS_RET_ERR_NOT_AVAILABLE    Node Discovery not running
337  */
338 Ucs_Return_t Nd_Stop(CNodeDiscovery *self)
339 {
340     Ucs_Return_t ret_val = UCS_RET_SUCCESS;
341
342     if (self->running == true)       /* check if Node Discovery was started */
343     {
344         self->stop_request = true;
345         Fsm_SetEvent(&self->fsm, ND_E_CHECK);
346         Srv_SetEvent(&self->service, ND_EVENT_SERVICE);
347
348         TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Stop", 0U));
349     }
350     else
351     {
352         ret_val = UCS_RET_ERR_NOT_AVAILABLE;
353         TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Stop failed", 0U));
354     }
355
356     return ret_val;
357 }
358
359
360 /*! \brief Sends the Init command to all nodes 
361  *
362  * \param *self Reference to Node Discovery object
363  */
364 void Nd_InitAll(CNodeDiscovery *self)
365 {
366     Ucs_Return_t result;
367
368     result = Exc_DeviceInit_Start(self->exc, UCS_ADDR_BROADCAST_BLOCKING, NULL);
369     if (result == UCS_RET_SUCCESS)
370     {
371         TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_InitAll", 0U));
372     }
373     else
374     {
375         TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_InitAll failed", 0U));
376     }
377
378 }
379
380
381
382
383 /**************************************************************************************************/
384 /*  FSM Actions                                                                                   */
385 /**************************************************************************************************/
386 /*! \brief Action on start event
387  *
388  * \param *self Reference to Node Discovery object
389  */
390 static void Nd_A_Start(void *self)
391 {
392     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
393
394     /* empty new_list*/
395     Nd_Reset_Lists(self_);
396
397     Nd_Send_Hello_Get(self_);
398
399     Nd_Start_Periodic_Timer(self_);
400
401     self_->stop_request  = false;
402     self_->hello_mpr_request   = false;
403     self_->hello_neton_request = false;
404 }
405
406 /*! \brief Action on stop event
407  *
408  * \param *self Reference to Node Discovery object
409  */
410 static void Nd_A_Stop(void *self)
411 {
412     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
413     Ucs_Signature_t *dummy = NULL;
414
415     if (self_->report_fptr != NULL)
416     {
417         self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_STOPPED, dummy);
418     }
419     self_->running = false;
420 }
421
422 /*! \brief Check conditions 
423  *
424  * \param *self Reference to Node Discovery object
425  */
426 static void Nd_A_CheckConditions(void *self)
427 {
428     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
429
430     if (self_->stop_request == true)
431     {
432         Fsm_SetEvent(&self_->fsm, ND_E_STOP);
433         Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
434     }
435     else if (self_->hello_mpr_request == true)
436     {
437         Nd_Reset_Lists(self_);
438         Nd_Send_Hello_Get(self_);
439         Nd_Start_Periodic_Timer(self_);
440         self_->hello_mpr_request   = false;
441         self_->hello_neton_request = false;
442     }
443     else if (self_->hello_neton_request == true)
444     {
445         Nd_Send_Hello_Get(self_);
446         Nd_Start_Periodic_Timer(self_);
447         self_->hello_neton_request = false;
448     }
449     else if (Dl_GetSize(&(self_->new_list)) > 0U)
450     {
451         Fsm_SetEvent(&self_->fsm, ND_E_HELLO_STATUS);
452         Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
453     }
454     else
455     {
456         Nd_Start_Periodic_Timer(self_);
457     }
458
459 }
460
461
462 /*! \brief Evaluate the signature of the next node
463  *
464  * \param *self Reference to Node Discovery object
465  */
466 static void Nd_A_Eval_Hello(void *self)
467 {
468     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
469     CDlNode *node;
470     Ucs_Nd_CheckResult_t result;
471     bool service_flag = false;
472     Ucs_Signature_t temp_sig;
473
474     if (Dl_GetSize(&(self_->new_list)) > 0U)
475     {
476         node = Dl_PopHead(&(self_->new_list));
477         self_->current_sig = *((Ucs_Signature_t *)(node->data_ptr));
478
479         if (self_->eval_fptr != NULL)
480         {
481             temp_sig = self_->current_sig;             /* provide only a copy to the application */
482             result = self_->eval_fptr(self_->cb_inst_ptr, &temp_sig);
483
484             switch (result)
485             {
486             case UCS_ND_CHK_UNKNOWN:
487                 Fsm_SetEvent(&self_->fsm, ND_E_RES_UNKNOWN);
488                 service_flag = true;
489                 break;
490
491             case UCS_ND_CHK_WELCOME:
492                 Fsm_SetEvent(&self_->fsm, ND_E_RES_NODE_OK);
493                 service_flag = true;
494                 break;
495
496             case UCS_ND_CHK_UNIQUE:
497                 Fsm_SetEvent(&self_->fsm, ND_E_RES_CHECK_UNIQUE);
498                 service_flag = true;
499                 break;
500
501             default: 
502                 Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
503                 service_flag = true;
504                 break;
505             }
506         }
507     }
508
509     if (service_flag == true)
510     {
511         Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
512     }
513 }
514
515
516 /*! \brief Sends a Welcome message to the current node
517  *
518  * \param *self Reference to Node Discovery object
519  */
520 static void Nd_A_Welcome(void *self)
521 {
522     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
523
524     Nd_Send_Welcome_SR(self, &self_->current_sig);
525 }
526
527
528 /*! \brief Report the current node as unknown
529  *
530  * \param *self Reference to Node Discovery object
531  */
532 static void Nd_A_Unknown(void *self)
533 {
534     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
535     Ucs_Signature_t temp_sig;
536
537     if (self_->report_fptr != NULL)
538     {
539         temp_sig = self_->current_sig;                 /* provide only a copy to the application */
540         self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_UNKNOWN, &temp_sig);
541     }
542
543     Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
544     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
545 }
546
547 /*! \brief Check if the current node has already got a Welcome message
548  *
549  * \param *self Reference to Node Discovery object
550  */
551 static void Nd_A_CheckUnique(void *self)
552 {
553     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
554
555     Nd_Send_Signature_Get(self, self_->current_sig.node_address);
556
557 }
558
559
560 /*! \brief Report a successful Welcome.Result
561  *
562  * \param *self Reference to Node Discovery object
563  */
564 static void Nd_A_WelcomeSuccess(void *self)
565 {
566     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
567     Ucs_Signature_t temp_sig;
568
569     if (self_->report_fptr != NULL)
570     {
571         temp_sig = self_->current_sig;                 /* provide only a copy to the application */
572         self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_WELCOME_SUCCESS, &temp_sig);
573     }
574
575     /* initiate a Hello.Get if the current node is the local INIC */
576     if (self_->current_sig.node_pos_addr == 0x0400U)
577     {
578         Nd_Send_Hello_Get(self_);
579         Nd_Start_Periodic_Timer(self_);
580     }
581
582     Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
583     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
584 }
585
586
587 /*! \brief Report an unsuccessful Welcome.Result
588  *
589  * \param *self Reference to Node Discovery object
590  */
591 static void Nd_A_WelcomeNoSuccess(void *self)
592 {
593     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
594
595     /* same reaction as for MPR event */
596     self_->hello_mpr_request = true;
597
598     Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
599     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
600 }
601
602
603 /*! \brief Reaction on a timeout for the Welcome messsage
604  *
605  * \param *self Reference to Node Discovery object
606  */
607 static void Nd_A_WelcomeTimeout(void *self)
608 {
609     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
610
611     /* same reaction as for MPR event */
612     self_->hello_mpr_request = true;
613
614     Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
615     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
616 }
617
618
619 /*! \brief The periodic timer elapsed
620  *
621  * \param *self Reference to Node Discovery object
622  */
623 static void Nd_A_Timeout_Hello(void *self)
624 {
625     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
626
627     Nd_Send_Hello_Get(self_);
628     Nd_Start_Periodic_Timer(self_);
629 }
630
631
632 /*! \brief  Reaction on a NetOff event
633  *
634  * \param *self Reference to Node Discovery object
635  */
636 static void Nd_A_NetOff(void *self)
637 {
638     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
639     Ucs_Signature_t *dummy = NULL;
640
641     if (self_->report_fptr != NULL)
642     {
643         self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_NETOFF, dummy);
644     }
645
646     Nd_Reset_Lists(self_);
647
648 }
649
650
651 /*! \brief Reaction on a timeout of the Signature command
652  *
653  * \param *self Reference to Node Discovery object
654  */
655 static void Nd_A_Signature_Timeout(void *self)
656 {
657     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
658
659     Nd_Send_Welcome_SR(self, &self_->current_sig);
660 }
661
662
663 /*! \brief Reaction on a successful Signature answer
664  *
665  * \param *self Reference to Node Discovery object
666  */
667 static void Nd_A_Signature_Success(void *self)
668 {
669     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
670     Ucs_Signature_t temp_sig;
671
672     if (self_->report_fptr != NULL)
673     {
674         temp_sig = self_->current_sig;                 /* provide only a copy to the application */
675         self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_MULTI, &temp_sig);
676     }
677 }
678
679
680 /*! \brief An unecpected error occurred
681  *
682  * \param *self Reference to Node Discovery object
683  */
684 static void Nd_A_Error(void *self)
685 {
686     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
687     Ucs_Signature_t *dummy = NULL;
688
689     if (self_->report_fptr != NULL)
690     {
691         self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_ERROR, dummy);
692     }
693     self_->running = false;
694 }
695
696
697 /**************************************************************************************************/
698 /*  Callback functions                                                                            */
699 /**************************************************************************************************/
700
701 /*! Callback function for the Exc.Hello.Status message
702  *
703  * \param *self         Reference to Node Discovery object
704  * \param *result_ptr   Result of the Exc_Hello_Get() command
705  */
706 static void Nd_HelloStatusCb(void *self, void *result_ptr)
707 {
708     CNodeDiscovery *self_        = (CNodeDiscovery *)self;
709     Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
710     CDlNode *node;
711
712     if (result_ptr_->result.code == UCS_RES_SUCCESS)
713     {
714         /* read signature and store it in the new_list */
715         node = Dl_PopHead(&(self_->unused_list)); /* get an unused list element */
716         if (node != NULL)
717         {
718             ((Nd_Node *)(node->data_ptr))->signature = (*(Exc_HelloStatus_t *)(result_ptr_->data_info)).signature;
719             Dl_InsertTail(&(self_->new_list), node);
720
721             Fsm_SetEvent(&self_->fsm, ND_E_HELLO_STATUS);
722             TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb UCS_RES_SUCCESS", 0U));
723         }
724         else
725         {
726             TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb No list entry av.", 0U));
727         }
728     }
729     else
730     {
731         Fsm_SetEvent(&self_->fsm, ND_E_ERROR); 
732         TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb ND_E_ERROR", 0U));
733     }
734
735     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
736 }
737
738
739 /*! \brief  Function is called on reception of the Welcome.Result messsage
740  *  \param  self        Reference to Node Discovery object
741  *  \param  result_ptr  Pointer to the result of the Welcome message
742  */
743 static void Nd_WelcomeResultCb(void *self, void *result_ptr)
744 {
745     CNodeDiscovery *self_        = (CNodeDiscovery *)self;
746     Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
747
748     Tm_ClearTimer(&self_->base->tm, &self_->timer);
749
750     if (result_ptr_->result.code == UCS_RES_SUCCESS)
751     {
752         /* read signature and store it */
753         self_->welcome_result = *(Exc_WelcomeResult_t *)(result_ptr_->data_info);
754         if (self_->welcome_result.res == EXC_WELCOME_SUCCESS)
755         {
756             Fsm_SetEvent(&self_->fsm, ND_E_WELCOME_SUCCESS);
757             TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb ND_E_WELCOME_SUCCESS", 0U));
758         }
759         else
760         {
761             Fsm_SetEvent(&self_->fsm, ND_E_WELCOME_NOSUCCESS);
762             TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb ND_E_WELCOME_NOSUCCESS", 0U));
763         }
764     }
765     else
766     {
767         uint8_t i;
768
769         if (    (result_ptr_->result.info_size   == 3U)
770              && (result_ptr_->result.info_ptr[0] == 0x20U)
771              && (result_ptr_->result.info_ptr[1] == 0x03U)
772              && (result_ptr_->result.info_ptr[2] == 0x31U))
773         {   /* Device has not yet received an ExtendedNetworkControl.Hello.Get() message. */
774             Fsm_SetEvent(&self_->fsm, ND_E_WELCOME_NOSUCCESS);
775         }
776         else
777         {
778             Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
779             TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb Error (code) 0x%x", 1U, result_ptr_->result.code));
780             for (i=0U; i< result_ptr_->result.info_size; ++i)
781             {
782                 TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb Error (info) 0x%x", 1U, result_ptr_->result.info_ptr[i]));
783             }
784         }
785     }
786
787     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
788 }
789
790
791 /*! \brief Callback function for Signature status and error messages
792  *
793  * \param *self         Reference to Node Discovery object
794  * \param *result_ptr   Pointer to the result of the Signature message
795  */
796 static void Nd_SignatureStatusCb(void *self, void *result_ptr)
797 {
798     CNodeDiscovery *self_        = (CNodeDiscovery *)self;
799     Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
800
801     Tm_ClearTimer(&self_->base->tm, &self_->timer);
802
803     if (result_ptr_->result.code == UCS_RES_SUCCESS)
804     {
805         self_->signature_status = *(Exc_SignatureStatus_t *)(result_ptr_->data_info);
806         Fsm_SetEvent(&self_->fsm, ND_E_SIGNATURE_SUCCESS);
807         TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_SignatureStatusCb ND_E_SIGNATURE_SUCCESS", 0U));
808     }
809     else
810     {
811         Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
812         TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_SignatureStatusCb Error  0x%x", 1U, result_ptr_->result.code));
813     }
814
815     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
816 }
817
818
819 /*! \brief Callback function for Init error messages
820  *
821  * \param *self         Reference to Node Discovery object
822  * \param *result_ptr   Pointer to the result of the Init message
823  */
824 static void Nd_InitCb(void *self, void *result_ptr)
825 {
826     CNodeDiscovery *self_        = (CNodeDiscovery *)self;
827     Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
828
829     MISC_UNUSED(self_);
830     MISC_UNUSED(result_ptr_);
831
832 }
833
834
835 /*! \brief Timer callback used for supervising INIC command timeouts.
836  *  \param self    Reference to Node Discovery object
837  */
838 static void Nd_TimerCb(void *self)
839 {
840     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
841
842     Fsm_SetEvent(&self_->fsm, ND_E_TIMEOUT);
843     TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_TimerCb ND_E_TIMEOUT", 0U));
844
845     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
846 }
847
848
849 /*!  Function is called on severe internal errors
850  *
851  * \param *self         Reference to Node Discovery object
852  * \param *result_ptr   Reference to data
853  */
854 static void Nd_OnTerminateEventCb(void *self, void *result_ptr)
855 {
856     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
857     Ucs_Signature_t *dummy = NULL;
858
859     MISC_UNUSED(result_ptr);
860
861     if (self_->fsm.current_state != ND_S_IDLE)
862     {
863         Tm_ClearTimer(&self_->base->tm, &self_->timer);
864         if (self_->report_fptr != NULL)
865         {
866             self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_ERROR, dummy);
867         }
868         Nd_Reset_Lists(self_);
869     }
870 }
871
872
873 /*! \brief Callback function for the INIC.NetworkStatus status and error messages
874  *
875  * \param *self         Reference to Node Discovery object
876  * \param *result_ptr   Pointer to the result of the INIC.NetworkStatus message
877  */
878 static void Nd_NetworkStatusCb(void *self, void *result_ptr)
879 {
880     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
881     Inic_StdResult_t *result_ptr_ = (Inic_StdResult_t *)result_ptr;
882
883     if (result_ptr_->result.code == UCS_RES_SUCCESS)
884     {
885         TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_NetworkStatusCb  0x%x", 1U, result_ptr_->result.code));
886         /* check for NetOn/NetOff events */
887         if (    (self_->neton == true)
888              && ((((Inic_NetworkStatus_t *)(result_ptr_->data_info))->availability) == UCS_NW_NOT_AVAILABLE) )
889         {
890             self_->neton = false;
891             Fsm_SetEvent(&self_->fsm, ND_E_NET_OFF);
892         }
893         /* check for NetOn/NetOff events */
894         else if (    (self_->neton == false)
895              && ((((Inic_NetworkStatus_t *)(result_ptr_->data_info))->availability) == UCS_NW_AVAILABLE) )
896         {
897             self_->neton = true;
898             self_->hello_neton_request = true;
899             Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
900         }
901         /* check for MPR event */
902         else if (   (((Inic_NetworkStatus_t *)(result_ptr_->data_info))->events & UCS_NETWORK_EVENT_NCE)
903             == UCS_NETWORK_EVENT_NCE)
904         {
905             self_->hello_mpr_request = true;
906             Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
907         }
908     }
909
910     Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
911 }
912
913
914
915 /**************************************************************************************************/
916 /*  Helper functions                                                                              */
917 /**************************************************************************************************/
918 /*! \brief Reset the list of new detected nodes
919  *
920  * \param *self Reference to Node Discovery object
921  */
922 static void Nd_Reset_Lists(void *self)
923 {
924     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
925     uint16_t i;
926
927     Dl_Ctor(&self_->new_list, self_->base->ucs_user_ptr);
928     Dl_Ctor(&self_->unused_list, self_->base->ucs_user_ptr);
929
930     for(i=0U; i < ND_NUM_NODES; ++i)
931     {
932         Dln_Ctor(&(self_->nodes[i]).node, &(self_->nodes[i]));
933         Dl_InsertTail(&(self_->unused_list), &(self_->nodes[i]).node);
934     }
935 }
936
937
938 /*! \brief Send the Hello.Get message
939  *
940  * \param *self Reference to Node Discovery object
941  */
942 static void Nd_Send_Hello_Get(void *self)
943 {
944     Ucs_Return_t ret_val;
945     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
946
947     ret_val = Exc_Hello_Get(self_->exc, UCS_ADDR_BROADCAST_BLOCKING, 
948                             ND_SIGNATURE_VERSION, &self_->nd_hello);
949
950     TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
951     MISC_UNUSED(ret_val);
952 }
953
954
955 /*! \brief Send the Welcome.StartResult message
956  *
957  * \param *self Reference to Node Discovery object
958  * \param *signature signature parameter
959  */
960 static void Nd_Send_Welcome_SR(void *self, Ucs_Signature_t *signature)
961 {
962     Ucs_Return_t    ret_val;
963     CNodeDiscovery  *self_ = (CNodeDiscovery *)self;
964     uint16_t        target_address;
965
966     if (signature->node_pos_addr == 0x0400U)
967     {
968         target_address = 0x0001U;
969     }
970     else
971     {
972         target_address = signature->node_pos_addr;
973     }
974
975     ret_val = Exc_Welcome_Sr(self_->exc,
976                              target_address,
977                              0xFFFFU,
978                              ND_SIGNATURE_VERSION,
979                              *signature,
980                              &self_->nd_welcome);
981     Tm_SetTimer(&self_->base->tm,
982                 &self_->timer,
983                 &Nd_TimerCb,
984                 self_,
985                 ND_TIMEOUT_COMMAND,
986                 0U);
987     TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
988     MISC_UNUSED(ret_val);
989 }
990
991
992 /*! \brief Send the Signature.Get message
993  *
994  * \param *self          Reference to Node Discovery object
995  * \param target_address target address for the command
996  */
997 static void Nd_Send_Signature_Get(void *self, uint16_t target_address)
998 {
999     Ucs_Return_t   ret_val;
1000     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
1001
1002     ret_val = Exc_Signature_Get(self_->exc, target_address, ND_SIGNATURE_VERSION, &self_->nd_signature);
1003     Tm_SetTimer(&self_->base->tm,
1004                 &self_->timer,
1005                 &Nd_TimerCb,
1006                 self_,
1007                 ND_TIMEOUT_COMMAND,
1008                 0U);
1009     TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
1010     MISC_UNUSED(ret_val);
1011 }
1012
1013 /*! \brief  Starts the periodic timer
1014  *
1015  * \param *self Reference to Node Discovery object
1016  */
1017 static void Nd_Start_Periodic_Timer(void *self)
1018 {
1019     CNodeDiscovery *self_ = (CNodeDiscovery *)self;
1020
1021     Tm_SetTimer(&self_->base->tm,
1022                 &self_->timer,
1023                 &Nd_TimerCb,
1024                 self,
1025                 ND_TIMEOUT_PERIODIC,
1026                 0U);
1027 }
1028
1029 /*!
1030  * @}
1031  * \endcond
1032  */
1033
1034
1035 /*------------------------------------------------------------------------------------------------*/
1036 /* End of file                                                                                    */
1037 /*------------------------------------------------------------------------------------------------*/
1038