diff options
Diffstat (limited to 'ucs2-lib/src/ucs_epm.c')
-rw-r--r-- | ucs2-lib/src/ucs_epm.c | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/ucs2-lib/src/ucs_epm.c b/ucs2-lib/src/ucs_epm.c new file mode 100644 index 0000000..adc5aab --- /dev/null +++ b/ucs2-lib/src/ucs_epm.c @@ -0,0 +1,495 @@ +/*------------------------------------------------------------------------------------------------*/ +/* 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 EndPoint Management. + * + * \cond UCS_INTERNAL_DOC + * \addtogroup G_EPM + * @{ + */ + +/*------------------------------------------------------------------------------------------------*/ +/* Includes */ +/*------------------------------------------------------------------------------------------------*/ +#include "ucs_epm.h" +#include "ucs_misc.h" + +/*------------------------------------------------------------------------------------------------*/ +/* Internal prototypes */ +/*------------------------------------------------------------------------------------------------*/ +static void Epm_XrmReportCb (uint16_t node_address, uint16_t connection_label, Ucs_Xrm_Result_t result, void * user_arg); +static bool Epm_RsmReportSyncLost (Fac_Inst_t inst_type, void * inst_ptr, void *ud_ptr); + +/*------------------------------------------------------------------------------------------------*/ +/* Implementation of class CEndpointManagement */ +/*------------------------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------------------------*/ +/* Initialization Methods */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief Constructor of the Remote Sync Manager class. + * \param self Instance pointer + * \param init_ptr init data_ptr + */ +void Epm_Ctor(CEndpointManagement *self, Epm_InitData_t *init_ptr) +{ + MISC_MEM_SET(self, 0, sizeof(CEndpointManagement)); + + /* Init all instances */ + self->fac_ptr = init_ptr->fac_ptr; + self->base_ptr = init_ptr->base_ptr; + self->res_debugging_fptr = init_ptr->res_debugging_fptr; + self->check_unmute_fptr = init_ptr->check_unmute_fptr; +} + +/*! \brief Initializes the internal information of the given endpoint object. + * + * Initialization is performed only if the magic number is not set. + * + * \param self Instance pointer + * \param ep_ptr Reference to the endpoint to be looked for + */ +void Epm_InitInternalInfos(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr) +{ + if ((self != NULL) && (ep_ptr != NULL)) + { + if (ep_ptr->internal_infos.magic_number != (uint32_t)0x0BADC0DE) + { + MISC_MEM_SET(&ep_ptr->internal_infos, 0, sizeof(Ucs_Rm_EndPointInt_t)); + + ep_ptr->internal_infos.magic_number = (uint32_t)0x0BADC0DE; + Sub_Ctor(&ep_ptr->internal_infos.subject_obj, self->base_ptr->ucs_user_ptr); + /* Set the EndpointManagement instance */ + ep_ptr->internal_infos.epm_inst = (Epm_Inst_t *)(void *)self; + } + } +} + +/*! \brief Clears the internal information of the given endpoint object. + * + * Resetting the magic number of the given endpoint will enforce Its Re-Initialization. + * + * \param self Instance pointer + * \param ep_ptr Reference to the endpoint to be cleared. + */ +void Epm_ClearIntInfos(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr) +{ + MISC_UNUSED (self); + if (ep_ptr != NULL) + { + ep_ptr->internal_infos.magic_number = 0x0U; + } +} + +/*------------------------------------------------------------------------------------------------*/ +/* Service */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief Add an observer to the Endpoint's subject. + * \param ep_ptr Reference to the endpoint instance + * \param obs_ptr Reference to the observer object + */ +void Epm_AddObserver(Ucs_Rm_EndPoint_t * ep_ptr, CObserver * obs_ptr) +{ + Sub_Ret_t ret_val = SUB_UNKNOWN_OBSERVER; + + ret_val = Sub_AddObserver(&ep_ptr->internal_infos.subject_obj, obs_ptr); + if (ret_val == SUB_OK) + { + if ((ep_ptr != NULL) && (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE)) + { + if ((ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT) && (ep_ptr->internal_infos.reference_cnt > 0U)) + { + ep_ptr->internal_infos.reference_cnt++; + } + } + } +} + +/*! \brief Removes an observer registered by Epm_AddObserver + * \param ep_ptr Reference to the endpoint instance + * \param obs_ptr Reference to the observer object + */ +void Epm_DelObserver(Ucs_Rm_EndPoint_t * ep_ptr, CObserver * obs_ptr) +{ + (void)Sub_RemoveObserver(&ep_ptr->internal_infos.subject_obj, obs_ptr); +} + +/*! \brief Processes the construction of the given endpoint + * \param self Instance pointer + * \param ep_ptr reference to an endpoint + * \return Possible return values are + * - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed. + * - \c UCS_RET_SUCCESS the build process was set successfully + * - \c UCS_RET_ERR_PARAM NULL pointer detected in the parameter list + * - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set + */ +Ucs_Return_t Epm_SetBuildProcess(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr) +{ + Ucs_Return_t result = UCS_RET_ERR_PARAM; + + if ((self != NULL) && (ep_ptr != NULL)) + { + /* Process Endpoint construction by XRM */ + result = Xrm_Process(Fac_GetXrm(self->fac_ptr, ep_ptr->node_obj_ptr->signature_ptr->node_address, &Epm_XrmResDebugCb, self->check_unmute_fptr), + ep_ptr->jobs_list_ptr, ep_ptr->internal_infos.connection_label, + (void *)ep_ptr, &Epm_XrmReportCb); + if (result == UCS_RET_SUCCESS) + { + if (ep_ptr->internal_infos.endpoint_state != UCS_RM_EP_BUILT) + { + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_XRMPROCESSING; + TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "XRM has been ordered to create following Endpoint: %X", 1U, ep_ptr)); + } + else + { + TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been built", 1U, ep_ptr)); + } + } + else if (result == UCS_RET_ERR_ALREADY_SET) + { + if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_IDLE) + { + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_BUILT; + TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been built", 1U, ep_ptr)); + } + } + else if (result == UCS_RET_ERR_NOT_AVAILABLE) + { + /* Set the internal error */ + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + ep_ptr->internal_infos.xrm_result.code = UCS_XRM_RES_ERR_BUILD; + ep_ptr->internal_infos.xrm_result.details.result_type = UCS_XRM_RESULT_TYPE_INT; + ep_ptr->internal_infos.xrm_result.details.int_result = result; + } + } + + return result; +} + +/*! \brief Processes the destruction of the given endpoint + * \param self Instance pointer + * \param ep_ptr reference to an endpoint + * \return Possible return values are + * - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed. + * - \c UCS_RET_SUCCESS the build process was set successfully + * - \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. + * - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set + * - \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. + * - \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. + */ +Ucs_Return_t Epm_SetDestroyProcess(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr) +{ + Ucs_Return_t result = UCS_RET_ERR_PARAM; + bool can_be_destroyed = true; + + if ((self != NULL) && (ep_ptr != NULL) ) + { + if (UCS_RM_EP_SOURCE == ep_ptr->endpoint_type) + { + if (ep_ptr->internal_infos.reference_cnt == 0U) + { + can_be_destroyed = false; + result = UCS_RET_ERR_PARAM; + } + else if (ep_ptr->internal_infos.reference_cnt > 1U) + { + ep_ptr->internal_infos.reference_cnt--; + can_be_destroyed = false; + result = UCS_RET_ERR_INVALID_SHADOW; + } + } + + if (can_be_destroyed) + { + result = Xrm_Destroy(Fac_GetXrmByJobList(self->fac_ptr, ep_ptr->jobs_list_ptr), ep_ptr->jobs_list_ptr); + if (result == UCS_RET_SUCCESS) + { + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_XRMPROCESSING; + TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "XRM has been ordered to destroy following Endpoint {%X}", 1U, ep_ptr)); + } + else if (result == UCS_RET_ERR_ALREADY_SET) + { + if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT) + { + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been destroyed", 1U, ep_ptr)); + } + } + else if (result == UCS_RET_ERR_NOT_AVAILABLE) + { + if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT) + { + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + TR_INFO((self->base_ptr->ucs_user_ptr, "[EPM]", "Following Endpoint {%X} has already been destroyed", 1U, ep_ptr)); + } + } + } + } + + return result; +} + +/*! \brief Returns the state (idle, processing or built) of the given endpoint. + * \param self Instance pointer. + * \param ep_ptr Reference to the endpoint to be looked for + * \return state of the endpoint. + */ +Ucs_Rm_EndPointState_t Epm_GetState(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr) +{ + MISC_UNUSED (self); + + return (ep_ptr != NULL) ? ep_ptr->internal_infos.endpoint_state:UCS_RM_EP_IDLE; +} + +/*! \brief Forces EPM to reset the state of this endpoint. + * \param self Instance pointer. + * \param ep_ptr Reference to the endpoint to be looked for. + */ +void Epm_ResetState(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr) +{ + MISC_UNUSED (self); + + if (ep_ptr != NULL) + { + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + ep_ptr->internal_infos.xrm_result.code = UCS_XRM_RES_UNKNOWN; + } +} + +/*! \brief Sets the connection label of the given endpoint. + * \param self Instance pointer. + * \param ep_ptr Reference to the endpoint to be looked for + * \param conn_label connection label to be set + */ +void Epm_SetConnectionLabel(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr, uint16_t conn_label) +{ + MISC_UNUSED (self); + + if (ep_ptr != NULL) + { + ep_ptr->internal_infos.connection_label = conn_label; + } +} + +/*! \brief Returns the connection label of the given endpoint. + * \param self Instance pointer. + * \param ep_ptr Reference to the endpoint to be looked for + * \return connection label of the endpoint. + */ +uint16_t Epm_GetConnectionLabel(CEndpointManagement * self, Ucs_Rm_EndPoint_t * ep_ptr) +{ + MISC_UNUSED (self); + + return (ep_ptr != NULL) ? ep_ptr->internal_infos.connection_label:0U; +} + +/*! \brief This function must be called when a device get invalid. + * \param self Reference to the MNS instance. + * \param destination_address MOST device address of the target. + */ +void Epm_ReportInvalidDevice(CEndpointManagement *self, uint16_t destination_address) +{ + if (MSG_ADDR_INIC != destination_address) + { + CRemoteSyncManagement * rsm_inst = Fac_FindRsm(self->fac_ptr, destination_address); + if (NULL != rsm_inst) + { + Rsm_ReportSyncLost(rsm_inst); + } + } +} + +/*! \brief Whenever this function has been called, the EndpointManager has to inform his sub-modules that a shutdown occurred. + * This function forwards the Network "NotAvailable" information + * \param self Instance pointer. + */ +void Epm_ReportShutDown(CEndpointManagement * self) +{ + Fac_Foreach(self->fac_ptr, FAC_INST_RSM, &Epm_RsmReportSyncLost, NULL); +} + +/*! \brief Function signature used for monitoring the XRM resources. + * \param resource_type The XRM resource type to be looked for + * \param resource_ptr Reference to the resource to be looked for + * \param resource_infos Resource information + * \param endpoint_inst_ptr Reference to the endpoint object that encapsulates the given resource. + * \param user_ptr User reference provided in \ref Ucs_InitData_t "Ucs_InitData_t::user_ptr" + */ +void Epm_XrmResDebugCb (Ucs_Xrm_ResourceType_t resource_type, Ucs_Xrm_ResObject_t *resource_ptr, + Ucs_Xrm_ResourceInfos_t resource_infos, void *endpoint_inst_ptr, void *user_ptr) +{ + Ucs_Rm_EndPoint_t * ep_ptr = (Ucs_Rm_EndPoint_t *)endpoint_inst_ptr; + if (ep_ptr != NULL) + { + CEndpointManagement * self = (CEndpointManagement *)(void *)ep_ptr->internal_infos.epm_inst; + if (self->res_debugging_fptr != NULL) + { + self->res_debugging_fptr(resource_type, resource_ptr, resource_infos, ep_ptr, user_ptr); + } + } +} + +/*------------------------------------------------------------------------------------------------*/ +/* Private Methods */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief Reports "SyncLost" to the RSM instance returned. + * \param inst_type The instance type to be looked for. + * \param inst_ptr Reference to the instance to be looked for. + * \param ud_ptr Reference to the user data. + * \return false in order to retrieve the next instance of the given type, otherwise false. + */ +static bool Epm_RsmReportSyncLost(Fac_Inst_t inst_type, void * inst_ptr, void *ud_ptr) +{ + bool ret_val = false; + MISC_UNUSED(ud_ptr); + + switch (inst_type) + { + case FAC_INST_RSM: + Rsm_ReportSyncLost((CRemoteSyncManagement *)inst_ptr); + break; + + default: + ret_val = true; + break; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------------------------*/ +/* Callback Functions */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief XRM report callback function. + * \param node_address The node address from which the results come + * \param connection_label Returned MOST network connection label + * \param result Result of the job + * \param user_arg Reference to the user argument + */ +static void Epm_XrmReportCb(uint16_t node_address, uint16_t connection_label, Ucs_Xrm_Result_t result, void * user_arg) +{ + Ucs_Rm_EndPoint_t * ep_ptr = (Ucs_Rm_EndPoint_t *)user_arg; + uint8_t handle_not_found = 0x32U; + uint8_t error_id = 2U; + + MISC_UNUSED (node_address); + + if (ep_ptr != NULL) + { + ep_ptr->internal_infos.xrm_result = result; + switch (result.code) + { + case UCS_XRM_RES_SUCCESS_BUILD: + ep_ptr->internal_infos.connection_label = connection_label; + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_BUILT; + if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE) + { + ep_ptr->internal_infos.reference_cnt++; + } + 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)); + break; + + case UCS_XRM_RES_SUCCESS_DESTROY: + ep_ptr->internal_infos.connection_label = 0xFFFFU; + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE) + { + if (ep_ptr->internal_infos.reference_cnt > 0U) + { + ep_ptr->internal_infos.reference_cnt--; + } + } + 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)); + break; + + case UCS_XRM_RES_RC_AUTO_DESTROYED: + 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)); + ep_ptr->internal_infos.connection_label = 0xFFFFU; + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE) + { + ep_ptr->internal_infos.reference_cnt = 0U; + } + if(Sub_GetNumObservers(&ep_ptr->internal_infos.subject_obj) > 0U) + { + Sub_Notify(&ep_ptr->internal_infos.subject_obj, (void *)ep_ptr); + } + break; + + case UCS_XRM_RES_ERR_CONFIG: + case UCS_XRM_RES_ERR_SYNC: + case UCS_XRM_RES_ERR_BUILD: + ep_ptr->internal_infos.connection_label = 0xFFFFU; + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + 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)); + break; + + case UCS_XRM_RES_ERR_DESTROY: + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + if (ep_ptr->internal_infos.xrm_result.details.result_type == UCS_XRM_RESULT_TYPE_TGT) + { + if ((ep_ptr->internal_infos.xrm_result.details.inic_result.code == UCS_RES_ERR_CONFIGURATION) && + (ep_ptr->internal_infos.xrm_result.details.inic_result.info_ptr != NULL) && + (ep_ptr->internal_infos.xrm_result.details.inic_result.info_size > 2U)) + { + if (ep_ptr->internal_infos.xrm_result.details.inic_result.info_ptr[error_id] == handle_not_found) + { + ep_ptr->internal_infos.xrm_result.code = UCS_XRM_RES_SUCCESS_DESTROY; + } + } + } + if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE) + { + ep_ptr->internal_infos.reference_cnt = 0U; + } + 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)); + break; + + case UCS_XRM_RES_ERR_INV_LIST: + 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)); + if (ep_ptr->internal_infos.endpoint_state == UCS_RM_EP_BUILT) + { + ep_ptr->internal_infos.connection_label = 0xFFFFU; + ep_ptr->internal_infos.endpoint_state = UCS_RM_EP_IDLE; + if(Sub_GetNumObservers(&ep_ptr->internal_infos.subject_obj) > 0U) + { + Sub_Notify(&ep_ptr->internal_infos.subject_obj, (void *)ep_ptr); + } + } + break; + + default: + 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)); + break; + } + } +} + +/*! + * @} + * \endcond + */ + +/*------------------------------------------------------------------------------------------------*/ +/* End of file */ +/*------------------------------------------------------------------------------------------------*/ + |