/*------------------------------------------------------------------------------------------------*/
/* 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 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; itel.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; (itel.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 */
/*------------------------------------------------------------------------------------------------*/