summaryrefslogtreecommitdiffstats
path: root/ucs2-lib/src/ucs_nodedis.c
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2017-05-26 18:45:56 +0200
committerFulup Ar Foll <fulup@iot.bzh>2017-05-26 18:45:56 +0200
commitd2e42029ec04c3f224580f8007cdfbbfe0fc47a6 (patch)
treead2ccf167cf7997c84191d41e6ba55cb2efd6bed /ucs2-lib/src/ucs_nodedis.c
parent18e393e1443fd4c38b34979888fb55d30448cf31 (diff)
Initial Commit
Diffstat (limited to 'ucs2-lib/src/ucs_nodedis.c')
-rw-r--r--ucs2-lib/src/ucs_nodedis.c1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/ucs2-lib/src/ucs_nodedis.c b/ucs2-lib/src/ucs_nodedis.c
new file mode 100644
index 0000000..b9f2f5a
--- /dev/null
+++ b/ucs2-lib/src/ucs_nodedis.c
@@ -0,0 +1,1038 @@
+/*------------------------------------------------------------------------------------------------*/
+/* UNICENS V2.1.0-3491 */
+/* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG. */
+/* */
+/* This program is free software: you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation, either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/* */
+/* You may also obtain this software under a propriety license from Microchip. */
+/* Please contact Microchip for further information. */
+/*------------------------------------------------------------------------------------------------*/
+
+/*!
+ * \file
+ * \brief Implementation of the Node Discovery.
+ *
+ * \cond UCS_INTERNAL_DOC
+ * \addtogroup G_NODE_DIS
+ * @{
+
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "ucs_inic_pb.h"
+#include "ucs_nodedis.h"
+#include "ucs_misc.h"
+
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+#define ND_NUM_STATES 5U /*!< \brief Number of state machine states */
+#define ND_NUM_EVENTS 14U /*!< \brief Number of state machine events */
+
+#define ND_TIMEOUT_PERIODIC 5000U /*!< \brief 5s timeout */
+#define ND_TIMEOUT_COMMAND 300U /*!< \brief supervise EXC commands */
+
+#define ND_SIGNATURE_VERSION 1U /*!< \brief signature version used for Node Discovery */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Service parameters */
+/*------------------------------------------------------------------------------------------------*/
+/*! Priority of the Node Discovery service used by scheduler */
+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." */
+/*! Main event for the Node Discovery service */
+static const Srv_Event_t ND_EVENT_SERVICE = 1U;
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal enumerators */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Possible events of the Node Discovery state machine */
+typedef enum Nd_Events_
+{
+ ND_E_NIL = 0U, /*!< \brief NIL Event */
+ ND_E_START = 1U, /*!< \brief API start command was called. */
+ ND_E_STOP = 2U, /*!< \brief Stop request occurred. */
+ ND_E_CHECK = 3U, /*!< \brief Check conditions in CHECK_HELLO state. */
+ ND_E_NET_OFF = 4U, /*!< \brief NetOff occurred. */
+ ND_E_HELLO_STATUS = 5U, /*!< \brief Hello.Status message available to be processed. */
+ ND_E_RES_NODE_OK = 6U, /*!< \brief Evaluation result of node: ok. */
+ ND_E_RES_UNKNOWN = 7U, /*!< \brief Evaluation result of node: unknown node. */
+ ND_E_RES_CHECK_UNIQUE = 8U, /*!< \brief Evaluation result of node: check if node is unique. */
+ ND_E_WELCOME_SUCCESS = 9U, /*!< \brief Welcome command was successful. */
+ ND_E_WELCOME_NOSUCCESS = 10U, /*!< \brief Welcome command was not successful. */
+ ND_E_SIGNATURE_SUCCESS = 11U, /*!< \brief Signature command was successful. */
+ ND_E_TIMEOUT = 12U, /*!< \brief Timeout occurred. */
+ ND_E_ERROR = 13U /*!< \brief An unexpected error occurred. */
+
+} Nd_Events_t;
+
+
+/*! \brief States of the Node Discovery state machine */
+typedef enum Nd_State_
+{
+ ND_S_IDLE = 0U, /*!< \brief Idle state */
+ ND_S_CHECK_HELLO = 1U, /*!< \brief Node Discovery started */
+ ND_S_WAIT_EVAL = 2U, /*!< \brief Evaluate next Hello.Status message */
+ ND_S_WAIT_WELCOME = 3U, /*!< \brief Wait for Welcome.Status */
+ ND_S_WAIT_PING = 4U /*!< \brief Wait for Signature.Status */
+} Nd_State_t;
+
+
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static void Nd_Service(void *self);
+
+static void Nd_HelloStatusCb(void *self, void *result_ptr);
+static void Nd_WelcomeResultCb(void *self, void *result_ptr);
+static void Nd_SignatureStatusCb(void *self, void *result_ptr);
+static void Nd_InitCb(void *self, void *result_ptr);
+static void Nd_TimerCb(void *self);
+static void Nd_OnTerminateEventCb(void *self, void *result_ptr);
+static void Nd_NetworkStatusCb(void *self, void *result_ptr);
+
+static void Nd_Reset_Lists(void *self);
+
+static void Nd_A_Start(void *self);
+static void Nd_A_Stop(void *self);
+static void Nd_A_CheckConditions(void *self);
+static void Nd_A_Eval_Hello(void *self);
+static void Nd_A_Welcome(void *self);
+static void Nd_A_Unknown(void *self);
+static void Nd_A_CheckUnique(void *self);
+static void Nd_A_WelcomeSuccess(void *self);
+static void Nd_A_WelcomeNoSuccess(void *self);
+static void Nd_A_WelcomeTimeout(void *self);
+static void Nd_A_Timeout_Hello(void *self);
+static void Nd_A_NetOff(void *self);
+static void Nd_A_Signature_Timeout(void *self);
+static void Nd_A_Signature_Success(void *self);
+static void Nd_A_Error(void *self);
+
+static void Nd_Send_Hello_Get(void *self);
+static void Nd_Start_Periodic_Timer(void *self);
+static void Nd_Send_Welcome_SR(void *self, Ucs_Signature_t *signature);
+static void Nd_Send_Signature_Get(void *self, uint16_t target_address);
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* State transition table (used by finite state machine) */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief State transition table */
+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." */
+{
+ { /* State ND_S_IDLE */
+ /* ND_E_NIL */ {NULL, ND_S_IDLE },
+ /* ND_E_START */ {&Nd_A_Start, ND_S_CHECK_HELLO },
+ /* ND_E_STOP */ {NULL, ND_S_IDLE },
+ /* ND_E_CHECK */ {NULL, ND_S_IDLE },
+ /* ND_E_NET_OFF */ {NULL, ND_S_IDLE },
+ /* ND_E_HELLO_STATUS */ {NULL, ND_S_IDLE },
+ /* ND_E_RES_NODE_OK */ {NULL, ND_S_IDLE },
+ /* ND_E_RES_UNKNOWN */ {NULL, ND_S_IDLE },
+ /* ND_E_RES_CHECK_UNIQUE */ {NULL, ND_S_IDLE },
+ /* ND_E_WELCOME_SUCCESS */ {NULL, ND_S_IDLE },
+ /* ND_E_WELCOME_NOSUCCESS */ {NULL, ND_S_IDLE },
+ /* ND_E_SIGNATURE_SUCCESS */ {NULL, ND_S_IDLE },
+ /* ND_E_TIMEOUT */ {NULL, ND_S_IDLE },
+ /* ND_E_ERROR */ {NULL, ND_S_IDLE }
+
+ },
+ { /* State ND_S_CHECK_HELLO */
+ /* ND_E_NIL */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_START */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_STOP */ {&Nd_A_Stop, ND_S_IDLE },
+ /* ND_E_CHECK */ {&Nd_A_CheckConditions, ND_S_CHECK_HELLO },
+ /* ND_E_NET_OFF */ {&Nd_A_NetOff, ND_S_CHECK_HELLO },
+ /* ND_E_HELLO_STATUS */ {&Nd_A_Eval_Hello, ND_S_WAIT_EVAL },
+ /* ND_E_RES_NODE_OK */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_RES_UNKNOWN */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_RES_CHECK_UNIQUE */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_WELCOME_SUCCESS */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_WELCOME_NOSUCCESS */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_SIGNATURE_SUCCESS */ {NULL, ND_S_CHECK_HELLO },
+ /* ND_E_TIMEOUT */ {&Nd_A_Timeout_Hello, ND_S_CHECK_HELLO },
+ /* ND_E_ERROR */ {&Nd_A_Error, ND_S_IDLE }
+ },
+ { /* State ND_S_WAIT_EVAL */
+ /* ND_E_NIL */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_START */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_STOP */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_CHECK */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_NET_OFF */ {&Nd_A_NetOff, ND_S_CHECK_HELLO },
+ /* ND_E_HELLO_STATUS */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_RES_NODE_OK */ {&Nd_A_Welcome, ND_S_WAIT_WELCOME },
+ /* ND_E_RES_UNKNOWN */ {&Nd_A_Unknown, ND_S_CHECK_HELLO },
+ /* ND_E_RES_CHECK_UNIQUE */ {&Nd_A_CheckUnique, ND_S_WAIT_PING },
+ /* ND_E_WELCOME_SUCCESS */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_WELCOME_NOSUCCESS */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_SIGNATURE_SUCCESS */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_TIMEOUT */ {NULL, ND_S_WAIT_EVAL },
+ /* ND_E_ERROR */ {&Nd_A_Error, ND_S_IDLE }
+ },
+
+ {/* ND_S_WAIT_WELCOME */
+ /* ND_E_NIL */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_START */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_STOP */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_CHECK */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_NET_OFF */ {&Nd_A_NetOff, ND_S_CHECK_HELLO },
+ /* ND_E_HELLO_STATUS */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_RES_NODE_OK */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_RES_UNKNOWN */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_RES_CHECK_UNIQUE */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_WELCOME_SUCCESS */ {&Nd_A_WelcomeSuccess, ND_S_CHECK_HELLO },
+ /* ND_E_WELCOME_NOSUCCESS */ {&Nd_A_WelcomeNoSuccess, ND_S_CHECK_HELLO },
+ /* ND_E_SIGNATURE_SUCCESS */ {NULL, ND_S_WAIT_WELCOME },
+ /* ND_E_TIMEOUT */ {&Nd_A_WelcomeTimeout, ND_S_CHECK_HELLO },
+ /* ND_E_ERROR */ {&Nd_A_Error, ND_S_IDLE }
+ },
+ {/* ND_S_WAIT_PING */
+ /* ND_E_NIL */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_START */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_STOP */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_CHECK */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_NET_OFF */ {&Nd_A_NetOff, ND_S_CHECK_HELLO },
+ /* ND_E_HELLO_STATUS */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_RES_NODE_OK */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_RES_UNKNOWN */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_RES_CHECK_UNIQUE */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_WELCOME_SUCCESS */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_WELCOME_NOSUCCESS */ {NULL, ND_S_WAIT_PING },
+ /* ND_E_SIGNATURE_SUCCESS */ {&Nd_A_Signature_Success, ND_S_CHECK_HELLO },
+ /* ND_E_TIMEOUT */ {&Nd_A_Signature_Timeout, ND_S_WAIT_WELCOME },
+ /* ND_E_ERROR */ {&Nd_A_Error, ND_S_IDLE }
+ }
+};
+
+
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* Implementation */
+/*------------------------------------------------------------------------------------------------*/
+
+/*! \brief Constructor of class CNodeDiscovery.
+ * \param self Reference to CNodeDiscovery instance
+ * \param inic Reference to CInic instance
+ * \param base Reference to CBase instance
+ * \param exc Reference to CExc instance
+ * \param init_ptr Report callback function
+ */
+void Nd_Ctor(CNodeDiscovery *self, CInic *inic, CBase *base, CExc *exc, Nd_InitData_t *init_ptr)
+{
+ MISC_MEM_SET((void *)self, 0, sizeof(*self));
+
+ self->inic = inic;
+ self->exc = exc;
+ self->base = base;
+ self->cb_inst_ptr = init_ptr->inst_ptr;
+ self->report_fptr = init_ptr->report_fptr;
+ self->eval_fptr = init_ptr->eval_fptr;
+
+ Fsm_Ctor(&self->fsm, self, &(nd_trans_tab[0][0]), ND_NUM_EVENTS, ND_E_NIL);
+
+ Nd_Reset_Lists(self);
+
+ Sobs_Ctor(&self->nd_hello, self, &Nd_HelloStatusCb);
+ Sobs_Ctor(&self->nd_welcome, self, &Nd_WelcomeResultCb);
+ Sobs_Ctor(&self->nd_signature, self, &Nd_SignatureStatusCb);
+ Sobs_Ctor(&self->nd_init, self, &Nd_InitCb);
+
+ /* register termination events */
+ Mobs_Ctor(&self->nd_terminate, self, EH_M_TERMINATION_EVENTS, &Nd_OnTerminateEventCb);
+ Eh_AddObsrvInternalEvent(&self->base->eh, &self->nd_terminate);
+
+ /* Register NetOn and MPR events */
+ Obs_Ctor(&self->nd_nwstatus, self, &Nd_NetworkStatusCb);
+ Inic_AddObsrvNwStatus(self->inic, &self->nd_nwstatus);
+ self->neton = false;
+
+ /* Initialize Node Discovery service */
+ Srv_Ctor(&self->service, ND_SRV_PRIO, self, &Nd_Service);
+ /* Add Node Discovery service to scheduler */
+ (void)Scd_AddService(&self->base->scd, &self->service);
+
+}
+
+
+/*! \brief Service function of the Node Discovery service.
+ * \param self Reference to Node Discovery object
+ */
+static void Nd_Service(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Srv_Event_t event_mask;
+ Srv_GetEvent(&self_->service, &event_mask);
+ if(ND_EVENT_SERVICE == (event_mask & ND_EVENT_SERVICE)) /* Is event pending? */
+ {
+ Fsm_State_t result;
+ Srv_ClearEvent(&self_->service, ND_EVENT_SERVICE);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "FSM __ %d %d", 2U, self_->fsm.current_state, self_->fsm.event_occured));
+ result = Fsm_Service(&self_->fsm);
+ TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", (result != FSM_STATE_ERROR));
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "FSM -> %d", 1U, self_->fsm.current_state));
+ MISC_UNUSED(result);
+ }
+}
+
+
+
+/**************************************************************************************************/
+/* API functions */
+/**************************************************************************************************/
+/*! \brief Start the Node Discovery
+ *
+ * \param *self Reference to Node Discovery object
+ * \return UCS_RET_SUCCESS Operation successful
+ * \return UCS_RET_ERR_API_LOCKED Node Discovery was already started
+ */
+Ucs_Return_t Nd_Start(CNodeDiscovery *self)
+{
+ Ucs_Return_t ret_val = UCS_RET_SUCCESS;
+
+
+ if (self->running == false)
+ {
+ Fsm_SetEvent(&self->fsm, ND_E_START);
+ Srv_SetEvent(&self->service, ND_EVENT_SERVICE);
+ self->running = true;
+ TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Start", 0U));
+ }
+ else
+ {
+ ret_val = UCS_RET_ERR_API_LOCKED;
+ TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Start failed", 0U));
+ }
+
+ return ret_val;
+
+
+
+
+}
+
+/*! \brief Stops the Node Discovery
+ *
+ * \param *self Reference to Node Discovery object
+ * \return UCS_RET_SUCCESS Operation successful
+ * \return UCS_RET_ERR_NOT_AVAILABLE Node Discovery not running
+ */
+Ucs_Return_t Nd_Stop(CNodeDiscovery *self)
+{
+ Ucs_Return_t ret_val = UCS_RET_SUCCESS;
+
+ if (self->running == true) /* check if Node Discovery was started */
+ {
+ self->stop_request = true;
+ Fsm_SetEvent(&self->fsm, ND_E_CHECK);
+ Srv_SetEvent(&self->service, ND_EVENT_SERVICE);
+
+ TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Stop", 0U));
+ }
+ else
+ {
+ ret_val = UCS_RET_ERR_NOT_AVAILABLE;
+ TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_Stop failed", 0U));
+ }
+
+ return ret_val;
+}
+
+
+/*! \brief Sends the Init command to all nodes
+ *
+ * \param *self Reference to Node Discovery object
+ */
+void Nd_InitAll(CNodeDiscovery *self)
+{
+ Ucs_Return_t result;
+
+ result = Exc_DeviceInit_Start(self->exc, UCS_ADDR_BROADCAST_BLOCKING, NULL);
+ if (result == UCS_RET_SUCCESS)
+ {
+ TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_InitAll", 0U));
+ }
+ else
+ {
+ TR_INFO((self->base->ucs_user_ptr, "[ND]", "Nd_InitAll failed", 0U));
+ }
+
+}
+
+
+
+
+/**************************************************************************************************/
+/* FSM Actions */
+/**************************************************************************************************/
+/*! \brief Action on start event
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Start(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ /* empty new_list*/
+ Nd_Reset_Lists(self_);
+
+ Nd_Send_Hello_Get(self_);
+
+ Nd_Start_Periodic_Timer(self_);
+
+ self_->stop_request = false;
+ self_->hello_mpr_request = false;
+ self_->hello_neton_request = false;
+}
+
+/*! \brief Action on stop event
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Stop(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Ucs_Signature_t *dummy = NULL;
+
+ if (self_->report_fptr != NULL)
+ {
+ self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_STOPPED, dummy);
+ }
+ self_->running = false;
+}
+
+/*! \brief Check conditions
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_CheckConditions(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ if (self_->stop_request == true)
+ {
+ Fsm_SetEvent(&self_->fsm, ND_E_STOP);
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+ }
+ else if (self_->hello_mpr_request == true)
+ {
+ Nd_Reset_Lists(self_);
+ Nd_Send_Hello_Get(self_);
+ Nd_Start_Periodic_Timer(self_);
+ self_->hello_mpr_request = false;
+ self_->hello_neton_request = false;
+ }
+ else if (self_->hello_neton_request == true)
+ {
+ Nd_Send_Hello_Get(self_);
+ Nd_Start_Periodic_Timer(self_);
+ self_->hello_neton_request = false;
+ }
+ else if (Dl_GetSize(&(self_->new_list)) > 0U)
+ {
+ Fsm_SetEvent(&self_->fsm, ND_E_HELLO_STATUS);
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+ }
+ else
+ {
+ Nd_Start_Periodic_Timer(self_);
+ }
+
+}
+
+
+/*! \brief Evaluate the signature of the next node
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Eval_Hello(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ CDlNode *node;
+ Ucs_Nd_CheckResult_t result;
+ bool service_flag = false;
+ Ucs_Signature_t temp_sig;
+
+ if (Dl_GetSize(&(self_->new_list)) > 0U)
+ {
+ node = Dl_PopHead(&(self_->new_list));
+ self_->current_sig = *((Ucs_Signature_t *)(node->data_ptr));
+
+ if (self_->eval_fptr != NULL)
+ {
+ temp_sig = self_->current_sig; /* provide only a copy to the application */
+ result = self_->eval_fptr(self_->cb_inst_ptr, &temp_sig);
+
+ switch (result)
+ {
+ case UCS_ND_CHK_UNKNOWN:
+ Fsm_SetEvent(&self_->fsm, ND_E_RES_UNKNOWN);
+ service_flag = true;
+ break;
+
+ case UCS_ND_CHK_WELCOME:
+ Fsm_SetEvent(&self_->fsm, ND_E_RES_NODE_OK);
+ service_flag = true;
+ break;
+
+ case UCS_ND_CHK_UNIQUE:
+ Fsm_SetEvent(&self_->fsm, ND_E_RES_CHECK_UNIQUE);
+ service_flag = true;
+ break;
+
+ default:
+ Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
+ service_flag = true;
+ break;
+ }
+ }
+ }
+
+ if (service_flag == true)
+ {
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+ }
+}
+
+
+/*! \brief Sends a Welcome message to the current node
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Welcome(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ Nd_Send_Welcome_SR(self, &self_->current_sig);
+}
+
+
+/*! \brief Report the current node as unknown
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Unknown(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Ucs_Signature_t temp_sig;
+
+ if (self_->report_fptr != NULL)
+ {
+ temp_sig = self_->current_sig; /* provide only a copy to the application */
+ self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_UNKNOWN, &temp_sig);
+ }
+
+ Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+/*! \brief Check if the current node has already got a Welcome message
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_CheckUnique(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ Nd_Send_Signature_Get(self, self_->current_sig.node_address);
+
+}
+
+
+/*! \brief Report a successful Welcome.Result
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_WelcomeSuccess(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Ucs_Signature_t temp_sig;
+
+ if (self_->report_fptr != NULL)
+ {
+ temp_sig = self_->current_sig; /* provide only a copy to the application */
+ self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_WELCOME_SUCCESS, &temp_sig);
+ }
+
+ /* initiate a Hello.Get if the current node is the local INIC */
+ if (self_->current_sig.node_pos_addr == 0x0400U)
+ {
+ Nd_Send_Hello_Get(self_);
+ Nd_Start_Periodic_Timer(self_);
+ }
+
+ Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+/*! \brief Report an unsuccessful Welcome.Result
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_WelcomeNoSuccess(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ /* same reaction as for MPR event */
+ self_->hello_mpr_request = true;
+
+ Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+/*! \brief Reaction on a timeout for the Welcome messsage
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_WelcomeTimeout(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ /* same reaction as for MPR event */
+ self_->hello_mpr_request = true;
+
+ Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+/*! \brief The periodic timer elapsed
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Timeout_Hello(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ Nd_Send_Hello_Get(self_);
+ Nd_Start_Periodic_Timer(self_);
+}
+
+
+/*! \brief Reaction on a NetOff event
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_NetOff(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Ucs_Signature_t *dummy = NULL;
+
+ if (self_->report_fptr != NULL)
+ {
+ self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_NETOFF, dummy);
+ }
+
+ Nd_Reset_Lists(self_);
+
+}
+
+
+/*! \brief Reaction on a timeout of the Signature command
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Signature_Timeout(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ Nd_Send_Welcome_SR(self, &self_->current_sig);
+}
+
+
+/*! \brief Reaction on a successful Signature answer
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Signature_Success(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Ucs_Signature_t temp_sig;
+
+ if (self_->report_fptr != NULL)
+ {
+ temp_sig = self_->current_sig; /* provide only a copy to the application */
+ self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_MULTI, &temp_sig);
+ }
+}
+
+
+/*! \brief An unecpected error occurred
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_A_Error(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Ucs_Signature_t *dummy = NULL;
+
+ if (self_->report_fptr != NULL)
+ {
+ self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_ERROR, dummy);
+ }
+ self_->running = false;
+}
+
+
+/**************************************************************************************************/
+/* Callback functions */
+/**************************************************************************************************/
+
+/*! Callback function for the Exc.Hello.Status message
+ *
+ * \param *self Reference to Node Discovery object
+ * \param *result_ptr Result of the Exc_Hello_Get() command
+ */
+static void Nd_HelloStatusCb(void *self, void *result_ptr)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
+ CDlNode *node;
+
+ if (result_ptr_->result.code == UCS_RES_SUCCESS)
+ {
+ /* read signature and store it in the new_list */
+ node = Dl_PopHead(&(self_->unused_list)); /* get an unused list element */
+ if (node != NULL)
+ {
+ ((Nd_Node *)(node->data_ptr))->signature = (*(Exc_HelloStatus_t *)(result_ptr_->data_info)).signature;
+ Dl_InsertTail(&(self_->new_list), node);
+
+ Fsm_SetEvent(&self_->fsm, ND_E_HELLO_STATUS);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb UCS_RES_SUCCESS", 0U));
+ }
+ else
+ {
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb No list entry av.", 0U));
+ }
+ }
+ else
+ {
+ Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_HelloStatusCb ND_E_ERROR", 0U));
+ }
+
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+/*! \brief Function is called on reception of the Welcome.Result messsage
+ * \param self Reference to Node Discovery object
+ * \param result_ptr Pointer to the result of the Welcome message
+ */
+static void Nd_WelcomeResultCb(void *self, void *result_ptr)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
+
+ Tm_ClearTimer(&self_->base->tm, &self_->timer);
+
+ if (result_ptr_->result.code == UCS_RES_SUCCESS)
+ {
+ /* read signature and store it */
+ self_->welcome_result = *(Exc_WelcomeResult_t *)(result_ptr_->data_info);
+ if (self_->welcome_result.res == EXC_WELCOME_SUCCESS)
+ {
+ Fsm_SetEvent(&self_->fsm, ND_E_WELCOME_SUCCESS);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb ND_E_WELCOME_SUCCESS", 0U));
+ }
+ else
+ {
+ Fsm_SetEvent(&self_->fsm, ND_E_WELCOME_NOSUCCESS);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb ND_E_WELCOME_NOSUCCESS", 0U));
+ }
+ }
+ else
+ {
+ uint8_t i;
+
+ if ( (result_ptr_->result.info_size == 3U)
+ && (result_ptr_->result.info_ptr[0] == 0x20U)
+ && (result_ptr_->result.info_ptr[1] == 0x03U)
+ && (result_ptr_->result.info_ptr[2] == 0x31U))
+ { /* Device has not yet received an ExtendedNetworkControl.Hello.Get() message. */
+ Fsm_SetEvent(&self_->fsm, ND_E_WELCOME_NOSUCCESS);
+ }
+ else
+ {
+ Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb Error (code) 0x%x", 1U, result_ptr_->result.code));
+ for (i=0U; i< result_ptr_->result.info_size; ++i)
+ {
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_WelcomeResultCb Error (info) 0x%x", 1U, result_ptr_->result.info_ptr[i]));
+ }
+ }
+ }
+
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+/*! \brief Callback function for Signature status and error messages
+ *
+ * \param *self Reference to Node Discovery object
+ * \param *result_ptr Pointer to the result of the Signature message
+ */
+static void Nd_SignatureStatusCb(void *self, void *result_ptr)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
+
+ Tm_ClearTimer(&self_->base->tm, &self_->timer);
+
+ if (result_ptr_->result.code == UCS_RES_SUCCESS)
+ {
+ self_->signature_status = *(Exc_SignatureStatus_t *)(result_ptr_->data_info);
+ Fsm_SetEvent(&self_->fsm, ND_E_SIGNATURE_SUCCESS);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_SignatureStatusCb ND_E_SIGNATURE_SUCCESS", 0U));
+ }
+ else
+ {
+ Fsm_SetEvent(&self_->fsm, ND_E_ERROR);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_SignatureStatusCb Error 0x%x", 1U, result_ptr_->result.code));
+ }
+
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+/*! \brief Callback function for Init error messages
+ *
+ * \param *self Reference to Node Discovery object
+ * \param *result_ptr Pointer to the result of the Init message
+ */
+static void Nd_InitCb(void *self, void *result_ptr)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Exc_StdResult_t *result_ptr_ = (Exc_StdResult_t *)result_ptr;
+
+ MISC_UNUSED(self_);
+ MISC_UNUSED(result_ptr_);
+
+}
+
+
+/*! \brief Timer callback used for supervising INIC command timeouts.
+ * \param self Reference to Node Discovery object
+ */
+static void Nd_TimerCb(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ Fsm_SetEvent(&self_->fsm, ND_E_TIMEOUT);
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_TimerCb ND_E_TIMEOUT", 0U));
+
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+/*! Function is called on severe internal errors
+ *
+ * \param *self Reference to Node Discovery object
+ * \param *result_ptr Reference to data
+ */
+static void Nd_OnTerminateEventCb(void *self, void *result_ptr)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Ucs_Signature_t *dummy = NULL;
+
+ MISC_UNUSED(result_ptr);
+
+ if (self_->fsm.current_state != ND_S_IDLE)
+ {
+ Tm_ClearTimer(&self_->base->tm, &self_->timer);
+ if (self_->report_fptr != NULL)
+ {
+ self_->report_fptr(self_->cb_inst_ptr, UCS_ND_RES_ERROR, dummy);
+ }
+ Nd_Reset_Lists(self_);
+ }
+}
+
+
+/*! \brief Callback function for the INIC.NetworkStatus status and error messages
+ *
+ * \param *self Reference to Node Discovery object
+ * \param *result_ptr Pointer to the result of the INIC.NetworkStatus message
+ */
+static void Nd_NetworkStatusCb(void *self, void *result_ptr)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ Inic_StdResult_t *result_ptr_ = (Inic_StdResult_t *)result_ptr;
+
+ if (result_ptr_->result.code == UCS_RES_SUCCESS)
+ {
+ TR_INFO((self_->base->ucs_user_ptr, "[ND]", "Nd_NetworkStatusCb 0x%x", 1U, result_ptr_->result.code));
+ /* check for NetOn/NetOff events */
+ if ( (self_->neton == true)
+ && ((((Inic_NetworkStatus_t *)(result_ptr_->data_info))->availability) == UCS_NW_NOT_AVAILABLE) )
+ {
+ self_->neton = false;
+ Fsm_SetEvent(&self_->fsm, ND_E_NET_OFF);
+ }
+ /* check for NetOn/NetOff events */
+ else if ( (self_->neton == false)
+ && ((((Inic_NetworkStatus_t *)(result_ptr_->data_info))->availability) == UCS_NW_AVAILABLE) )
+ {
+ self_->neton = true;
+ self_->hello_neton_request = true;
+ Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
+ }
+ /* check for MPR event */
+ else if ( (((Inic_NetworkStatus_t *)(result_ptr_->data_info))->events & UCS_NETWORK_EVENT_NCE)
+ == UCS_NETWORK_EVENT_NCE)
+ {
+ self_->hello_mpr_request = true;
+ Fsm_SetEvent(&self_->fsm, ND_E_CHECK);
+ }
+ }
+
+ Srv_SetEvent(&self_->service, ND_EVENT_SERVICE);
+}
+
+
+
+/**************************************************************************************************/
+/* Helper functions */
+/**************************************************************************************************/
+/*! \brief Reset the list of new detected nodes
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_Reset_Lists(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ uint16_t i;
+
+ Dl_Ctor(&self_->new_list, self_->base->ucs_user_ptr);
+ Dl_Ctor(&self_->unused_list, self_->base->ucs_user_ptr);
+
+ for(i=0U; i < ND_NUM_NODES; ++i)
+ {
+ Dln_Ctor(&(self_->nodes[i]).node, &(self_->nodes[i]));
+ Dl_InsertTail(&(self_->unused_list), &(self_->nodes[i]).node);
+ }
+}
+
+
+/*! \brief Send the Hello.Get message
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_Send_Hello_Get(void *self)
+{
+ Ucs_Return_t ret_val;
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ ret_val = Exc_Hello_Get(self_->exc, UCS_ADDR_BROADCAST_BLOCKING,
+ ND_SIGNATURE_VERSION, &self_->nd_hello);
+
+ TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
+ MISC_UNUSED(ret_val);
+}
+
+
+/*! \brief Send the Welcome.StartResult message
+ *
+ * \param *self Reference to Node Discovery object
+ * \param *signature signature parameter
+ */
+static void Nd_Send_Welcome_SR(void *self, Ucs_Signature_t *signature)
+{
+ Ucs_Return_t ret_val;
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+ uint16_t target_address;
+
+ if (signature->node_pos_addr == 0x0400U)
+ {
+ target_address = 0x0001U;
+ }
+ else
+ {
+ target_address = signature->node_pos_addr;
+ }
+
+ ret_val = Exc_Welcome_Sr(self_->exc,
+ target_address,
+ 0xFFFFU,
+ ND_SIGNATURE_VERSION,
+ *signature,
+ &self_->nd_welcome);
+ Tm_SetTimer(&self_->base->tm,
+ &self_->timer,
+ &Nd_TimerCb,
+ self_,
+ ND_TIMEOUT_COMMAND,
+ 0U);
+ TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
+ MISC_UNUSED(ret_val);
+}
+
+
+/*! \brief Send the Signature.Get message
+ *
+ * \param *self Reference to Node Discovery object
+ * \param target_address target address for the command
+ */
+static void Nd_Send_Signature_Get(void *self, uint16_t target_address)
+{
+ Ucs_Return_t ret_val;
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ ret_val = Exc_Signature_Get(self_->exc, target_address, ND_SIGNATURE_VERSION, &self_->nd_signature);
+ Tm_SetTimer(&self_->base->tm,
+ &self_->timer,
+ &Nd_TimerCb,
+ self_,
+ ND_TIMEOUT_COMMAND,
+ 0U);
+ TR_ASSERT(self_->base->ucs_user_ptr, "[ND]", ret_val == UCS_RET_SUCCESS);
+ MISC_UNUSED(ret_val);
+}
+
+/*! \brief Starts the periodic timer
+ *
+ * \param *self Reference to Node Discovery object
+ */
+static void Nd_Start_Periodic_Timer(void *self)
+{
+ CNodeDiscovery *self_ = (CNodeDiscovery *)self;
+
+ Tm_SetTimer(&self_->base->tm,
+ &self_->timer,
+ &Nd_TimerCb,
+ self,
+ ND_TIMEOUT_PERIODIC,
+ 0U);
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+