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 CNodeObserver class
26 * \cond UCS_INTERNAL_DOC
27 * \addtogroup G_NODEOBSERVER
31 /*------------------------------------------------------------------------------------------------*/
33 /*------------------------------------------------------------------------------------------------*/
34 #include "ucs_nodeobserver.h"
36 #include "ucs_trace.h"
38 /*------------------------------------------------------------------------------------------------*/
39 /* Internal constants */
40 /*------------------------------------------------------------------------------------------------*/
41 #define NOBS_ADDR_ADMIN_MIN 0xF80U /*!< \brief Start of address range to park unknown devices */
42 #define NOBS_ADDR_ADMIN_MAX 0xFDFU /*!< \brief End of address range to park unknown devices */
44 #define NOBS_ADDR_RANGE1_MIN 0x200U /*!< \brief Start of first static address range */
45 #define NOBS_ADDR_RANGE1_MAX 0x2FFU /*!< \brief End of first static address range */
46 #define NOBS_ADDR_RANGE2_MIN 0x500U /*!< \brief Start of second static address range */
47 #define NOBS_ADDR_RANGE2_MAX 0xEFFU /*!< \brief End of second static address range */
49 #define NOSB_JOIN_NO 0x00U
50 #define NOSB_JOIN_WAIT 0x01U
51 #define NOSB_JOIN_YES 0x02U
53 #define NOBS_WAIT_TIME 200U /*!< \brief Wait time between node not_available -> available */
55 /*------------------------------------------------------------------------------------------------*/
56 /* Internal prototypes */
57 /*------------------------------------------------------------------------------------------------*/
58 static void Nobs_OnInitComplete(void *self, void *error_code_ptr);
59 static void Nobs_OnWakeupTimer(void *self);
60 static bool Nobs_CheckAddrRange(CNodeObserver *self, Ucs_Signature_t *signature_ptr);
61 static void Nobs_InitAllNodes(CNodeObserver *self);
62 static void Nobs_InvalidateAllNodes(CNodeObserver *self);
63 static void Nobs_InvalidateNode(CNodeObserver *self, Ucs_Rm_Node_t *node_ptr);
64 static Ucs_Rm_Node_t* Nobs_GetNodeBySignature(CNodeObserver *self, Ucs_Signature_t *signature_ptr);
65 static void Nobs_NotifyApp(CNodeObserver *self, Ucs_MgrReport_t code, uint16_t node_address, Ucs_Rm_Node_t *node_ptr);
67 /*------------------------------------------------------------------------------------------------*/
69 /*------------------------------------------------------------------------------------------------*/
70 /*! \brief Constructor of NodeObserver class
71 * \param self The instance
72 * \param base_ptr Reference to base component
73 * \param nd_ptr Reference to NodeDiscovery component
74 * \param rtm_ptr Reference to RoutingManagement component
75 * \param init_ptr Reference to initialization data
77 void Nobs_Ctor(CNodeObserver *self, CBase *base_ptr, CNodeDiscovery *nd_ptr, CRouteManagement *rtm_ptr, Ucs_Mgr_InitData_t *init_ptr)
79 MISC_MEM_SET(self, 0, sizeof(*self));
80 self->base_ptr = base_ptr;
81 self->nd_ptr = nd_ptr;
82 self->rtm_ptr = rtm_ptr;
85 self->init_data = *init_ptr;
87 Nobs_InitAllNodes(self);
88 T_Ctor(&self->wakeup_timer);
90 Mobs_Ctor(&self->event_observer, self, EH_E_INIT_SUCCEEDED, &Nobs_OnInitComplete);
91 Eh_AddObsrvInternalEvent(&self->base_ptr->eh, &self->event_observer);
94 /*! \brief Callback function which is invoked if the initialization is complete
95 * \param self The instance
96 * \param error_code_ptr Reference to the error code
98 static void Nobs_OnInitComplete(void *self, void *error_code_ptr)
100 CNodeObserver *self_ = (CNodeObserver*)self;
101 MISC_UNUSED(error_code_ptr);
103 (void)Nd_Start(self_->nd_ptr);
104 (void)Rtm_StartProcess(self_->rtm_ptr, self_->init_data.routes_list_ptr, self_->init_data.routes_list_size);
107 /*------------------------------------------------------------------------------------------------*/
108 /* Callback Methods */
109 /*------------------------------------------------------------------------------------------------*/
110 Ucs_Nd_CheckResult_t Nobs_OnNdEvaluate(void *self, Ucs_Signature_t *signature_ptr)
112 CNodeObserver *self_ = (CNodeObserver*)self;
113 Ucs_Rm_Node_t *node_ptr = NULL;
114 Ucs_Nd_CheckResult_t ret = UCS_ND_CHK_UNKNOWN; /* ignore by default */
116 if (signature_ptr != NULL)
118 if (Nobs_CheckAddrRange(self_, signature_ptr) != false)
120 node_ptr = Nobs_GetNodeBySignature(self_, signature_ptr);
122 if (node_ptr != NULL)
124 if (node_ptr->internal_infos.mgr_joined == NOSB_JOIN_NO)
126 ret = UCS_ND_CHK_WELCOME; /* welcome new node */
128 else if (node_ptr->internal_infos.mgr_joined == NOSB_JOIN_YES)
130 ret = UCS_ND_CHK_UNIQUE; /* node already available - check for reset */
132 /* else if (node_ptr->internal_infos.mgr_joined == NOSB_JOIN_WAIT) --> ignore waiting nodes */
133 /* future version compare node position to improve handling */
137 self_->eval_signature = *signature_ptr;
138 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdEvaluate(): node=0x%03X, node_pos=0x%03X, ret=0x%02X", 2U, signature_ptr->node_address, signature_ptr->node_pos_addr, ret));
142 MISC_MEM_SET(&self_->eval_signature, 0, sizeof(self_->eval_signature)); /* reset signature */
143 TR_FAILED_ASSERT(self_->base_ptr->ucs_user_ptr, "[NOBS]"); /* signature missing - it is evident for evaluation */
146 self_->eval_node_ptr = node_ptr;
147 self_->eval_action = ret;
149 if ((ret == UCS_ND_CHK_UNKNOWN) && (signature_ptr != NULL)) /* notify unknown node */
151 Nobs_NotifyApp(self_, UCS_MGR_REP_IGNORED_UNKNOWN, signature_ptr->node_address, NULL);
157 void Nobs_OnNdReport(void *self, Ucs_Nd_ResCode_t code, Ucs_Signature_t *signature_ptr)
159 CNodeObserver *self_ = (CNodeObserver*)self;
160 Ucs_Rm_Node_t *node_ptr = NULL;
162 if (signature_ptr != NULL)
164 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): code=0x%02X, node=0x%03X, node_pos=0x%03X", 3U, code, signature_ptr->node_address, signature_ptr->node_pos_addr));
165 node_ptr = Nobs_GetNodeBySignature(self_, signature_ptr);
166 if (node_ptr != self_->eval_node_ptr) /* if signature available -> expecting the same node_ptr as previously announced in Nobs_OnNdEvaluate */
168 TR_ERROR((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): sanity check failed node_ptr=%p, eval_node_ptr=%p", 2U, node_ptr, self_->eval_node_ptr));
169 node_ptr = NULL; /* do not handle node */
174 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): code=0x%02X", 1U, code));
177 if (code == UCS_ND_RES_NETOFF)
179 Nobs_InvalidateAllNodes(self_);
181 else if (node_ptr == NULL)
183 /* no not handle events with unspecified node */
185 else if ((code == UCS_ND_RES_WELCOME_SUCCESS) && (self_->eval_action == UCS_ND_CHK_WELCOME)) /* is new node? */
187 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): welcome of new node=0x%03X", 1U, signature_ptr->node_address));
188 node_ptr->internal_infos.mgr_joined = NOSB_JOIN_YES;
189 (void)Rtm_SetNodeAvailable(self_->rtm_ptr, node_ptr, true);
190 Nobs_NotifyApp(self_, UCS_MGR_REP_AVAILABLE, signature_ptr->node_address, node_ptr);
192 else if ((code == UCS_ND_RES_WELCOME_SUCCESS) && (self_->eval_action == UCS_ND_CHK_UNIQUE)) /* is node that previously joined */
194 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): welcome of existing node=0x%03X (RESET -> not_available)", 1U, signature_ptr->node_address));
195 node_ptr->internal_infos.mgr_joined = NOSB_JOIN_WAIT;
196 (void)Rtm_SetNodeAvailable(self_->rtm_ptr, node_ptr, false);
197 Nobs_NotifyApp(self_, UCS_MGR_REP_NOT_AVAILABLE, signature_ptr->node_address, node_ptr);
198 (void)Nd_Stop(self_->nd_ptr); /* stop node discovery and restart after timeout, */
199 Tm_SetTimer(&self_->base_ptr->tm, &self_->wakeup_timer, &Nobs_OnWakeupTimer, /* transition from node not_available -> available */
200 self, /* needs some time and no callback is provided. */
205 else if ((code == UCS_ND_RES_MULTI) && (self_->eval_action == UCS_ND_CHK_UNIQUE)) /* is node that causes address conflict */
208 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): ignoring duplicate node=0x%03X", 1U, signature_ptr->node_address));
209 Nobs_NotifyApp(self_, UCS_MGR_REP_IGNORED_DUPLICATE, signature_ptr->node_address, NULL);
211 else if (code == UCS_ND_RES_UNKNOWN)
214 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): ignoring unknown node=0x%03X", 1U, signature_ptr->node_address));
219 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnNdReport(): ignoring node in unexpected, node=0x%03X, code=0x02X ", 2U, signature_ptr->node_address, code));
223 static void Nobs_OnWakeupTimer(void *self)
225 CNodeObserver *self_ = (CNodeObserver*)self;
227 if (self_->eval_node_ptr != NULL)
229 if (self_->eval_node_ptr->internal_infos.mgr_joined == NOSB_JOIN_WAIT)
231 TR_INFO((self_->base_ptr->ucs_user_ptr, "[NOBS]", "Nobs_OnWakeupTimer(): welcome of existing node 0x%03X (RESET -> available)", 1U, self_->eval_node_ptr->signature_ptr->node_address));
232 self_->eval_node_ptr->internal_infos.mgr_joined = NOSB_JOIN_YES;
233 (void)Rtm_SetNodeAvailable(self_->rtm_ptr, self_->eval_node_ptr, true);
234 Nobs_NotifyApp(self_, UCS_MGR_REP_AVAILABLE, self_->eval_signature.node_address, self_->eval_node_ptr);
237 (void)Nd_Start(self_->nd_ptr);
241 /*------------------------------------------------------------------------------------------------*/
243 /*------------------------------------------------------------------------------------------------*/
245 /*! \brief Checks if the node address in signature is in supported address range
246 * \param self The instance
247 * \param signature_ptr Reference to the nodes signature
248 * \return Returns \c true if the address in signature is supported, otherwise \c false.
250 static bool Nobs_CheckAddrRange(CNodeObserver *self, Ucs_Signature_t *signature_ptr)
254 if (((signature_ptr->node_address >= NOBS_ADDR_RANGE1_MIN) && (signature_ptr->node_address <= NOBS_ADDR_RANGE1_MAX)) ||
255 ((signature_ptr->node_address >= NOBS_ADDR_RANGE2_MIN) && (signature_ptr->node_address <= NOBS_ADDR_RANGE2_MAX)))
264 static void Nobs_InitAllNodes(CNodeObserver *self)
266 if (self->init_data.nodes_list_ptr != NULL)
270 for (cnt = 0U; cnt < self->init_data.nodes_list_size; cnt++)
272 self->init_data.nodes_list_ptr[cnt].internal_infos.available = 0U;
273 self->init_data.nodes_list_ptr[cnt].internal_infos.mgr_joined = NOSB_JOIN_NO;
278 static void Nobs_InvalidateAllNodes(CNodeObserver *self)
280 if (self->init_data.nodes_list_ptr != NULL)
284 for (cnt = 0U; cnt < self->init_data.nodes_list_size; cnt++)
286 Nobs_InvalidateNode(self, &self->init_data.nodes_list_ptr[cnt]);
291 static void Nobs_InvalidateNode(CNodeObserver *self, Ucs_Rm_Node_t *node_ptr)
293 if (node_ptr->internal_infos.mgr_joined == NOSB_JOIN_YES) /* notify welcomed nodes as invalid */
295 Nobs_NotifyApp(self, UCS_MGR_REP_NOT_AVAILABLE, node_ptr->signature_ptr->node_address, node_ptr);
298 node_ptr->internal_infos.mgr_joined = NOSB_JOIN_NO;
299 /* RoutingManagement individually cares for network-not-available event */
300 /* (void)Rtm_SetNodeAvailable(self->rtm_ptr, &self->init_data.nodes_list_ptr[cnt], false); */
303 static Ucs_Rm_Node_t* Nobs_GetNodeBySignature(CNodeObserver *self, Ucs_Signature_t *signature_ptr)
305 Ucs_Rm_Node_t* ret = NULL;
307 if ((signature_ptr != NULL) && (self->init_data.nodes_list_ptr != NULL))
310 uint16_t node_addr = signature_ptr->node_address;
312 for (cnt = 0U; cnt < self->init_data.nodes_list_size; cnt++)
314 if (node_addr == self->init_data.nodes_list_ptr[cnt].signature_ptr->node_address)
316 ret = &self->init_data.nodes_list_ptr[cnt];
325 static void Nobs_NotifyApp(CNodeObserver *self, Ucs_MgrReport_t code, uint16_t node_address, Ucs_Rm_Node_t *node_ptr)
327 if (self->init_data.report_fptr != NULL)
329 self->init_data.report_fptr(code, node_address, node_ptr, self->base_ptr->ucs_user_ptr);
338 /*------------------------------------------------------------------------------------------------*/
340 /*------------------------------------------------------------------------------------------------*/