summaryrefslogtreecommitdiffstats
path: root/Src/Network/IndustrialStack_MNS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Network/IndustrialStack_MNS.cpp')
-rw-r--r--Src/Network/IndustrialStack_MNS.cpp414
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);
+}