diff options
Diffstat (limited to 'Src/Network/IndustrialStack_MNS.cpp')
-rw-r--r-- | Src/Network/IndustrialStack_MNS.cpp | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/Src/Network/IndustrialStack_MNS.cpp b/Src/Network/IndustrialStack_MNS.cpp new file mode 100644 index 0000000..257db40 --- /dev/null +++ b/Src/Network/IndustrialStack_MNS.cpp @@ -0,0 +1,414 @@ +/* + * Video On Demand Samples + * + * Copyright (C) 2015 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 3 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 This file contains the CIndustrialStack class (NetService part). + */ +/*----------------------------------------------------------*/ + +#define ENABLE_INIC_WATCHDOG true + +#include <assert.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "IndustrialStack_MNS.h" +#include "IndustrialStack_Types.h" +#include "Board.h" +#include "Console.h" + +static bool CheckMnswPointer(void *inst_ptr, const char *functionName); +static void Lld_CtrlStartC( Mns_Lld_Api_t *callbacks_ptr, void *ns_ptr, void *inst_ptr ); +static void Lld_CtrlStopC( void *inst_ptr ); +static void Lld_CtrlTxTransmitC( Mns_Lld_TxMsg_t *msg_ptr, void *inst_ptr ); +static void Lld_CtrlRxMsgAvailableC( void *inst_ptr ); +static uint16_t GetTickCountWordC(); +static void OnMnslEventC( Mnsl_Event_t event_code, void *inst_ptr ); +static void OnMnslServiceC( void *inst_ptr ); +static void *OnMnslAmsAllocMemC( void *inst_ptr, uint16_t mem_size, Mns_Ams_MemUsage_t type, void** custom_info_pptr ); +static void OnMnslAmsFreeMemC( void *inst_ptr, void *mem_ptr, Mns_Ams_MemUsage_t type, void* custom_info_ptr ); +static void OnIcmRx( void *inst_ptr, Msg_MostTel_t *pRx ); +static void OnRcmRx( void *inst_ptr, Msg_MostTel_t *pRx ); +static void OnMcmRx( void *inst_ptr, Msg_MostTel_t *pRx ); +static void OnTransmissionStatus(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status); + +CISNetServiceWrapper::CISNetServiceWrapper(uint8_t deviceApi, int controlRxHandle, int controlTxHandle) + : testPattern(MNSW_TESTPATTERN), inicWriteError( false ), pMnsInterface(NULL), pMnsInst(NULL) + , isSynced(false), wrapperCB(NULL) +{ + if( 2 != deviceApi && 3 != deviceApi ) + { + ConsolePrintf( PRIO_ERROR, RED"CISNetServiceWrapper was called with deviceApi set"\ + " to %d. This is not supported by this branch of NetworkManager"\ + RESETCOLOR"\n", deviceApi ); + } + + lld = new CIndustrialStackLld(controlRxHandle, controlTxHandle); + lld->listener = this; + + memset(&pLldCb, 0, sizeof(pLldCb)); + pLldCb.start_fptr = &Lld_CtrlStartC; + pLldCb.stop_fptr = &Lld_CtrlStopC; + pLldCb.rx_available_fptr = &Lld_CtrlRxMsgAvailableC; + pLldCb.tx_transmit_fptr = &Lld_CtrlTxTransmitC; + + Mnsl_InitData_t initData; + Mnsl_SetDefaultConfig(&initData, ENABLE_INIC_WATCHDOG); + initData.lld.start_fptr = &Lld_CtrlStartC; + initData.lld.stop_fptr = &Lld_CtrlStopC; + initData.lld.rx_available_fptr = &Lld_CtrlRxMsgAvailableC; + initData.lld.tx_transmit_fptr = &Lld_CtrlTxTransmitC; + + initData.general.get_tickcount_fptr = &GetTickCountWordC; + initData.general.event_fptr = &OnMnslEventC; + initData.general.request_service_fptr = &OnMnslServiceC; + + initData.pms.active_fifos = MNSL_FIFOS_MCM_ICM_RCM; + initData.pms.compressed = (2 == deviceApi); + + initData.ams.rx_alloc_mem_fptr = &OnMnslAmsAllocMemC; + initData.ams.rx_free_mem_fptr = &OnMnslAmsFreeMemC; + + Mnsl_Init( &mnsl, &initData, this ); + + icm_inst_ptr = Mnsl_GetIcmTransceiver( &mnsl ); // Retrieve ICM instance + rcm_inst_ptr = Mnsl_GetRcmTransceiver( &mnsl ); // Retrieve RCM instance + mcm_inst_ptr = Mnsl_GetMcmTransceiver( &mnsl ); // Retrieve MCM instance + + Trcv_RxAssignReceiver( icm_inst_ptr, &OnIcmRx, this ); // Assign ICM Receiver Callback + Trcv_RxAssignReceiver( rcm_inst_ptr, &OnRcmRx, this ); // Assign ICM Receiver Callback + Trcv_RxAssignReceiver( mcm_inst_ptr, &OnMcmRx, this ); // Assign ICM Receiver Callback + + Mnsl_Synchronize( &mnsl ); +} + +CISNetServiceWrapper::~CISNetServiceWrapper() +{ + if (NULL != lld) + { + delete lld; + lld = NULL; + } +} + +void CISNetServiceWrapper::ServiceMns() +{ + assert(NULL != lld); + uint16_t wLen; + while( 0 != ( wLen = lld->DataAvailable() ) ) + { + if (NULL != pMnsInterface) + { + Mns_Lld_RxMsg_t *pRxMsg = pMnsInterface->rx_allocate_fptr( pMnsInst, wLen ); + if( pRxMsg ) + { + if (wLen != lld->Read( pRxMsg->data_ptr, wLen )) + ConsolePrintf( PRIO_ERROR, RED"! LLD read error"RESETCOLOR"\n" ); //Must not happen + pRxMsg->data_size = wLen; + pMnsInterface->rx_receive_fptr( pMnsInst, pRxMsg ); + Mnsl_Service( &mnsl ); + } + else + ConsolePrintf( PRIO_ERROR, RED"! out of message memory"RESETCOLOR"\n" ); + } + } + Mnsl_Service( &mnsl ); +} + +void CISNetServiceWrapper::AddListener(IISNetServiceWrapperCB *rcvListener) +{ + wrapperCB = rcvListener; +} + +bool CISNetServiceWrapper::SendMostMessage(CISMostMsg *msg) +{ + assert(NULL != msg); + assert(msg->IsValid); + + CTransceiver *tr = NULL; + + if (0x1 == msg->TargetAddress || 0x100 == msg->TargetAddress) + tr = icm_inst_ptr; + else if (0x0 == msg->FBlock || 0x1 == msg->FBlock) + tr = rcm_inst_ptr; + else + tr = mcm_inst_ptr; + + Msg_MostTel_t *tel = Trcv_TxAllocateMsg( tr, msg->PayloadLen ); + if( NULL == tel ) + { + ConsolePrintf( PRIO_ERROR, RED"Trcv_TxAllocateMsg failed. Len:"\ + " %u, Message-Type=%s"RESETCOLOR"\n", msg->PayloadLen, + (tr == icm_inst_ptr ? "ICM" : tr == rcm_inst_ptr ? "RCM" : "MCM")); + return false; + } + tel->source_addr = msg->SourceAddress; + tel->destination_addr = msg->TargetAddress; + tel->id.fblock_id = msg->FBlock; + tel->id.function_id = msg->Func; + tel->id.instance_id = msg->Inst; + tel->id.op_type = (Mns_OpType_t)msg->OpType; + tel->tel.tel_len = msg->PayloadLen; + tel->tel.tel_id = 0; + if (0 != msg->PayloadLen) + { + if (NULL != tel->tel.tel_data_ptr) + { + memcpy(tel->tel.tel_data_ptr, msg->Payload, msg->PayloadLen); + } else { + ConsolePrintf(PRIO_ERROR, RED"CISNetServiceWrapper::SendMostMessage,"\ + " packet has NULL pointer payload"RESETCOLOR"\n"); + Trcv_TxReleaseMsg(tel); + return false; + } + } + Trcv_TxSendMsgExt( tr, tel, OnTransmissionStatus, NULL ); + return true; +} + +void CISNetServiceWrapper::Unsynchronize() +{ + Mnsl_Unsynchronize( &mnsl, true ); +} + +void CISNetServiceWrapper::OnReadThreadEnd(CIndustrialStackLld *lld) +{ + if (NULL != wrapperCB) + wrapperCB->OnControlReadEnd(); +} + +void CISNetServiceWrapper::OnCtrlTxTransmit( Mns_Lld_TxMsg_t *msg_ptr) +{ + assert(NULL != msg_ptr); + assert(NULL != pMnsInterface); + if( msg_ptr && pMnsInterface ) + { + assert(NULL != lld); + Mns_Mem_Buffer_t *pMemBuf; +#define MAX_DATA_LEN 72 + uint8_t data[MAX_DATA_LEN]; + uint8_t *pW = data; + for( pMemBuf = msg_ptr->memory_ptr; pMemBuf != NULL; + pMemBuf = pMemBuf->next_buffer_ptr ) + { + if( pW + pMemBuf->data_size >= data + MAX_DATA_LEN ) + { + ConsolePrintf( PRIO_ERROR, RED"invalid size"RESETCOLOR"\n" ); + return; + } + memcpy( pW, pMemBuf->data_ptr, pMemBuf->data_size ); + pW += pMemBuf->data_size; + } + + if( !lld->Write( pW - data, data ) ) + { + if (!inicWriteError) + { + inicWriteError = true; + ConsolePrintf( PRIO_ERROR, RED"! Unable to write to INIC!"RESETCOLOR"\n" ); + } + } + else inicWriteError = false; + + pMnsInterface->tx_release_fptr( pMnsInst, msg_ptr ); + } +} + +void CISNetServiceWrapper::OnMnslEvent( Mnsl_Event_t event_code ) +{ + bool oldSyncState = isSynced; + switch( event_code ) + { + case MNSL_EVENT_SYNC_COMPLETE: + isSynced = true; + ConsolePrintf( PRIO_MEDIUM, "MNSL Event Callback notifies: MNSL_EVENT_SYNC_COMPLETE\n" ); + break; + case MNSL_EVENT_SYNC_FAILED: + isSynced = false; + ConsolePrintf( PRIO_ERROR, YELLOW"MNSL Event Callback notifies: MNSL_EVENT_SYNC_FAILED" \ + ", retrying..\nMake sure that local INIC runs Firmware V2.3.0 or later!"RESETCOLOR"\n" ); + Mnsl_Synchronize( &mnsl ); + return; /* Do not report the event */ + case MNSL_EVENT_SYNC_LOST: + isSynced = false; + ConsolePrintf( PRIO_ERROR, "MNSL Event Callback notifies: MNSL_EVENT_SYNC_LOST\n" ); + break; + case MNSL_EVENT_UNSYNC_COMPLETE: + isSynced = false; + ConsolePrintf( PRIO_MEDIUM, YELLOW"MNSL Event Callback notifies: MNSL_EVENT_UNSYNC_COMPLETE, syncing again.."RESETCOLOR"\n" ); + Mnsl_Synchronize( &mnsl ); + return; /* Do not report the event */ + case MNSL_EVENT_UNSYNC_FAILED: + isSynced = false; + ConsolePrintf( PRIO_ERROR, RED"MNSL Event Callback notifies: MNSL_EVENT_UNSYNC_FAILED"RESETCOLOR"\n" ); + Mnsl_Synchronize( &mnsl ); + break; + default: + ConsolePrintf( PRIO_ERROR, "MNSL Event Callback notifies: UNKNOWN CODE\n" ); + break; + } + if (NULL != wrapperCB && oldSyncState != isSynced) + { + wrapperCB->OnSyncStateChanged(isSynced); + } +} + +void CISNetServiceWrapper::OnMessage( Msg_MostTel_t *pRx, CTransceiver *pTr ) +{ + assert(NULL != pRx); + assert(pRx->tel.tel_len <= MAX_PAYLOAD_SIZE); + if (NULL == wrapperCB) + return; + CISMostMsg msg; + msg.IsValid = true; + msg.SourceAddress = pRx->source_addr; + msg.TargetAddress = pRx->destination_addr; + msg.FBlock = pRx->id.fblock_id; + msg.Func = pRx->id.function_id; + msg.Inst = pRx->id.instance_id; + msg.OpType = (CISOpType_t) pRx->id.op_type; + msg.PayloadLen = pRx->tel.tel_len; + memcpy(msg.Payload, pRx->tel.tel_data_ptr, msg.PayloadLen); + Trcv_RxReleaseMsg(pTr, pRx); + wrapperCB->OnReceivedMostMessage(&msg); +} + +/*---------------------------------------- + * Private helper functions and C wrapper: + *---------------------------------------- + */ +static bool CheckMnswPointer(void *inst_ptr, const char *functionName) +{ + if( NULL == inst_ptr || MNSW_TESTPATTERN != ( ( CISNetServiceWrapper * )inst_ptr )->testPattern ) + { + ConsolePrintf( PRIO_ERROR, RED"Parameter bug in %s"RESETCOLOR"\n", functionName ); + assert(false); + return true; + } + return false; +} +static void Lld_CtrlStartC( Mns_Lld_Api_t *callbacks_ptr, void *ns_ptr, void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "Lld_CtrlStart")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->pMnsInterface = callbacks_ptr; + mnsw->pMnsInst = ns_ptr; +} +static void Lld_CtrlStopC( void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "Lld_CtrlStop")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->pMnsInterface = 0; + mnsw->pMnsInst = 0; +} +static void Lld_CtrlTxTransmitC( Mns_Lld_TxMsg_t *msg_ptr, void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "Lld_CtrlTxTransmit")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnCtrlTxTransmit(msg_ptr); +} +static void Lld_CtrlRxMsgAvailableC( void *inst_ptr ) +{ + //Unused +} +static uint16_t GetTickCountWordC() +{ + return GetTickCountWord(); +} +static void OnMnslEventC( Mnsl_Event_t event_code, void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "OnMnslEvent")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMnslEvent(event_code); +} +static void OnMnslServiceC( void *inst_ptr ) +{ + //Unused +} +static void *OnMnslAmsAllocMemC( void *inst_ptr, uint16_t mem_size, Mns_Ams_MemUsage_t type, void** custom_info_pptr ) +{ + if( 0 == mem_size ) + return NULL; + return calloc( mem_size, 1 ); +} +static void OnMnslAmsFreeMemC( void *inst_ptr, void *mem_ptr, Mns_Ams_MemUsage_t type, void* custom_info_ptr ) +{ + if( NULL != mem_ptr ) + free( mem_ptr ); +} +static void OnIcmRx( void *inst_ptr, Msg_MostTel_t *pRx ) +{ + if (CheckMnswPointer(inst_ptr, "OnIcmRx")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMessage(pRx, mnsw->icm_inst_ptr); +} +static void OnRcmRx( void *inst_ptr, Msg_MostTel_t *pRx ) +{ + if (CheckMnswPointer(inst_ptr, "OnRcmRx")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMessage(pRx, mnsw->rcm_inst_ptr); +} +static void OnMcmRx( void *inst_ptr, Msg_MostTel_t *pRx ) +{ + if (CheckMnswPointer(inst_ptr, "OnMcmRx")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMessage(pRx, mnsw->mcm_inst_ptr); +} + +static void OnTransmissionStatus(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status) +{ + if (MNS_MSG_STAT_OK != status) + { + ConsolePrintf(PRIO_ERROR, RED"Transmission failed for addr=0x%X FBlock=0x%X " \ + "Function=0x%X, error-code=0x%X"RESETCOLOR"\n", tel_ptr->destination_addr, + tel_ptr->id.fblock_id, tel_ptr->id.function_id, status); + } + Trcv_TxReleaseMsg(tel_ptr); +} + +#define TRACE_BUFFER_SZ 200 +#include <stdarg.h> +#include <stdio.h> +void My_TraceInfo(uint8_t mns_inst_id, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...) +{ + char_t outbuf[TRACE_BUFFER_SZ]; + va_list argptr; + uint16_t timestamp = GetTickCountWord(); + va_start(argptr, vargs_cnt); + vsprintf(outbuf, entry_str, argptr); + va_end(argptr); + ConsolePrintf(PRIO_HIGH, YELLOW"[%u] | %u | Info | %s | %s"RESETCOLOR"\n", mns_inst_id, timestamp, module_str, outbuf); +} + +void My_TraceError(uint8_t mns_inst_id, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...) +{ + char_t outbuf[TRACE_BUFFER_SZ]; + va_list argptr; + uint16_t timestamp = GetTickCountWord(); + va_start(argptr, vargs_cnt); + vsprintf(outbuf, entry_str, argptr); + va_end(argptr); + ConsolePrintf(PRIO_ERROR, RED"[%u] | %u | Error | %s | %s"RESETCOLOR"\n", mns_inst_id, timestamp, module_str, outbuf); +} |