/*
* 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 .
*
* 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);
}