1 /*------------------------------------------------------------------------------------------------*/
2 /* UNICENS V2.1.0-3491 */
3 /* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG. */
5 /* This program is free software: you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation, either version 2 of the License, or */
8 /* (at your option) any later version. */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* You may also obtain this software under a propriety license from Microchip. */
19 /* Please contact Microchip for further information. */
20 /*------------------------------------------------------------------------------------------------*/
24 * \brief Implementation of the Node Discovery.
26 * \cond UCS_INTERNAL_DOC
27 * \addtogroup G_NODE_DIS
32 /*------------------------------------------------------------------------------------------------*/
34 /*------------------------------------------------------------------------------------------------*/
35 #include "ucs_inic_pb.h"
36 #include "ucs_nodedis.h"
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 */
47 #define ND_TIMEOUT_PERIODIC 5000U /*!< \brief 5s timeout */
48 #define ND_TIMEOUT_COMMAND 300U /*!< \brief supervise EXC commands */
50 #define ND_SIGNATURE_VERSION 1U /*!< \brief signature version used for Node Discovery */
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;
61 /*------------------------------------------------------------------------------------------------*/
62 /* Internal enumerators */
63 /*------------------------------------------------------------------------------------------------*/
64 /*! \brief Possible events of the Node Discovery state machine */
65 typedef enum Nd_Events_
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. */
85 /*! \brief States of the Node Discovery state machine */
86 typedef enum Nd_State_
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 */
98 /*------------------------------------------------------------------------------------------------*/
99 /* Internal prototypes */
100 /*------------------------------------------------------------------------------------------------*/
101 static void Nd_Service(void *self);
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);
111 static void Nd_Reset_Lists(void *self);
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);
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);
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." */
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 }
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 }
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 }
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 }
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 }
228 /*------------------------------------------------------------------------------------------------*/
230 /*------------------------------------------------------------------------------------------------*/
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
239 void Nd_Ctor(CNodeDiscovery *self, CInic *inic, CBase *base, CExc *exc, Nd_InitData_t *init_ptr)
241 MISC_MEM_SET((void *)self, 0, sizeof(*self));
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;
250 Fsm_Ctor(&self->fsm, self, &(nd_trans_tab[0][0]), ND_NUM_EVENTS, ND_E_NIL);
252 Nd_Reset_Lists(self);
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);
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);
263 /* Register NetOn and MPR events */
264 Obs_Ctor(&self->nd_nwstatus, self, &Nd_NetworkStatusCb);
265 Inic_AddObsrvNwStatus(self->inic, &self->nd_nwstatus);
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);
276 /*! \brief Service function of the Node Discovery service.
277 * \param self Reference to Node Discovery object
279 static void Nd_Service(void *self)
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? */
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));
298 /**************************************************************************************************/
300 /**************************************************************************************************/
301 /*! \brief Start the Node Discovery
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
307 Ucs_Return_t Nd_Start(CNodeDiscovery *self)
309 Ucs_Return_t ret_val = UCS_RET_SUCCESS;
312 if (self->running == false)
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));
321 ret_val = UCS_RET_ERR_API_LOCKED;
322 TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Start failed", 0U));
332 /*! \brief Stops the Node Discovery
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
338 Ucs_Return_t Nd_Stop(CNodeDiscovery *self)
340 Ucs_Return_t ret_val = UCS_RET_SUCCESS;
342 if (self->running == true) /* check if Node Discovery was started */
344 self->stop_request = true;
345 Fsm_SetEvent(&self->fsm, ND_E_CHECK);
346 Srv_SetEvent(&self->service, ND_EVENT_SERVICE);
348 TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Stop", 0U));
352 ret_val = UCS_RET_ERR_NOT_AVAILABLE;
353 TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Stop failed", 0U));
360 /*! \brief Sends the Init command to all nodes
362 * \param *self Reference to Node Discovery object
364 void Nd_InitAll(CNodeDiscovery *self)
368 result = Exc_DeviceInit_Start(self->exc, UCS_ADDR_BROADCAST_BLOCKING, NULL);
369 if (result == UCS_RET_SUCCESS)
371 TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_InitAll", 0U));
375 TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_InitAll failed", 0U));
383 /**************************************************************************************************/
385 /**************************************************************************************************/
386 /*! \brief Action on start event
388 * \param *self Reference to Node Discovery object
390 static void Nd_A_Start(void *self)
392 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
395 Nd_Reset_Lists(self_);
397 Nd_Send_Hello_Get(self_);
399 Nd_Start_Periodic_Timer(self_);
401 self_->stop_request = false;
402 self_->hello_mpr_request = false;
403 self_->hello_neton_request = false;
406 /*! \brief Action on stop event
408 * \param *self Reference to Node Discovery object
410 static void Nd_A_Stop(void *self)
412 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
413 Ucs_Signature_t *dummy = NULL;
415 if (self_->report_fptr != NULL)
417 self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_STOPPED, dummy);
419 self_->running = false;
422 /*! \brief Check conditions
424 * \param *self Reference to Node Discovery object
426 static void Nd_A_CheckConditions(void *self)
428 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
430 if (self_->stop_request == true)
432 Fsm_SetEvent(&self_->fsm, ND_E_STOP);
433 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
435 else if (self_->hello_mpr_request == true)
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;
443 else if (self_->hello_neton_request == true)
445 Nd_Send_Hello_Get(self_);
446 Nd_Start_Periodic_Timer(self_);
447 self_->hello_neton_request = false;
449 else if (Dl_GetSize(&(self_->new_list)) > 0U)
451 Fsm_SetEvent(&self_->fsm, ND_E_HELLO_STATUS);
452 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
456 Nd_Start_Periodic_Timer(self_);
462 /*! \brief Evaluate the signature of the next node
464 * \param *self Reference to Node Discovery object
466 static void Nd_A_Eval_Hello(void *self)
468 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
470 Ucs_Nd_CheckResult_t result;
471 bool service_flag = false;
472 Ucs_Signature_t temp_sig;
474 if (Dl_GetSize(&(self_->new_list)) > 0U)
476 node = Dl_PopHead(&(self_->new_list));
477 self_->current_sig = *((Ucs_Signature_t *)(node->data_ptr));
479 if (self_->eval_fptr != NULL)
481 temp_sig = self_->current_sig; /* provide only a copy to the application */
482 result = self_->eval_fptr(self_->cb_inst_ptr, &temp_sig);
486 case UCS_ND_CHK_UNKNOWN:
487 Fsm_SetEvent(&self_->fsm, ND_E_RES_UNKNOWN);
491 case UCS_ND_CHK_WELCOME:
492 Fsm_SetEvent(&self_->fsm, ND_E_RES_NODE_OK);
496 case UCS_ND_CHK_UNIQUE:
497 Fsm_SetEvent(&self_->fsm, ND_E_RES_CHECK_UNIQUE);
502 Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
509 if (service_flag == true)
511 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
516 /*! \brief Sends a Welcome message to the current node
518 * \param *self Reference to Node Discovery object
520 static void Nd_A_Welcome(void *self)
522 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
524 Nd_Send_Welcome_SR(self, &self_->current_sig);
528 /*! \brief Report the current node as unknown
530 * \param *self Reference to Node Discovery object
532 static void Nd_A_Unknown(void *self)
534 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
535 Ucs_Signature_t temp_sig;
537 if (self_->report_fptr != NULL)
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);
543 Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
544 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
547 /*! \brief Check if the current node has already got a Welcome message
549 * \param *self Reference to Node Discovery object
551 static void Nd_A_CheckUnique(void *self)
553 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
555 Nd_Send_Signature_Get(self, self_->current_sig.node_address);
560 /*! \brief Report a successful Welcome.Result
562 * \param *self Reference to Node Discovery object
564 static void Nd_A_WelcomeSuccess(void *self)
566 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
567 Ucs_Signature_t temp_sig;
569 if (self_->report_fptr != NULL)
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);
575 /* initiate a Hello.Get if the current node is the local INIC */
576 if (self_->current_sig.node_pos_addr == 0x0400U)
578 Nd_Send_Hello_Get(self_);
579 Nd_Start_Periodic_Timer(self_);
582 Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
583 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
587 /*! \brief Report an unsuccessful Welcome.Result
589 * \param *self Reference to Node Discovery object
591 static void Nd_A_WelcomeNoSuccess(void *self)
593 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
595 /* same reaction as for MPR event */
596 self_->hello_mpr_request = true;
598 Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
599 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
603 /*! \brief Reaction on a timeout for the Welcome messsage
605 * \param *self Reference to Node Discovery object
607 static void Nd_A_WelcomeTimeout(void *self)
609 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
611 /* same reaction as for MPR event */
612 self_->hello_mpr_request = true;
614 Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
615 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
619 /*! \brief The periodic timer elapsed
621 * \param *self Reference to Node Discovery object
623 static void Nd_A_Timeout_Hello(void *self)
625 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
627 Nd_Send_Hello_Get(self_);
628 Nd_Start_Periodic_Timer(self_);
632 /*! \brief Reaction on a NetOff event
634 * \param *self Reference to Node Discovery object
636 static void Nd_A_NetOff(void *self)
638 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
639 Ucs_Signature_t *dummy = NULL;
641 if (self_->report_fptr != NULL)
643 self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_NETOFF, dummy);
646 Nd_Reset_Lists(self_);
651 /*! \brief Reaction on a timeout of the Signature command
653 * \param *self Reference to Node Discovery object
655 static void Nd_A_Signature_Timeout(void *self)
657 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
659 Nd_Send_Welcome_SR(self, &self_->current_sig);
663 /*! \brief Reaction on a successful Signature answer
665 * \param *self Reference to Node Discovery object
667 static void Nd_A_Signature_Success(void *self)
669 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
670 Ucs_Signature_t temp_sig;
672 if (self_->report_fptr != NULL)
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);
680 /*! \brief An unecpected error occurred
682 * \param *self Reference to Node Discovery object
684 static void Nd_A_Error(void *self)
686 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
687 Ucs_Signature_t *dummy = NULL;
689 if (self_->report_fptr != NULL)
691 self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_ERROR, dummy);
693 self_->running = false;
697 /**************************************************************************************************/
698 /* Callback functions */
699 /**************************************************************************************************/
701 /*! Callback function for the Exc.Hello.Status message
703 * \param *self Reference to Node Discovery object
704 * \param *result_ptr Result of the Exc_Hello_Get() command
706 static void Nd_HelloStatusCb(void *self, void *result_ptr)
708 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
709 Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
712 if (result_ptr_->result.code == UCS_RES_SUCCESS)
714 /* read signature and store it in the new_list */
715 node = Dl_PopHead(&(self_->unused_list)); /* get an unused list element */
718 ((Nd_Node *)(node->data_ptr))->signature = (*(Exc_HelloStatus_t *)(result_ptr_->data_info)).signature;
719 Dl_InsertTail(&(self_->new_list), node);
721 Fsm_SetEvent(&self_->fsm, ND_E_HELLO_STATUS);
722 TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb UCS_RES_SUCCESS", 0U));
726 TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb No list entry av.", 0U));
731 Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
732 TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb ND_E_ERROR", 0U));
735 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
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
743 static void Nd_WelcomeResultCb(void *self, void *result_ptr)
745 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
746 Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
748 Tm_ClearTimer(&self_->base->tm, &self_->timer);
750 if (result_ptr_->result.code == UCS_RES_SUCCESS)
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)
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));
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));
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);
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)
782 TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb Error (info) 0x%x", 1U, result_ptr_->result.info_ptr[i]));
787 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
791 /*! \brief Callback function for Signature status and error messages
793 * \param *self Reference to Node Discovery object
794 * \param *result_ptr Pointer to the result of the Signature message
796 static void Nd_SignatureStatusCb(void *self, void *result_ptr)
798 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
799 Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
801 Tm_ClearTimer(&self_->base->tm, &self_->timer);
803 if (result_ptr_->result.code == UCS_RES_SUCCESS)
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));
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));
815 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
819 /*! \brief Callback function for Init error messages
821 * \param *self Reference to Node Discovery object
822 * \param *result_ptr Pointer to the result of the Init message
824 static void Nd_InitCb(void *self, void *result_ptr)
826 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
827 Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
830 MISC_UNUSED(result_ptr_);
835 /*! \brief Timer callback used for supervising INIC command timeouts.
836 * \param self Reference to Node Discovery object
838 static void Nd_TimerCb(void *self)
840 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
842 Fsm_SetEvent(&self_->fsm, ND_E_TIMEOUT);
843 TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_TimerCb ND_E_TIMEOUT", 0U));
845 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
849 /*! Function is called on severe internal errors
851 * \param *self Reference to Node Discovery object
852 * \param *result_ptr Reference to data
854 static void Nd_OnTerminateEventCb(void *self, void *result_ptr)
856 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
857 Ucs_Signature_t *dummy = NULL;
859 MISC_UNUSED(result_ptr);
861 if (self_->fsm.current_state != ND_S_IDLE)
863 Tm_ClearTimer(&self_->base->tm, &self_->timer);
864 if (self_->report_fptr != NULL)
866 self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_ERROR, dummy);
868 Nd_Reset_Lists(self_);
873 /*! \brief Callback function for the INIC.NetworkStatus status and error messages
875 * \param *self Reference to Node Discovery object
876 * \param *result_ptr Pointer to the result of the INIC.NetworkStatus message
878 static void Nd_NetworkStatusCb(void *self, void *result_ptr)
880 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
881 Inic_StdResult_t *result_ptr_ = (Inic_StdResult_t *)result_ptr;
883 if (result_ptr_->result.code == UCS_RES_SUCCESS)
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) )
890 self_->neton = false;
891 Fsm_SetEvent(&self_->fsm, ND_E_NET_OFF);
893 /* check for NetOn/NetOff events */
894 else if ( (self_->neton == false)
895 && ((((Inic_NetworkStatus_t *)(result_ptr_->data_info))->availability) == UCS_NW_AVAILABLE) )
898 self_->hello_neton_request = true;
899 Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
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)
905 self_->hello_mpr_request = true;
906 Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
910 Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
915 /**************************************************************************************************/
916 /* Helper functions */
917 /**************************************************************************************************/
918 /*! \brief Reset the list of new detected nodes
920 * \param *self Reference to Node Discovery object
922 static void Nd_Reset_Lists(void *self)
924 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
927 Dl_Ctor(&self_->new_list, self_->base->ucs_user_ptr);
928 Dl_Ctor(&self_->unused_list, self_->base->ucs_user_ptr);
930 for(i=0U; i < ND_NUM_NODES; ++i)
932 Dln_Ctor(&(self_->nodes[i]).node, &(self_->nodes[i]));
933 Dl_InsertTail(&(self_->unused_list), &(self_->nodes[i]).node);
938 /*! \brief Send the Hello.Get message
940 * \param *self Reference to Node Discovery object
942 static void Nd_Send_Hello_Get(void *self)
944 Ucs_Return_t ret_val;
945 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
947 ret_val = Exc_Hello_Get(self_->exc, UCS_ADDR_BROADCAST_BLOCKING,
948 ND_SIGNATURE_VERSION, &self_->nd_hello);
950 TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
951 MISC_UNUSED(ret_val);
955 /*! \brief Send the Welcome.StartResult message
957 * \param *self Reference to Node Discovery object
958 * \param *signature signature parameter
960 static void Nd_Send_Welcome_SR(void *self, Ucs_Signature_t *signature)
962 Ucs_Return_t ret_val;
963 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
964 uint16_t target_address;
966 if (signature->node_pos_addr == 0x0400U)
968 target_address = 0x0001U;
972 target_address = signature->node_pos_addr;
975 ret_val = Exc_Welcome_Sr(self_->exc,
978 ND_SIGNATURE_VERSION,
981 Tm_SetTimer(&self_->base->tm,
987 TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
988 MISC_UNUSED(ret_val);
992 /*! \brief Send the Signature.Get message
994 * \param *self Reference to Node Discovery object
995 * \param target_address target address for the command
997 static void Nd_Send_Signature_Get(void *self, uint16_t target_address)
999 Ucs_Return_t ret_val;
1000 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
1002 ret_val = Exc_Signature_Get(self_->exc, target_address, ND_SIGNATURE_VERSION, &self_->nd_signature);
1003 Tm_SetTimer(&self_->base->tm,
1009 TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
1010 MISC_UNUSED(ret_val);
1013 /*! \brief Starts the periodic timer
1015 * \param *self Reference to Node Discovery object
1017 static void Nd_Start_Periodic_Timer(void *self)
1019 CNodeDiscovery *self_ = (CNodeDiscovery *)self;
1021 Tm_SetTimer(&self_->base->tm,
1025 ND_TIMEOUT_PERIODIC,
1035 /*------------------------------------------------------------------------------------------------*/
1037 /*------------------------------------------------------------------------------------------------*/