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 EndPoint Management.
26 * \cond UCS_INTERNAL_DOC
31 /*------------------------------------------------------------------------------------------------*/
33 /*------------------------------------------------------------------------------------------------*/
37 /*------------------------------------------------------------------------------------------------*/
38 /* Internal prototypes */
39 /*------------------------------------------------------------------------------------------------*/
40 static void Epm_XrmReportCb (uint16_t node_address, uint16_t connection_label, Ucs_Xrm_Result_t result, void * user_arg);
41 static bool Epm_RsmReportSyncLost (Fac_Inst_t inst_type, void * inst_ptr, void *ud_ptr);
43 /*------------------------------------------------------------------------------------------------*/
44 /* Implementation of class CEndpointManagement */
45 /*------------------------------------------------------------------------------------------------*/
46 /*------------------------------------------------------------------------------------------------*/
47 /* Initialization Methods */
48 /*------------------------------------------------------------------------------------------------*/
49 /*! \brief Constructor of the Remote Sync Manager class.
50 * \param self Instance pointer
51 * \param init_ptr init data_ptr
53 void Epm_Ctor(CEndpointManagement *self, Epm_InitData_t *init_ptr)
55 MISC_MEM_SET(self, 0, sizeof(CEndpointManagement));
57 /* Init all instances */
58 self->fac_ptr = init_ptr->fac_ptr;
59 self->base_ptr = init_ptr->base_ptr;
60 self->res_debugging_fptr = init_ptr->res_debugging_fptr;
61 self->check_unmute_fptr = init_ptr->check_unmute_fptr;
64 /*! \brief Initializes the internal information of the given endpoint object.
66 * Initialization is performed only if the magic number is not set.
68 * \param self Instance pointer
69 * \param ep_ptr Reference to the endpoint to be looked for
71 void Epm_InitInternalInfos(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr)
73 if ((self != NULL) && (ep_ptr != NULL))
75 if (ep_ptr->internal_infos.magic_number != (uint32_t)0x0BADC0DE)
77 MISC_MEM_SET(&ep_ptr->internal_infos, 0, sizeof(Ucs_Rm_EndPointInt_t));
79 ep_ptr->internal_infos.magic_number = (uint32_t)0x0BADC0DE;
80 Sub_Ctor(&ep_ptr->internal_infos.subject_obj, self->base_ptr->ucs_user_ptr);
81 /* Set the EndpointManagement instance */
82 ep_ptr->internal_infos.epm_inst = (Epm_Inst_t *)(void *)self;
87 /*! \brief Clears the internal information of the given endpoint object.
89 * Resetting the magic number of the given endpoint will enforce Its Re-Initialization.
91 * \param self Instance pointer
92 * \param ep_ptr Reference to the endpoint to be cleared.
94 void Epm_ClearIntInfos(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr)
99 ep_ptr->internal_infos.magic_number = 0x0U;
103 /*------------------------------------------------------------------------------------------------*/
105 /*------------------------------------------------------------------------------------------------*/
106 /*! \brief Add an observer to the Endpoint's subject.
107 * \param ep_ptr Reference to the endpoint instance
108 * \param obs_ptr Reference to the observer object
110 void Epm_AddObserver(Ucs_Rm_EndPoint_t * ep_ptr, CObserver * obs_ptr)
112 Sub_Ret_t ret_val = SUB_UNKNOWN_OBSERVER;
114 ret_val = Sub_AddObserver(&ep_ptr->internal_infos.subject_obj, obs_ptr);
115 if (ret_val == SUB_OK)
117 if ((ep_ptr != NULL) && (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE))
119 if ((ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT) && (ep_ptr->internal_infos.reference_cnt > 0U))
121 ep_ptr->internal_infos.reference_cnt++;
127 /*! \brief Removes an observer registered by Epm_AddObserver
128 * \param ep_ptr Reference to the endpoint instance
129 * \param obs_ptr Reference to the observer object
131 void Epm_DelObserver(Ucs_Rm_EndPoint_t * ep_ptr, CObserver * obs_ptr)
133 (void)Sub_RemoveObserver(&ep_ptr->internal_infos.subject_obj, obs_ptr);
136 /*! \brief Processes the construction of the given endpoint
137 * \param self Instance pointer
138 * \param ep_ptr reference to an endpoint
139 * \return Possible return values are
140 * - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed.
141 * - \c UCS_RET_SUCCESS the build process was set successfully
142 * - \c UCS_RET_ERR_PARAM NULL pointer detected in the parameter list
143 * - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set
145 Ucs_Return_t Epm_SetBuildProcess(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr)
147 Ucs_Return_t result = UCS_RET_ERR_PARAM;
149 if ((self != NULL) && (ep_ptr != NULL))
151 /* Process Endpoint construction by XRM */
152 result = Xrm_Process(Fac_GetXrm(self->fac_ptr, ep_ptr->node_obj_ptr->signature_ptr->node_address, &Epm_XrmResDebugCb, self->check_unmute_fptr),
153 ep_ptr->jobs_list_ptr, ep_ptr->internal_infos.connection_label,
154 (void *)ep_ptr, &Epm_XrmReportCb);
155 if (result == UCS_RET_SUCCESS)
157 if (ep_ptr->internal_infos.endpoint_state != UCS_RM_EP_BUILT)
159 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_XRMPROCESSING;
160 TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "XRM has been ordered to create following Endpoint: %X", 1U, ep_ptr));
164 TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been built", 1U, ep_ptr));
167 else if (result == UCS_RET_ERR_ALREADY_SET)
169 if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_IDLE)
171 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_BUILT;
172 TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been built", 1U, ep_ptr));
175 else if (result == UCS_RET_ERR_NOT_AVAILABLE)
177 /* Set the internal error */
178 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
179 ep_ptr->internal_infos.xrm_result.code = UCS_XRM_RES_ERR_BUILD;
180 ep_ptr->internal_infos.xrm_result.details.result_type = UCS_XRM_RESULT_TYPE_INT;
181 ep_ptr->internal_infos.xrm_result.details.int_result = result;
188 /*! \brief Processes the destruction of the given endpoint
189 * \param self Instance pointer
190 * \param ep_ptr reference to an endpoint
191 * \return Possible return values are
192 * - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed.
193 * - \c UCS_RET_SUCCESS the build process was set successfully
194 * - \c UCS_RET_ERR_PARAM At least one parameter is not correct, either NULL pointer in the param list or reference_cnt of the endpoint is NULL.
195 * - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set
196 * - \c UCS_RET_ERR_NOT_AVAILABLE the endpoint cannot be destroyed since its reference_cnt is greater than 1, i.e. it's in use.
197 * - \c UCS_RET_ERR_INVALID_SHADOW the endpoint cannot be destroyed since its reference_cnt is greater than 1, i.e. it's in use.
199 Ucs_Return_t Epm_SetDestroyProcess(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr)
201 Ucs_Return_t result = UCS_RET_ERR_PARAM;
202 bool can_be_destroyed = true;
204 if ((self != NULL) && (ep_ptr != NULL) )
206 if (UCS_RM_EP_SOURCE == ep_ptr->endpoint_type)
208 if (ep_ptr->internal_infos.reference_cnt == 0U)
210 can_be_destroyed = false;
211 result = UCS_RET_ERR_PARAM;
213 else if (ep_ptr->internal_infos.reference_cnt > 1U)
215 ep_ptr->internal_infos.reference_cnt--;
216 can_be_destroyed = false;
217 result = UCS_RET_ERR_INVALID_SHADOW;
221 if (can_be_destroyed)
223 result = Xrm_Destroy(Fac_GetXrmByJobList(self->fac_ptr, ep_ptr->jobs_list_ptr), ep_ptr->jobs_list_ptr);
224 if (result == UCS_RET_SUCCESS)
226 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_XRMPROCESSING;
227 TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "XRM has been ordered to destroy following Endpoint {%X}", 1U, ep_ptr));
229 else if (result == UCS_RET_ERR_ALREADY_SET)
231 if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT)
233 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
234 TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been destroyed", 1U, ep_ptr));
237 else if (result == UCS_RET_ERR_NOT_AVAILABLE)
239 if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT)
241 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
242 TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been destroyed", 1U, ep_ptr));
251 /*! \brief Returns the state (idle, processing or built) of the given endpoint.
252 * \param self Instance pointer.
253 * \param ep_ptr Reference to the endpoint to be looked for
254 * \return state of the endpoint.
256 Ucs_Rm_EndPointState_t Epm_GetState(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr)
260 return (ep_ptr != NULL) ? ep_ptr->internal_infos.endpoint_state:UCS_RM_EP_IDLE;
263 /*! \brief Forces EPM to reset the state of this endpoint.
264 * \param self Instance pointer.
265 * \param ep_ptr Reference to the endpoint to be looked for.
267 void Epm_ResetState(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr)
273 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
274 ep_ptr->internal_infos.xrm_result.code = UCS_XRM_RES_UNKNOWN;
278 /*! \brief Sets the connection label of the given endpoint.
279 * \param self Instance pointer.
280 * \param ep_ptr Reference to the endpoint to be looked for
281 * \param conn_label connection label to be set
283 void Epm_SetConnectionLabel(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr, uint16_t conn_label)
289 ep_ptr->internal_infos.connection_label = conn_label;
293 /*! \brief Returns the connection label of the given endpoint.
294 * \param self Instance pointer.
295 * \param ep_ptr Reference to the endpoint to be looked for
296 * \return connection label of the endpoint.
298 uint16_t Epm_GetConnectionLabel(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr)
302 return (ep_ptr != NULL) ? ep_ptr->internal_infos.connection_label:0U;
305 /*! \brief This function must be called when a device get invalid.
306 * \param self Reference to the MNS instance.
307 * \param destination_address MOST device address of the target.
309 void Epm_ReportInvalidDevice(CEndpointManagement *self, uint16_t destination_address)
311 if (MSG_ADDR_INIC != destination_address)
313 CRemoteSyncManagement * rsm_inst = Fac_FindRsm(self->fac_ptr, destination_address);
314 if (NULL != rsm_inst)
316 Rsm_ReportSyncLost(rsm_inst);
321 /*! \brief Whenever this function has been called, the EndpointManager has to inform his sub-modules that a shutdown occurred.
322 * This function forwards the Network "NotAvailable" information
323 * \param self Instance pointer.
325 void Epm_ReportShutDown(CEndpointManagement * self)
327 Fac_Foreach(self->fac_ptr, FAC_INST_RSM, &Epm_RsmReportSyncLost, NULL);
330 /*! \brief Function signature used for monitoring the XRM resources.
331 * \param resource_type The XRM resource type to be looked for
332 * \param resource_ptr Reference to the resource to be looked for
333 * \param resource_infos Resource information
334 * \param endpoint_inst_ptr Reference to the endpoint object that encapsulates the given resource.
335 * \param user_ptr User reference provided in \ref Ucs_InitData_t "Ucs_InitData_t::user_ptr"
337 void Epm_XrmResDebugCb (Ucs_Xrm_ResourceType_t resource_type, Ucs_Xrm_ResObject_t *resource_ptr,
338 Ucs_Xrm_ResourceInfos_t resource_infos, void *endpoint_inst_ptr, void *user_ptr)
340 Ucs_Rm_EndPoint_t * ep_ptr = (Ucs_Rm_EndPoint_t *)endpoint_inst_ptr;
343 CEndpointManagement * self = (CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst;
344 if (self->res_debugging_fptr != NULL)
346 self->res_debugging_fptr(resource_type, resource_ptr, resource_infos, ep_ptr, user_ptr);
351 /*------------------------------------------------------------------------------------------------*/
352 /* Private Methods */
353 /*------------------------------------------------------------------------------------------------*/
354 /*! \brief Reports "SyncLost" to the RSM instance returned.
355 * \param inst_type The instance type to be looked for.
356 * \param inst_ptr Reference to the instance to be looked for.
357 * \param ud_ptr Reference to the user data.
358 * \return false in order to retrieve the next instance of the given type, otherwise false.
360 static bool Epm_RsmReportSyncLost(Fac_Inst_t inst_type, void * inst_ptr, void *ud_ptr)
362 bool ret_val = false;
368 Rsm_ReportSyncLost((CRemoteSyncManagement *)inst_ptr);
379 /*------------------------------------------------------------------------------------------------*/
380 /* Callback Functions */
381 /*------------------------------------------------------------------------------------------------*/
382 /*! \brief XRM report callback function.
383 * \param node_address The node address from which the results come
384 * \param connection_label Returned MOST network connection label
385 * \param result Result of the job
386 * \param user_arg Reference to the user argument
388 static void Epm_XrmReportCb(uint16_t node_address, uint16_t connection_label, Ucs_Xrm_Result_t result, void * user_arg)
390 Ucs_Rm_EndPoint_t * ep_ptr = (Ucs_Rm_EndPoint_t *)user_arg;
391 uint8_t handle_not_found = 0x32U;
392 uint8_t error_id = 2U;
394 MISC_UNUSED (node_address);
398 ep_ptr->internal_infos.xrm_result = result;
401 case UCS_XRM_RES_SUCCESS_BUILD:
402 ep_ptr->internal_infos.connection_label = connection_label;
403 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_BUILT;
404 if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE)
406 ep_ptr->internal_infos.reference_cnt++;
408 TR_INFO((((CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst)->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has been successfully built", 1U, ep_ptr));
411 case UCS_XRM_RES_SUCCESS_DESTROY:
412 ep_ptr->internal_infos.connection_label = 0xFFFFU;
413 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
414 if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE)
416 if (ep_ptr->internal_infos.reference_cnt > 0U)
418 ep_ptr->internal_infos.reference_cnt--;
421 TR_INFO((((CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst)->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has been successfully destroyed", 1U, ep_ptr));
424 case UCS_XRM_RES_RC_AUTO_DESTROYED:
425 TR_ERROR((((CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst)->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has been auto destroyed.", 1U, ep_ptr));
426 ep_ptr->internal_infos.connection_label = 0xFFFFU;
427 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
428 if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE)
430 ep_ptr->internal_infos.reference_cnt = 0U;
432 if(Sub_GetNumObservers(&ep_ptr->internal_infos.subject_obj) > 0U)
434 Sub_Notify(&ep_ptr->internal_infos.subject_obj, (void *)ep_ptr);
438 case UCS_XRM_RES_ERR_CONFIG:
439 case UCS_XRM_RES_ERR_SYNC:
440 case UCS_XRM_RES_ERR_BUILD:
441 ep_ptr->internal_infos.connection_label = 0xFFFFU;
442 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
443 TR_ERROR((((CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst)->base_ptr->ucs_user_ptr, "[EPM]", "Building endpoint {%X} failed. Error_Code: 0x%02X", 2U, ep_ptr, result.code));
446 case UCS_XRM_RES_ERR_DESTROY:
447 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
448 if (ep_ptr->internal_infos.xrm_result.details.result_type == UCS_XRM_RESULT_TYPE_TGT)
450 if ((ep_ptr->internal_infos.xrm_result.details.inic_result.code == UCS_RES_ERR_CONFIGURATION) &&
451 (ep_ptr->internal_infos.xrm_result.details.inic_result.info_ptr != NULL) &&
452 (ep_ptr->internal_infos.xrm_result.details.inic_result.info_size > 2U))
454 if (ep_ptr->internal_infos.xrm_result.details.inic_result.info_ptr[error_id] == handle_not_found)
456 ep_ptr->internal_infos.xrm_result.code = UCS_XRM_RES_SUCCESS_DESTROY;
460 if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE)
462 ep_ptr->internal_infos.reference_cnt = 0U;
464 TR_ERROR((((CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst)->base_ptr->ucs_user_ptr, "[EPM]", "Destroying endpoint {%X} failed. Error_Code: 0x%02X", 2U, ep_ptr, result.code));
467 case UCS_XRM_RES_ERR_INV_LIST:
468 TR_ERROR((((CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst)->base_ptr->ucs_user_ptr, "[EPM]", "Request of invalid lists on endpoint {%X} failed.", 1U, ep_ptr));
469 if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT)
471 ep_ptr->internal_infos.connection_label = 0xFFFFU;
472 ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE;
473 if(Sub_GetNumObservers(&ep_ptr->internal_infos.subject_obj) > 0U)
475 Sub_Notify(&ep_ptr->internal_infos.subject_obj, (void *)ep_ptr);
481 TR_ERROR((((CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst)->base_ptr->ucs_user_ptr, "[EPM]", "Processing endpoint {%X} failed. Unknown Error_Code: 0x%02X", 2U, ep_ptr, result.code));
492 /*------------------------------------------------------------------------------------------------*/
494 /*------------------------------------------------------------------------------------------------*/