diff options
author | Fulup Ar Foll <fulup@iot.bzh> | 2017-05-26 18:45:56 +0200 |
---|---|---|
committer | Fulup Ar Foll <fulup@iot.bzh> | 2017-05-26 18:45:56 +0200 |
commit | d2e42029ec04c3f224580f8007cdfbbfe0fc47a6 (patch) | |
tree | ad2ccf167cf7997c84191d41e6ba55cb2efd6bed /ucs2-lib/src/ucs_exc.c | |
parent | 18e393e1443fd4c38b34979888fb55d30448cf31 (diff) |
Initial Commit
Diffstat (limited to 'ucs2-lib/src/ucs_exc.c')
-rw-r--r-- | ucs2-lib/src/ucs_exc.c | 1711 |
1 files changed, 1711 insertions, 0 deletions
diff --git a/ucs2-lib/src/ucs_exc.c b/ucs2-lib/src/ucs_exc.c new file mode 100644 index 0000000..5f5b5db --- /dev/null +++ b/ucs2-lib/src/ucs_exc.c @@ -0,0 +1,1711 @@ +/*------------------------------------------------------------------------------------------------*/ +/* 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 FBlock ExtendedNetworkControl + * \details Contains the housekeeping functions of INIC management + * + * \cond UCS_INTERNAL_DOC + * \addtogroup G_EXC + * @{ + */ + +/*------------------------------------------------------------------------------------------------*/ +/* Includes */ +/*------------------------------------------------------------------------------------------------*/ +#include "ucs_misc.h" +#include "ucs_ret_pb.h" +#include "ucs_exc.h" + + + +/*------------------------------------------------------------------------------------------------*/ +/* Internal definitions */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief Bitmask for API method Exc_PhyTestResult_Get() used by API locking manager */ +#define EXC_API_PHY_LAY_TEST_RESULT 0x01U +/*! \brief Bitmask for API method Exc_MemSessionOpen_Sr() used by API locking manager */ +#define EXC_API_MEM_SESSION_OPEN 0x02U +/*! \brief Bitmask for API method Exc_MemSessionClose_Sr() used by API locking manager */ +#define EXC_API_MEM_SESSION_CLOSE 0x04U +/*! \brief Bitmask for API method Exc_MemoryRead_Sr() used by API locking manager */ +#define EXC_API_MEM_READ 0x08U +/*! \brief Bitmask for API method Exc_MemoryWrite_Sr() used by API locking manager */ +#define EXC_API_MEM_WRITE 0x10U + +/*! \brief max. number of elements used in MemoryWrite and MemoryWrite messages */ +#define MAX_UNIT_LEN 18U + +/*! \brief length of signature (V1) */ +#define EXC_SIGNATURE_LEN_V1 26U + + +/*------------------------------------------------------------------------------------------------*/ +/* Internal prototypes */ +/*------------------------------------------------------------------------------------------------*/ +static void Exc_DecodeMsg(CExc *self, Msg_MostTel_t *msg_rx_ptr); +static void Exc_EnablePort_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_EnablePort_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_Hello_Status(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_Hello_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_Welcome_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_Welcome_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_Signature_Status(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_Signature_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_DeviceInit_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_CableLinkDiag_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_CableLinkDiag_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_NwPhyTest_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_NwPhyTestResult_Status(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_NwPhyTestResult_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_BC_Diag_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_BC_Diag_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_BC_EnableTx_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_BC_EnableTx_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemoryRead_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemoryRead_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemoryWrite_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemoryWrite_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemSessionOpen_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemSessionOpen_Error(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemSessionClose_Result(void *self, Msg_MostTel_t *msg_ptr); +static void Exc_MemSessionClose_Error(void *self, Msg_MostTel_t *msg_ptr); + +static void Exc_HandleApiTimeout(void *self, void *method_mask_ptr); + +static Ucs_StdResult_t Exc_TranslateError(CExc *self, uint8_t error_data[], uint8_t error_size); +static void Exc_Read_Signature(Ucs_Signature_t *dest, uint8_t source[]); + + +/*------------------------------------------------------------------------------------------------*/ +/* Internal constants */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief List of all EXC messages */ +static const Dec_FktOpIsh_t exc_handler[] = /* parasoft-suppress MISRA2004-8_7 "Value shall be part of the module, not part of a function." */ +{ + { DEC_FKTOP(EXC_FID_HELLO, UCS_OP_STATUS), Exc_Hello_Status }, + { DEC_FKTOP(EXC_FID_HELLO, UCS_OP_ERROR), Exc_Hello_Error }, + { DEC_FKTOP(EXC_FID_WELCOME, UCS_OP_RESULT), Exc_Welcome_Result }, + { DEC_FKTOP(EXC_FID_WELCOME, UCS_OP_ERROR), Exc_Welcome_Error }, + { DEC_FKTOP(EXC_FID_SIGNATURE, UCS_OP_STATUS), Exc_Signature_Status }, + { DEC_FKTOP(EXC_FID_SIGNATURE, UCS_OP_ERROR), Exc_Signature_Error }, + { DEC_FKTOP(EXC_FID_DEVICE_INIT, UCS_OP_ERROR), Exc_DeviceInit_Error }, + { DEC_FKTOP(EXC_FID_ENABLEPORT, UCS_OP_RESULT), Exc_EnablePort_Result }, + { DEC_FKTOP(EXC_FID_ENABLEPORT, UCS_OP_ERROR), Exc_EnablePort_Error }, + { DEC_FKTOP(EXC_FID_CABLE_LINK_DIAG, UCS_OP_RESULT), Exc_CableLinkDiag_Result }, + { DEC_FKTOP(EXC_FID_CABLE_LINK_DIAG, UCS_OP_ERROR), Exc_CableLinkDiag_Error }, + { DEC_FKTOP(EXC_FID_PHY_LAY_TEST, UCS_OP_ERROR), Exc_NwPhyTest_Error }, + { DEC_FKTOP(EXC_FID_PHY_LAY_TEST_RES, UCS_OP_STATUS), Exc_NwPhyTestResult_Status }, + { DEC_FKTOP(EXC_FID_PHY_LAY_TEST_RES, UCS_OP_ERROR), Exc_NwPhyTestResult_Error }, + { DEC_FKTOP(EXC_FID_BC_DIAG, UCS_OP_RESULT), Exc_BC_Diag_Result }, + { DEC_FKTOP(EXC_FID_BC_DIAG, UCS_OP_ERROR), Exc_BC_Diag_Error }, + { DEC_FKTOP(EXC_FID_BC_ENABLE_TX, UCS_OP_RESULT), Exc_BC_EnableTx_Result }, + { DEC_FKTOP(EXC_FID_BC_ENABLE_TX, UCS_OP_ERROR), Exc_BC_EnableTx_Error }, + { DEC_FKTOP(EXC_FID_MEM_SESSION_OPEN, UCS_OP_RESULT), Exc_MemSessionOpen_Result }, + { DEC_FKTOP(EXC_FID_MEM_SESSION_OPEN, UCS_OP_ERROR), Exc_MemSessionOpen_Error }, + { DEC_FKTOP(EXC_FID_MEM_SESSION_CLOSE, UCS_OP_RESULT), Exc_MemSessionClose_Result }, + { DEC_FKTOP(EXC_FID_MEM_SESSION_CLOSE, UCS_OP_ERROR), Exc_MemSessionClose_Error }, + { DEC_FKTOP(EXC_FID_MEMORY_READ, UCS_OP_RESULT), Exc_MemoryRead_Result }, + { DEC_FKTOP(EXC_FID_MEMORY_READ, UCS_OP_ERROR), Exc_MemoryRead_Error }, + { DEC_FKTOP(EXC_FID_MEMORY_WRITE, UCS_OP_RESULT), Exc_MemoryWrite_Result }, + { DEC_FKTOP(EXC_FID_MEMORY_WRITE, UCS_OP_ERROR), Exc_MemoryWrite_Error }, + { DEC_FKTOP_TERMINATION, NULL } +}; + + +/*------------------------------------------------------------------------------------------------*/ +/* Implementation */ +/*------------------------------------------------------------------------------------------------*/ + +/*! \brief Constructor of class CExc. + * \param self Reference to CExc instance + * \param base_ptr Reference to a Base instance + * \param rcm_ptr Reference to Transceiver instance + */ +void Exc_Ctor(CExc *self, CBase *base_ptr, CTransceiver *rcm_ptr) +{ + + MISC_MEM_SET((void *)self, 0, sizeof(*self)); + + self->base_ptr = base_ptr; + self->xcvr_ptr = rcm_ptr; + + self->fkt_op_list_ptr = &exc_handler[0]; + + + /* Initialize API locking mechanism */ + Sobs_Ctor(&self->lock.observer, self, &Exc_HandleApiTimeout); + Al_Ctor(&self->lock.api, &self->lock.observer, self->base_ptr->ucs_user_ptr); + Alm_RegisterApi(&self->base_ptr->alm, &self->lock.api); + +} + + +/*! \brief Callback function to filter RCM Rx messages + * \details Do not release the message object here + * \param self reference to INIC object + * \param tel_ptr received message + */ +void Exc_OnRcmRxFilter(void *self, Msg_MostTel_t *tel_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_DecodeMsg(self_, tel_ptr); + +} + + +/*! \brief Decode a message for FBlock EXC + * \param self Instance pointer to FBlock EXC + * \param msg_rx_ptr pointer to the MCM message to decode + */ +static void Exc_DecodeMsg(CExc *self, Msg_MostTel_t *msg_rx_ptr) +{ + Dec_Return_t result; + uint16_t index; + + result = Dec_SearchFktOpIsh(self->fkt_op_list_ptr, &index, msg_rx_ptr->id.function_id, msg_rx_ptr->id.op_type); + + if (result == DEC_RET_SUCCESS) + { + self->fkt_op_list_ptr[index].handler_function_ptr(self, msg_rx_ptr); + } + else + { + /* no handling of decoding error for shadow OpTypes */ + } +} + + + +/*! \brief Handles an API timeout + * \param self Instance pointer + * \param method_mask_ptr Bitmask to signal which API method has caused the timeout + */ +static void Exc_HandleApiTimeout(void *self, void *method_mask_ptr) +{ + CExc *self_ = (CExc *)self; + Alm_ModuleMask_t method_mask = *((Alm_ModuleMask_t *)method_mask_ptr); + Exc_StdResult_t res_data; + + res_data.result.code = UCS_RES_ERR_TIMEOUT; + res_data.result.info_ptr = NULL; + res_data.result.info_size = 0U; + res_data.data_info = NULL; + + switch(method_mask) + { +#if 0 /* System Diagnosis supervises timeouts for these functions */ + case EXC_API_ENABLE_PORT: + Ssub_Notify(&self_->ssubs.enableport, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_EnablePort_Sr().", 0U)); + break; + case EXC_API_HELLO: + Ssub_Notify(&self_->ssubs.hello, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_Hello_Get().", 0U)); + break; + case EXC_API_WELCOME: + Ssub_Notify(&self_->ssubs.welcome, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_Welcome_Sr().", 0U)); + break; + case EXC_API_CABLE_LINK_DIAG: + Ssub_Notify(&self_->ssubs.cablelinkdiag, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_CableLinkDiagnosis_Start().", 0U)); + break; +#endif + case EXC_API_PHY_LAY_TEST_RESULT: + Ssub_Notify(&self_->ssubs.phylaytestresult, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_PhyTestResult_Get().", 0U)); + break; + case EXC_API_MEM_SESSION_OPEN: + Ssub_Notify(&self_->ssubs.memsessionopen, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_MemSessionOpen_Sr().", 0U)); + break; + case EXC_API_MEM_SESSION_CLOSE: + Ssub_Notify(&self_->ssubs.memsessionclose, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_MemSessionClose_Sr().", 0U)); + break; + case EXC_API_MEM_READ: + Ssub_Notify(&self_->ssubs.memoryread, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_MemoryRead_Sr().", 0U)); + break; + case EXC_API_MEM_WRITE: + Ssub_Notify(&self_->ssubs.memorywrite, &res_data, false); + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "API locking timeout occurred for method Exc_MemoryWrite_Sr().", 0U)); + break; + + default: + TR_ERROR((self_->base_ptr->ucs_user_ptr, "[EXC]", "Unknown API locking bitmask detected. Mask: 0x%02X", 1U, method_mask)); + break; + } +} + + + + +/*------------------------------------------------------------------------------------------------*/ +/* Internal API */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief This method sends the Hello.Get message + * \param self Reference to CExc instance + * \param target_address Target address + * \param version_limit Signature version limit + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_Hello_Get(CExc *self, + uint16_t target_address, + uint8_t version_limit, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 1U); + + if (msg_ptr != NULL) + { + if (version_limit > UCS_EXC_SIGNATURE_VERSION_LIMIT) + { + version_limit = UCS_EXC_SIGNATURE_VERSION_LIMIT; + } + + msg_ptr->destination_addr = target_address; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_HELLO; + msg_ptr->id.op_type = UCS_OP_GET; + msg_ptr->tel.tel_data_ptr[0] = version_limit; + + msg_ptr->info_ptr = &self->ssubs.hello; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.hello, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + + +/*! \brief This method send the Welcome.StartResult message + * \param self Reference to CExc instance + * \param target_address Target address + * \param admin_node_address The node address used during system diagnosis + * \param version Signature version + * \param signature Signature of the device + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_Welcome_Sr(CExc *self, + uint16_t target_address, + uint16_t admin_node_address, + uint8_t version, + Ucs_Signature_t signature, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, EXC_SIGNATURE_LEN_V1 + 3U); /* Signature v1 */ + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = target_address; + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_WELCOME; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = MISC_HB(admin_node_address); + msg_ptr->tel.tel_data_ptr[1] = MISC_LB(admin_node_address); + msg_ptr->tel.tel_data_ptr[2] = version; + msg_ptr->tel.tel_data_ptr[3] = MISC_HB(signature.node_address); + msg_ptr->tel.tel_data_ptr[4] = MISC_LB(signature.node_address); + msg_ptr->tel.tel_data_ptr[5] = MISC_HB(signature.group_address); + msg_ptr->tel.tel_data_ptr[6] = MISC_LB(signature.group_address); + msg_ptr->tel.tel_data_ptr[7] = MISC_HB(signature.mac_47_32); + msg_ptr->tel.tel_data_ptr[8] = MISC_LB(signature.mac_47_32); + msg_ptr->tel.tel_data_ptr[9] = MISC_HB(signature.mac_31_16); + msg_ptr->tel.tel_data_ptr[10] = MISC_LB(signature.mac_31_16); + msg_ptr->tel.tel_data_ptr[11] = MISC_HB(signature.mac_15_0); + msg_ptr->tel.tel_data_ptr[12] = MISC_LB(signature.mac_15_0); + msg_ptr->tel.tel_data_ptr[13] = MISC_HB(signature.node_pos_addr); + msg_ptr->tel.tel_data_ptr[14] = MISC_LB(signature.node_pos_addr); + msg_ptr->tel.tel_data_ptr[15] = MISC_HB(signature.diagnosis_id); + msg_ptr->tel.tel_data_ptr[16] = MISC_LB(signature.diagnosis_id); + msg_ptr->tel.tel_data_ptr[17] = signature.num_ports; + msg_ptr->tel.tel_data_ptr[18] = signature.chip_id; + msg_ptr->tel.tel_data_ptr[19] = signature.fw_major; + msg_ptr->tel.tel_data_ptr[20] = signature.fw_minor; + msg_ptr->tel.tel_data_ptr[21] = signature.fw_release; + msg_ptr->tel.tel_data_ptr[22] = MISC_HB((signature.fw_build) >>16U); + msg_ptr->tel.tel_data_ptr[23] = MISC_LB((signature.fw_build) >>16U); + msg_ptr->tel.tel_data_ptr[24] = MISC_HB(signature.fw_build); + msg_ptr->tel.tel_data_ptr[25] = MISC_LB(signature.fw_build); + msg_ptr->tel.tel_data_ptr[26] = signature.cs_major; + msg_ptr->tel.tel_data_ptr[27] = signature.cs_minor; + msg_ptr->tel.tel_data_ptr[28] = signature.cs_release; +/* msg_ptr->tel.tel_data_ptr[29] = signature.uid_persistency; + msg_ptr->tel.tel_data_ptr[30] = MISC_HB((signature.uid) >>16U); + msg_ptr->tel.tel_data_ptr[31] = MISC_LB((signature.uid) >>16U); + msg_ptr->tel.tel_data_ptr[32] = MISC_HB(signature.uid); + msg_ptr->tel.tel_data_ptr[33] = MISC_LB(signature.uid); +*/ + + msg_ptr->info_ptr = &self->ssubs.welcome; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.welcome, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + + +/*! \brief This method sends the Signature.Get message + * \param self Reference to CExc instance + * \param target_address Target address + * \param version_limit Signature version limit + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_Signature_Get(CExc *self, + uint16_t target_address, + uint8_t version_limit, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 1U); + + if (msg_ptr != NULL) + { + if (version_limit > UCS_EXC_SIGNATURE_VERSION_LIMIT) + { + version_limit = UCS_EXC_SIGNATURE_VERSION_LIMIT; + } + + msg_ptr->destination_addr = target_address; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_SIGNATURE; + msg_ptr->id.op_type = UCS_OP_GET; + msg_ptr->tel.tel_data_ptr[0] = version_limit; + + msg_ptr->info_ptr = &self->ssubs.signature; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.signature, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + + +/*! \brief This method sends the DeviceInit.Start message + * \param self Reference to CExc instance + * \param target_address Target address + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_DeviceInit_Start(CExc *self, + uint16_t target_address, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 0U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = target_address; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_DEVICE_INIT; + msg_ptr->id.op_type = UCS_OP_START; + + msg_ptr->info_ptr = &self->ssubs.deviceinit; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.deviceinit, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + + +/*! \brief This method enables a port + * \param self Reference to CExc instance + * \param target_address Target address + * \param port_number PortNumber + * \param enabled Enabled + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_EnablePort_Sr(CExc *self, + uint16_t target_address, + uint8_t port_number, + bool enabled, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 2U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = target_address; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_ENABLEPORT; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = port_number; + msg_ptr->tel.tel_data_ptr[1] = (uint8_t)enabled; + + msg_ptr->info_ptr = &self->ssubs.enableport; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.enableport, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + +/*! \brief This method starts the Cable Link Diagnosis + * \param self Reference to CExc instance + * \param target_address Target address + * \param port_number PortNumber + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_CableLinkDiagnosis_Start(CExc *self, + uint16_t target_address, + uint8_t port_number, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 1U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = target_address; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_CABLE_LINK_DIAG; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = port_number; + + msg_ptr->info_ptr = &self->ssubs.cablelinkdiag; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.cablelinkdiag, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + +/*! \brief This method starts the Physical Layer Test + * \param self Reference to CExc instance + * \param port_number PortNumber + * \param type Type + * \param lead_in Lead-in + * \param duration Duration + * \param lead_out Lead-out + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_PhyTest_Start(CExc *self, + uint8_t port_number, + Ucs_Diag_PhyTest_Type_t type, + uint16_t lead_in, + uint32_t duration, + uint16_t lead_out, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 10U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = MSG_ADDR_INIC; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_PHY_LAY_TEST; + msg_ptr->id.op_type = UCS_OP_START; + msg_ptr->tel.tel_data_ptr[0] = port_number; + msg_ptr->tel.tel_data_ptr[1] = (uint8_t)type; + msg_ptr->tel.tel_data_ptr[2] = MISC_HB(lead_in); + msg_ptr->tel.tel_data_ptr[3] = MISC_LB(lead_in); + msg_ptr->tel.tel_data_ptr[4] = (uint8_t)((duration) >> 24); + msg_ptr->tel.tel_data_ptr[5] = (uint8_t)((duration) >> 16); + msg_ptr->tel.tel_data_ptr[6] = (uint8_t)((duration) >> 8); + msg_ptr->tel.tel_data_ptr[7] = (uint8_t)(duration & (uint32_t)0xFF); + msg_ptr->tel.tel_data_ptr[8] = MISC_HB(lead_out); + msg_ptr->tel.tel_data_ptr[9] = MISC_LB(lead_out); + + + msg_ptr->info_ptr = &self->ssubs.phylaytest; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.phylaytest, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + + +/*! \brief Requests the EXC.PhysicalLayerTestResult.Status message + * \param self Reference to CExc instance + * \param obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + * \return UCS_RET_ERR_API_LOCKED Resource API is already used by another command + */ +Ucs_Return_t Exc_PhyTestResult_Get(CExc *self, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + if(Al_Lock(&self->lock.api, EXC_API_PHY_LAY_TEST_RESULT) != false) + { + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 0U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = MSG_ADDR_INIC; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_PHY_LAY_TEST_RES; + msg_ptr->id.op_type = UCS_OP_GET; + + msg_ptr->info_ptr = &self->ssubs.phylaytestresult; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.phylaytestresult, obs_ptr); + } + else + { + Al_Release(&self->lock.api, EXC_API_PHY_LAY_TEST_RESULT); + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + } + else + { + result = UCS_RET_ERR_API_LOCKED; + } + + return result; +} + + + +/*! Sends the BCDiag.Startresult command + * + * \param *self Reference to CExc instance + * \param position Position of the segment to be checked. + * \param admin_na Admin Node Address + * \param t_send Timing parameter t_Send + * \param t_wait4dut Timing parameter t_WaitForDUT + * \param t_switch Timing parameter t_Switch + * \param t_back Timing parameter t_Back + * \param autoback TBD + * \param *obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_BCDiag_Start(CExc *self, + uint8_t position, + uint16_t admin_na, + uint16_t t_send, + uint16_t t_wait4dut, + uint16_t t_switch, + uint16_t t_back, + bool autoback, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 12U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = UCS_ADDR_BROADCAST_BLOCKING; + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_BC_DIAG; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = position; + msg_ptr->tel.tel_data_ptr[1] = MISC_HB(admin_na); + msg_ptr->tel.tel_data_ptr[2] = MISC_LB(admin_na); + msg_ptr->tel.tel_data_ptr[3] = MISC_HB(t_send); + msg_ptr->tel.tel_data_ptr[4] = MISC_LB(t_send); + msg_ptr->tel.tel_data_ptr[5] = MISC_HB(t_wait4dut); + msg_ptr->tel.tel_data_ptr[6] = MISC_LB(t_wait4dut); + msg_ptr->tel.tel_data_ptr[7] = MISC_HB(t_switch); + msg_ptr->tel.tel_data_ptr[8] = MISC_LB(t_switch); + msg_ptr->tel.tel_data_ptr[9] = MISC_HB(t_back); + msg_ptr->tel.tel_data_ptr[10] = MISC_LB(t_back); + msg_ptr->tel.tel_data_ptr[11] = (uint8_t)autoback; + + + msg_ptr->info_ptr = &self->ssubs.bcdiag; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.bcdiag, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + + +/*! Enables the signal during backChannel Diagnosis + * + * \param *self Reference to CExc instance + * \param port Number of port which has to be enabled. + * \param *obs_ptr Reference to an optional observer + * \return UCS_RET_SUCCESS message was created + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + */ +Ucs_Return_t Exc_BCEnableTx_StartResult(CExc *self, + uint8_t port, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 1U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = UCS_ADDR_BROADCAST_BLOCKING; + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_BC_ENABLE_TX; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = port; + + msg_ptr->info_ptr = &self->ssubs.enabletx; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.enabletx, obs_ptr); + } + else + { + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + + return result; +} + + +/*! \brief This function is used to open a memory session. + * + * A memory session is used to control access to the memory resources. Before a memory could + * be read or written, a session of the appropriate type has to be opened. + * Only a single memory session is supported. Once opened, the session must be first + * closed before a new session of a different type could be used. Some session types + * (0x01, 0x02 and 0x04) require a hardware reset after they were closed. + * Function Exc_MemSessionOpen_Sr() also performs some preprocessing, + * depending on the session_type. This includes clearing of the configuration + * and identification strings before the error memory is programmed or erased. + * + * \param *self Reference to CExc instance + * \param target_address Target address + * \param session_type Defines the set of MemIDs and the memory access type(s) (read and/or write) + * \param *obs_ptr Reference to an optional observer + * + * \return UCS_RET_SUCCESS message was created and sent to INIC + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + * \return UCS_RET_ERR_API_LOCKED Resource API is already used by another command + */ +Ucs_Return_t Exc_MemSessionOpen_Sr(CExc *self, + uint16_t target_address, + uint8_t session_type, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + if(Al_Lock(&self->lock.api, EXC_API_MEM_SESSION_OPEN) != false) + { + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 1U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = target_address; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_MEM_SESSION_OPEN; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = session_type; + + msg_ptr->info_ptr = &self->ssubs.memsessionopen; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.memsessionopen, obs_ptr); + } + else + { + Al_Release(&self->lock.api, EXC_API_MEM_SESSION_OPEN); + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + } + else + { + result = UCS_RET_ERR_API_LOCKED; + } + + return result; +} + + +/*! \brief This function is used to close an active memory session that was previously opened by + * function Exc_MemSessionOpen_Sr(). + * + * In addition, the function performs some post-processing on given session types. This includes + * validation of the newly programmed configuration and identification strings as well as + * the deactivation of the current configuration and identification strings. In these cases, + * the new configuration becomes active after a hardware reset. + * + * \param *self Reference to CExc instance + * \param target_address Target address + * \param session_handle Unique number assigned to the active memory session + * \param *obs_ptr Reference to an optional observer + * + * \return UCS_RET_SUCCESS message was created and sent to INIC + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + * \return UCS_RET_ERR_API_LOCKED Resource API is already used by another command + */ +Ucs_Return_t Exc_MemSessionClose_Sr(CExc *self, + uint16_t target_address, + uint16_t session_handle, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + if(Al_Lock(&self->lock.api, EXC_API_MEM_SESSION_CLOSE) != false) + { + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 2U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = target_address; + + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_MEM_SESSION_CLOSE; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = MISC_HB(session_handle); + msg_ptr->tel.tel_data_ptr[1] = MISC_LB(session_handle); + + msg_ptr->info_ptr = &self->ssubs.memsessionclose; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.memsessionclose, obs_ptr); + } + else + { + Al_Release(&self->lock.api, EXC_API_MEM_SESSION_CLOSE); + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + } + else + { + result = UCS_RET_ERR_API_LOCKED; + } + + return result; +} + + +/*! \brief This function provides read access to the memories described by parameter MemID. + * + * In addition, the function can be used to retrieve the active Configuration String and + * Identification String. + * Reading the memory can only be done within an active memory session. Parameter + * session_handle authorizes the access to the memory resource defined by parameter + * MemID. The session_handle is provided by function Exc_MemSessionOpen_Sr(), + * which must be called in advance to memory access. + * + * \param *self Reference to CExc instance + * \param target_address Target address + * \param session_handle Unique number assigned to the active memory session + * \param mem_id Represents the memory resource to be read + * \param address Defines the memory location at which the reading operation starts + * \param unit_len Sets the number of memory units to be read. Memory units can be + * unsigned bytes, unsigned words or unsigned masked data depending + * on the memory type. + * \param *obs_ptr Reference to an optional observer + * + * \return UCS_RET_SUCCESS message was created and sent to INIC + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + * \return UCS_RET_ERR_PARAM parameter ubit_len ist too big + * \return UCS_RET_ERR_API_LOCKED Resource API is already used by another command + */ +Ucs_Return_t Exc_MemoryRead_Sr(CExc *self, + uint16_t target_address, + uint16_t session_handle, + uint8_t mem_id, + uint32_t address, + uint8_t unit_len, + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + if(Al_Lock(&self->lock.api, EXC_API_MEM_READ) != false) + { + if (unit_len > MAX_UNIT_LEN) + { + result = UCS_RET_ERR_PARAM; + } + + if (result == UCS_RET_SUCCESS) + { + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 8U); + + if (msg_ptr != NULL) + { + msg_ptr->destination_addr = target_address; + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_MEMORY_READ; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = MISC_HB(session_handle); + msg_ptr->tel.tel_data_ptr[1] = MISC_LB(session_handle); + msg_ptr->tel.tel_data_ptr[2] = mem_id; + msg_ptr->tel.tel_data_ptr[3] = (uint8_t)((address) >> 24); + msg_ptr->tel.tel_data_ptr[4] = (uint8_t)((address) >> 16); + msg_ptr->tel.tel_data_ptr[5] = (uint8_t)((address) >> 8); + msg_ptr->tel.tel_data_ptr[6] = (uint8_t)(address & (uint32_t)0xFF); + msg_ptr->tel.tel_data_ptr[7] = unit_len; + + msg_ptr->info_ptr = &self->ssubs.memoryread; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.memoryread, obs_ptr); + } + else + { + Al_Release(&self->lock.api, EXC_API_MEM_READ); + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + } + } + else + { + result = UCS_RET_ERR_API_LOCKED; + } + + return result; +} + + +/*! \brief This function provides write access to the memories described by parameter MemID. + * + * In addition, the function can be used to program a new Configuration String and Identification + * String. + * Writing the memory can only be done within an active memory session. Parameter + * SessionHandle authorizes the access to the memory resource defined by parameter + * MemID. The SessionHandle is provided by function ExtendedNetworkControl.MemorySessionOpen(), + * which must be called in advance to memory access. + * + * \param *self Reference to CExc instance + * \param target_address Target address + * \param session_handle Unique number assigned to the active memory session + * \param mem_id Represents the memory resource to be read + * \param address Defines the memory location at which the reading operation starts + * \param unit_len Sets the number of memory units to be read. Memory units can be + * unsigned bytes, unsigned words or unsigned masked data depending + * on the memory type. + * \param *unit_data Contains the actual data written to the memory resource and formatted + * as memory units + * \param *obs_ptr Reference to an optional observer + * + * \return UCS_RET_SUCCESS message was created and sent to INIC + * \return UCS_RET_ERR_BUFFER_OVERFLOW no message buffer available + * \return UCS_RET_ERR_PARAM parameter ubit_len ist too big + * \return UCS_RET_ERR_API_LOCKED Resource API is already used by another command + */ +Ucs_Return_t Exc_MemoryWrite_Sr(CExc *self, + uint16_t target_address, + uint16_t session_handle, + uint8_t mem_id, + uint32_t address, + uint8_t unit_len, + uint8_t unit_data[], + CSingleObserver *obs_ptr) +{ + Ucs_Return_t result = UCS_RET_SUCCESS; + + if(Al_Lock(&self->lock.api, EXC_API_MEM_WRITE) != false) + { + if (unit_len > MAX_UNIT_LEN) + { + result = UCS_RET_ERR_PARAM; + } + + if (result == UCS_RET_SUCCESS) + { + Msg_MostTel_t *msg_ptr = Trcv_TxAllocateMsg(self->xcvr_ptr, 8U + unit_len); + + if (msg_ptr != NULL) + { + uint8_t i; + + msg_ptr->destination_addr = target_address; + msg_ptr->id.fblock_id = FB_EXC; + msg_ptr->id.instance_id = 0U; + msg_ptr->id.function_id = EXC_FID_MEMORY_WRITE; + msg_ptr->id.op_type = UCS_OP_STARTRESULT; + msg_ptr->tel.tel_data_ptr[0] = MISC_HB(session_handle); + msg_ptr->tel.tel_data_ptr[1] = MISC_LB(session_handle); + msg_ptr->tel.tel_data_ptr[2] = mem_id; + msg_ptr->tel.tel_data_ptr[3] = (uint8_t)((address) >> 24); + msg_ptr->tel.tel_data_ptr[4] = (uint8_t)((address) >> 16); + msg_ptr->tel.tel_data_ptr[5] = (uint8_t)((address) >> 8); + msg_ptr->tel.tel_data_ptr[6] = (uint8_t)(address & (uint32_t)0xFF); + msg_ptr->tel.tel_data_ptr[7] = unit_len; + for (i=0U; i<unit_len; ++i) + { + msg_ptr->tel.tel_data_ptr[8U+i] = *(unit_data + i); + } + + msg_ptr->info_ptr = &self->ssubs.memorywrite; + Trcv_TxSendMsg(self->xcvr_ptr, msg_ptr); + + (void)Ssub_AddObserver(&self->ssubs.memorywrite, obs_ptr); + } + else + { + Al_Release(&self->lock.api, EXC_API_MEM_WRITE); + result = UCS_RET_ERR_BUFFER_OVERFLOW; + } + } + } + else + { + result = UCS_RET_ERR_API_LOCKED; + } + + return result; +} + + + +/*------------------------------------------------------------------------------------------------*/ +/* Handler functions */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief Handler function for EXC.Hello.Status + * \param self Reference to EXC object + * \param msg_ptr Received message + */ +static void Exc_Hello_Status(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_HelloStatus_t hello_data; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len >= (EXC_SIGNATURE_LEN_V1 + 1U)) + { + hello_data.version = msg_ptr->tel.tel_data_ptr[0]; + Exc_Read_Signature(&(hello_data.signature), &(msg_ptr->tel.tel_data_ptr[1])); + + res_data.data_info = &hello_data; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + res_data.result.info_size = 0U; + + /* Node Discovery sends the Hello.Get as broadcast message. So we will need the observer + several times. */ + Ssub_Notify(&self_->ssubs.hello, &res_data, false); + } +} + + +/*! \brief Handler function for EXC.Hello.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_Hello_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + /* Node Discovery sends the Hello.Get as broadcast message. So we will need the observer + several times. */ + Ssub_Notify(&self_->ssubs.hello, &res_data, false); + } +} + + +/*! \brief Handler function for EXC.Welcome.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_Welcome_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.welcome, &res_data, true); + } +} + +/*! \brief Handler function for the EXC.Welcome.Result message + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_Welcome_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_WelcomeResult_t welcome_data; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len >= (EXC_SIGNATURE_LEN_V1 + 2U)) + { + welcome_data.res = msg_ptr->tel.tel_data_ptr[0]; + welcome_data.version = msg_ptr->tel.tel_data_ptr[1]; + Exc_Read_Signature(&(welcome_data.signature), &(msg_ptr->tel.tel_data_ptr[2])); + res_data.data_info = &welcome_data; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.welcome, &res_data, true); + } +} + + +/*! Handler function for the EXC.Signature.Status message + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_Signature_Status(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_SignatureStatus_t signature_data; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len >= (EXC_SIGNATURE_LEN_V1 + 1U)) + { + signature_data.version = msg_ptr->tel.tel_data_ptr[0]; + Exc_Read_Signature(&(signature_data.signature), &(msg_ptr->tel.tel_data_ptr[1])); + + res_data.data_info = &signature_data; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + res_data.result.info_size = 0U; + + Ssub_Notify(&self_->ssubs.signature, &res_data, true); + } +} + + +/*! Handler function for the EXC.Signature.Error message + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_Signature_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.signature, &res_data, true); + } +} + + +/*! Handler function for the EXC.DeviceInit.Error message + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_DeviceInit_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len >0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.deviceinit, &res_data, true); + } +} + + +/*! \brief Handler function for EXC.EnablePort.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_EnablePort_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.enableport, &res_data, true); + } +} + +/*! \brief Handler function for EXC.EnablePort.Result + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_EnablePort_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + MISC_UNUSED(msg_ptr); + + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + Ssub_Notify(&self_->ssubs.enableport, &res_data, true); +} + + +/*! \brief Handler function for EXC.CableLinkDiag.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_CableLinkDiag_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.cablelinkdiag, &res_data, true); + } +} + +/*! \brief Handler function for EXC.CableLinkDiag.Result + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_CableLinkDiag_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_CableLinkDiagResult_t cable_link_diag_result_data; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + cable_link_diag_result_data.port_number = msg_ptr->tel.tel_data_ptr[0]; + cable_link_diag_result_data.result = msg_ptr->tel.tel_data_ptr[1]; + res_data.data_info = &cable_link_diag_result_data; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.cablelinkdiag, &res_data, true); + } +} + + +/*! \brief Handler function for EXC.PhysicalLayerTest.Error + * \param self reference to EXC object + * \param msg_ptr received message + */static void Exc_NwPhyTest_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.phylaytest, &res_data, true); + } +} + + +/*! \brief Handler function for EXC.MOSTNetworkPhysicalLayerTestResult.Status + * \param self Reference to EXC object + * \param msg_ptr Received message + */ +static void Exc_NwPhyTestResult_Status(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_PhyTestResult_t phy_test_result; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + phy_test_result.port_number = msg_ptr->tel.tel_data_ptr[0]; + phy_test_result.lock_status = (msg_ptr->tel.tel_data_ptr[1] != 0U) ? true : false; + MISC_DECODE_WORD(&(phy_test_result.err_count), &(msg_ptr->tel.tel_data_ptr[2])); + res_data.data_info = &phy_test_result; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.phylaytestresult, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_PHY_LAY_TEST_RESULT); +} + + +/*! \brief Handler function for EXC.MOSTNetworkPhysicalLayerTestResult.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_NwPhyTestResult_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.phylaytestresult, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_PHY_LAY_TEST_RESULT); +} + + + +/*! \brief Handler function for EXC.BCDiag.Status + * \param self Reference to EXC object + * \param msg_ptr Received message + */ +static void Exc_BC_Diag_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_BCDiagResult bcd_result; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 1U) + { + bcd_result.diag_result = (Exc_BCDiagResValue)(msg_ptr->tel.tel_data_ptr[0] >> 4U); + MISC_DECODE_WORD(&(bcd_result.admin_addr), &(msg_ptr->tel.tel_data_ptr[0])); + bcd_result.admin_addr &= 0x0FFFU; + res_data.data_info = &bcd_result; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.bcdiag, &res_data, true); + } +} + + +/*! \brief Handler function for EXC.BCDiag.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_BC_Diag_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.bcdiag, &res_data, true); + } +} + + + + +/*! \brief Handler function for EXC.BCEnableTx.Result + * \param self Reference to EXC object + * \param msg_ptr Received message + */ +static void Exc_BC_EnableTx_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + res_data.data_info = NULL; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.enabletx, &res_data, true); + + MISC_UNUSED(msg_ptr); +} + + +/*! \brief Handler function for EXC.BCEnableTx.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_BC_EnableTx_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.enabletx, &res_data, true); + } +} + + +/*! \brief Handler function for EXC.MemorySessionOpen.Result + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemSessionOpen_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + uint16_t session_handle; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + MISC_DECODE_WORD(&(session_handle), &(msg_ptr->tel.tel_data_ptr[0])); + res_data.data_info = &session_handle; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.memsessionopen, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_SESSION_OPEN); +} + + +/*! \brief Handler function for EXC.MemorySessionOpen.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemSessionOpen_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.memsessionopen, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_SESSION_OPEN); +} + + +/*! \brief Handler function for EXC.MemorySessionClose.Result + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemSessionClose_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + uint8_t session_result; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + session_result = msg_ptr->tel.tel_data_ptr[0]; + res_data.data_info = &session_result; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.memsessionclose, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_SESSION_CLOSE); +} + +/*! \brief Handler function for EXC.MemorySessionClose.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemSessionClose_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.memsessionclose, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_SESSION_CLOSE); +} + +/*! \brief Handler function for EXC.MemoryRead.Result + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemoryRead_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_MemReadResult_t mem_read_result; + Exc_StdResult_t res_data; + uint8_t i; + + if (msg_ptr->tel.tel_len > 0U) + { + MISC_DECODE_WORD(&(mem_read_result.session_handle), &(msg_ptr->tel.tel_data_ptr[0])); + mem_read_result.mem_id = msg_ptr->tel.tel_data_ptr[2]; + MISC_DECODE_DWORD(&(mem_read_result.address), &(msg_ptr->tel.tel_data_ptr[3])); + mem_read_result.unit_len = msg_ptr->tel.tel_data_ptr[7]; + for (i=0U; (i<mem_read_result.unit_len) && (i<MAX_UNIT_LEN); ++i) + { + mem_read_result.unit_data[i] = msg_ptr->tel.tel_data_ptr[8U+i]; + } + + res_data.data_info = &mem_read_result; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.memoryread, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_READ); +} + + +/*! \brief Handler function for EXC.MemoryRead.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemoryRead_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.memoryread, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_READ); +} + + +/*! \brief Handler function for EXC.MemoryWrite.Result + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemoryWrite_Result(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_MemWriteResult_t mem_write_result; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + MISC_DECODE_WORD(&(mem_write_result.session_handle), &(msg_ptr->tel.tel_data_ptr[0])); + mem_write_result.mem_id = msg_ptr->tel.tel_data_ptr[2]; + + res_data.data_info = &mem_write_result; + res_data.result.code = UCS_RES_SUCCESS; + res_data.result.info_ptr = NULL; + + Ssub_Notify(&self_->ssubs.memorywrite, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_WRITE); +} + + +/*! \brief Handler function for EXC.MemoryWrite.Error + * \param self reference to EXC object + * \param msg_ptr received message + */ +static void Exc_MemoryWrite_Error(void *self, Msg_MostTel_t *msg_ptr) +{ + CExc *self_ = (CExc *)self; + Exc_StdResult_t res_data; + + if (msg_ptr->tel.tel_len > 0U) + { + res_data.data_info = NULL; + res_data.result = Exc_TranslateError(self_, + &msg_ptr->tel.tel_data_ptr[0], + (uint8_t)(msg_ptr->tel.tel_len)); + + Ssub_Notify(&self_->ssubs.memorywrite, &res_data, true); + } + Al_Release(&self_->lock.api, EXC_API_MEM_WRITE); +} + + + +/*------------------------------------------------------------------------------------------------*/ +/* Helper functions */ +/*------------------------------------------------------------------------------------------------*/ +/*! \brief Translates EXC error codes into UNICENS error codes and wraps the raw INIC + * error data to a byte stream. + * \param self Instance of CExc + * \param error_data[] EXC error data + * \param error_size Size of EXC error data in bytes + * \return The formatted error + */ +static Ucs_StdResult_t Exc_TranslateError(CExc *self, uint8_t error_data[], uint8_t error_size) +{ + Ucs_StdResult_t ret_val; + MISC_UNUSED(self); + + if(error_data[0] != 0x20U) + { + ret_val.code = UCS_RES_ERR_MOST_STANDARD; + } + else + { + ret_val.code = (Ucs_Result_t)(error_data[1] + 1U); + } + + ret_val.info_ptr = &error_data[0]; + ret_val.info_size = error_size; + + return ret_val; +} + + +/*! \brief Reads a signature from a message's payload + * + * \param dest Pointer to signature + * \param source Pointer to start of signature inabyte array + */ +static void Exc_Read_Signature(Ucs_Signature_t *dest, uint8_t source[]) +{ + MISC_DECODE_WORD(&(dest->node_address), source); + MISC_DECODE_WORD(&(dest->group_address), &(source[2])); + MISC_DECODE_WORD(&(dest->mac_47_32), &(source[4])); + MISC_DECODE_WORD(&(dest->mac_31_16), &(source[6])); + MISC_DECODE_WORD(&(dest->mac_15_0), &(source[8])); + MISC_DECODE_WORD(&(dest->node_pos_addr), &(source[10])); + MISC_DECODE_WORD(&(dest->diagnosis_id), &(source[12])); + dest->num_ports = source[14]; + dest->chip_id = source[15]; + dest->fw_major = source[16]; + dest->fw_minor = source[17]; + dest->fw_release = source[18]; + MISC_DECODE_DWORD(&(dest->fw_build), &(source[19])); + dest->cs_major = source[23]; + dest->cs_minor = source[24]; + dest->cs_release = source[25]; +/* dest->uid_persistency = source[26];*/ /* Signature v1 */ +/* MISC_DECODE_DWORD(&(dest->uid), &(source[27]));*/ + +} +/*! + * @} + * \endcond + */ + +/*------------------------------------------------------------------------------------------------*/ +/* End of file */ +/*------------------------------------------------------------------------------------------------*/ + |