/* * 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 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 This file contains the CIndustrialStack class (NetService part). */ /*----------------------------------------------------------*/ #define ENABLE_INIC_WATCHDOG true #include #include #include #include #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 #include 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); }