/*------------------------------------------------------------------------------------------------*/ /* 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 . */ /* */ /* You may also obtain this software under a propriety license from Microchip. */ /* Please contact Microchip for further information. */ /*------------------------------------------------------------------------------------------------*/ /*! * \file * \brief Implementation of the Network Management. * * \cond UCS_INTERNAL_DOC * \addtogroup G_NET * @{ */ /*------------------------------------------------------------------------------------------------*/ /* Includes */ /*------------------------------------------------------------------------------------------------*/ #include "ucs_net.h" #include "ucs_misc.h" #include "ucs_trace.h" /*------------------------------------------------------------------------------------------------*/ /* Service parameters */ /*------------------------------------------------------------------------------------------------*/ /*! Priority of the NET service used by scheduler */ static const uint8_t NET_SRV_PRIO = 251U; /* parasoft-suppress MISRA2004-8_7 "Value shall be part of the module, not part of a function." */ /*! \brief Event to trigger notification of MOST Network Status */ static const Srv_Event_t NET_EVENT_NOTIFY_NW_STATUS = 1U; /*! \brief Event to trigger notification of MOST Network Configuration */ static const Srv_Event_t NET_EVENT_NOTIFY_NW_CONFIG = 2U; /*------------------------------------------------------------------------------------------------*/ /* Internal constants */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Default value used for INIC sender handles */ static const uint16_t NET_DEFAULT_SENDER_HANDLE = 0x0001U; /* parasoft-suppress MISRA2004-8_7 "Value shall be part of the module, not part of a function." */ /*! \brief Initialization timeout in milliseconds (t = 7s) */ static const uint16_t NET_PBW_TIMEOUT = 7000U; /* parasoft-suppress MISRA2004-8_7 "Value shall be part of the module, not part of a function." */ /*------------------------------------------------------------------------------------------------*/ /* Internal prototypes */ /*------------------------------------------------------------------------------------------------*/ static void Net_Service(void *self); static void Net_UpdateNetworkStatus(void *self, void *data_ptr); static void Net_UpdateNetworkConfiguration(void *self, void *data_ptr); /*------------------------------------------------------------------------------------------------*/ /* Implementation of class CNetworkManagement */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Constructor of the Network Management class. * \param self Instance pointer * \param init_ptr Reference to the initialization data */ void Net_Ctor(CNetworkManagement *self, Net_InitData_t *init_ptr) { MISC_MEM_SET(self, 0, sizeof(*self)); self->base_ptr = init_ptr->base_ptr; self->inic_ptr = init_ptr->inic_ptr; Obs_Ctor(&self->network_status.observer, self, &Net_UpdateNetworkStatus); Inic_AddObsrvNwStatus(self->inic_ptr, &self->network_status.observer); self->network_status.param.change_mask = 0xFFFFU; /* Used for initial notification! */ Sub_Ctor(&self->network_status.pre_subject, self->base_ptr->ucs_user_ptr); Sub_Ctor(&self->network_status.subject, self->base_ptr->ucs_user_ptr); Obs_Ctor(&self->network_configuration.observer, self, &Net_UpdateNetworkConfiguration); Inic_AddObsvrNwConfig(self->inic_ptr, &self->network_configuration.observer); self->network_configuration.param.change_mask = 0xFFFFU; /* Used for initial notification! */ Sub_Ctor(&self->network_configuration.pre_subject, self->base_ptr->ucs_user_ptr); Sub_Ctor(&self->network_configuration.subject, self->base_ptr->ucs_user_ptr); Srv_Ctor(&self->net_srv, NET_SRV_PRIO, self, &Net_Service); /* Initialize Network Management service */ (void)Scd_AddService(&self->base_ptr->scd, &self->net_srv); /* Add NET service to scheduler */ } /*! \brief Service function of the network management. * \param self Instance pointer */ static void Net_Service(void *self) { CNetworkManagement *self_ = (CNetworkManagement *)self; Srv_Event_t event_mask; Srv_GetEvent(&self_->net_srv, &event_mask); /* Notification of MOST Network Status triggered? */ if((event_mask & NET_EVENT_NOTIFY_NW_STATUS) == NET_EVENT_NOTIFY_NW_STATUS) { Srv_ClearEvent(&self_->net_srv, NET_EVENT_NOTIFY_NW_STATUS); self_->network_status.param.change_mask = 0xFFFFU; Sub_Notify(&self_->network_status.pre_subject, &self_->network_status.param); self_->network_status.param.change_mask = 0U; (void)Sub_SwitchObservers(&self_->network_status.subject, &self_->network_status.pre_subject); } /* Notification of MOST Network Configuration triggered? */ if((event_mask & NET_EVENT_NOTIFY_NW_CONFIG) == NET_EVENT_NOTIFY_NW_CONFIG) { Srv_ClearEvent(&self_->net_srv, NET_EVENT_NOTIFY_NW_CONFIG); self_->network_configuration.param.change_mask = 0xFFFFU; Sub_Notify(&self_->network_configuration.pre_subject, &self_->network_configuration.param); self_->network_configuration.param.change_mask = 0U; (void)Sub_SwitchObservers(&self_->network_configuration.subject, &self_->network_configuration.pre_subject); } } /*! \brief Adds an observer which is called if the network status has been changed. * \param self Instance pointer * \param obs_ptr Reference to an observer */ void Net_AddObserverNetworkStatus(CNetworkManagement *self, CMaskedObserver *obs_ptr) { (void)Msub_AddObserver(&self->network_status.pre_subject, obs_ptr); Srv_SetEvent(&self->net_srv, NET_EVENT_NOTIFY_NW_STATUS); } /*! \brief Removes an observer registered by Net_AddObserverNetworkStatus(). * \param self Instance pointer * \param obs_ptr Reference to observer to be removed */ void Net_DelObserverNetworkStatus(CNetworkManagement *self, CMaskedObserver *obs_ptr) { (void)Msub_RemoveObserver(&self->network_status.pre_subject, obs_ptr); (void)Msub_RemoveObserver(&self->network_status.subject, obs_ptr); } /*! \brief Adds an observer which is called if the network configuration has been changed. * \param self Instance pointer * \param obs_ptr Reference to an observer */ void Net_AddObserverNetworkConfig(CNetworkManagement *self, CMaskedObserver *obs_ptr) { (void)Msub_AddObserver(&self->network_configuration.pre_subject, obs_ptr); Srv_SetEvent(&self->net_srv, NET_EVENT_NOTIFY_NW_CONFIG); } /*! \brief Removes an observer registered by Net_AddObserverNetworkConfig(). * \param self Instance pointer * \param obs_ptr Reference to observer to be removed */ void Net_DelObserverNetworkConfig(CNetworkManagement *self, CMaskedObserver *obs_ptr) { (void)Msub_RemoveObserver(&self->network_configuration.pre_subject, obs_ptr); (void)Msub_RemoveObserver(&self->network_configuration.subject, obs_ptr); } /*! \brief Observer callback used for the MOST Network Status * \param self Instance pointer * \param data_ptr Reference to the data structure */ static void Net_UpdateNetworkStatus(void *self, void *data_ptr) { Inic_StdResult_t *data_ptr_ = (Inic_StdResult_t *)data_ptr; if(data_ptr_->result.code == UCS_RES_SUCCESS) { CNetworkManagement *self_ = (CNetworkManagement *)self; Inic_NetworkStatus_t result = *((Inic_NetworkStatus_t *)data_ptr_->data_info); /* Check for changes */ if(result.events != 0U) /* Notify only if at least one event flag is set */ { self_->network_status.param.change_mask |= 0x0001U; } if(self_->network_status.param.availability != result.availability) { self_->network_status.param.change_mask |= 0x0002U; } if(self_->network_status.param.avail_info != result.avail_info) { self_->network_status.param.change_mask |= 0x0004U; } if(self_->network_status.param.avail_trans_cause != result.avail_trans_cause) { self_->network_status.param.change_mask |= 0x0008U; } if(self_->network_status.param.node_address != result.node_address) { self_->network_status.param.change_mask |= 0x0010U; } if(self_->network_status.param.node_position != result.node_position) { self_->network_status.param.change_mask |= 0x0020U; } if(self_->network_status.param.max_position != result.max_position) { self_->network_status.param.change_mask |= 0x0040U; } if(self_->network_status.param.packet_bw != result.packet_bw) { self_->network_status.param.change_mask |= 0x0080U; } /* Update MOST Network Status parameters */ self_->network_status.param.events = result.events; self_->network_status.param.availability = result.availability; self_->network_status.param.avail_info = result.avail_info; self_->network_status.param.avail_trans_cause = result.avail_trans_cause; self_->network_status.param.node_address = result.node_address; self_->network_status.param.node_position = result.node_position; self_->network_status.param.max_position = result.max_position; self_->network_status.param.packet_bw = result.packet_bw; /* Notify observer? */ Msub_Notify(&self_->network_status.subject, &self_->network_status.param, (uint32_t)self_->network_status.param.change_mask); /* Clear change-mask */ self_->network_status.param.change_mask = 0U; } } /*! \brief Observer callback used for the MOST Network Configuration * \param self Instance pointer * \param data_ptr Reference to the data structure */ static void Net_UpdateNetworkConfiguration(void *self, void *data_ptr) { Inic_StdResult_t *data_ptr_ = (Inic_StdResult_t *)data_ptr; if(data_ptr_->result.code == UCS_RES_SUCCESS) { CNetworkManagement *self_ = (CNetworkManagement *)self; Inic_NetworkConfig_t result = *((Inic_NetworkConfig_t *)data_ptr_->data_info); /* Check for changes */ if(self_->network_configuration.param.node_address != result.node_address) { self_->network_configuration.param.change_mask |= 0x0001U; } if(self_->network_configuration.param.group_address != result.group_address) { self_->network_configuration.param.change_mask |= 0x0002U; } if(self_->network_configuration.param.llrbc != result.llrbc) { self_->network_configuration.param.change_mask |= 0x0004U; } /* Update MOST Network Configuration parameters */ self_->network_configuration.param.node_address = result.node_address; self_->network_configuration.param.group_address = result.group_address; self_->network_configuration.param.llrbc = result.llrbc; /* Notify observer? */ Msub_Notify(&self_->network_configuration.subject, &self_->network_configuration.param, (uint32_t)self_->network_configuration.param.change_mask); /* Clear change-mask */ self_->network_configuration.param.change_mask = 0U; } } /*! \brief Checks if the given address matches with the own node address, node position or group address. * \param self Instance pointer * \param address Address to be checked * \return Possible return values are shown in the table below. * Value | Description * --------------------- | ------------------------------------------------------------- * NET_IS_OWN_ADDR_NODE | Is own node position address or own logical node address * NET_IS_OWN_ADDR_GROUP | Is own group address * NET_IS_OWN_ADDR_NONE | Is foreign address */ Net_IsOwnAddrResult_t Net_IsOwnAddress(CNetworkManagement *self, uint16_t address) { Net_IsOwnAddrResult_t ret_val; if((self->network_status.param.node_address == address) || (((uint16_t)self->network_status.param.node_position + (uint16_t)0x400) == address)) { ret_val = NET_IS_OWN_ADDR_NODE; } else if(self->network_configuration.param.group_address == address) { ret_val = NET_IS_OWN_ADDR_GROUP; } else { ret_val = NET_IS_OWN_ADDR_NONE; } return ret_val; } /*! * @} * \endcond */ /*------------------------------------------------------------------------------------------------*/ /* End of file */ /*------------------------------------------------------------------------------------------------*/