Initial Commit
[apps/agl-service-unicens.git] / ucs2-lib / src / ucs_epm.c
diff --git a/ucs2-lib/src/ucs_epm.c b/ucs2-lib/src/ucs_epm.c
new file mode 100644 (file)
index 0000000..adc5aab
--- /dev/null
@@ -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                                                                                    */
+/*------------------------------------------------------------------------------------------------*/
+