/*
* 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.
*
*/
#include
#include
#include "SafeVector.h"
#include "Network.h"
#include "NetworkDevice.h"
#include "DriverConfiguration.h"
#include "MacAddr.h"
#include "Board.h"
#include "Console.h"
#include "NodeDatabase.h"
using namespace std;
static CNetwork *staticInstance = NULL;
CSafeVector CNetwork::allNetworkDevices;
CNetwork::CNetwork() : CThread( "CNetwork", false ), allowNetworkRun( false ),
vodXml( NULL ), connectionBitMask( 0 ), promiscuous( false ), retryCounter( 0 ),
retryExecTime( 0 )
{
searchPath[0] = 0;
sem_init( &vodXmlMutex, 0, 1 ); //Mutex, initialized to 1 => sem_wait will block at 2nd call
Start();
}
CNetwork::~CNetwork()
{
ConsolePrintf( PRIO_LOW, "Destructor of network called\r\n" );
Stop();
allowNetworkRun = false;
CloseAllNetworkDevices();
sem_wait( &vodXmlMutex );
if( NULL != vodXml )
{
delete vodXml;
vodXml = NULL;
}
sem_post( &vodXmlMutex );
staticInstance = NULL;
ConsolePrintf( PRIO_LOW, "end network\r\n" );
}
CNetwork *CNetwork::GetInstance( void )
{
if( NULL == staticInstance )
{
staticInstance = new CNetwork();
}
return staticInstance;
}
void CNetwork::AddListener( CNetworkListner *listener )
{
allListeners.PushBack( listener );
}
void CNetwork::RemoveListener( CNetworkListner *listener )
{
allListeners.Remove(listener);
}
void CNetwork::SetPromiscuousMode( bool enabled )
{
promiscuous = enabled;
}
bool CNetwork::LoadConfig( char *szConfigXml )
{
uint32_t len = strlen(szConfigXml);
if( NULL == szConfigXml || 0 == len)
{
ConsolePrintf( PRIO_ERROR, RED"Path to config file was NULL"RESETCOLOR"\n" );
return false;
}
if ('/' == szConfigXml[0])
{
char path[300];
uint32_t i;
uint32_t lastSlash = 0;
for (i = len - 1; i > 0; i--)
{
if ('/' == szConfigXml[i])
{
lastSlash = i;
break;
}
}
memcpy(path, szConfigXml, lastSlash);
path[lastSlash] = '\0';
memcpy(szConfigXml, &szConfigXml[lastSlash + 1], (len - lastSlash - 1) );
szConfigXml[len - lastSlash - 1] = '\0';
return LoadConfig(szConfigXml, path);
}
else
{
return LoadConfig(szConfigXml, NULL);
}
}
bool CNetwork::LoadConfig( const char *szConfigXml, const char *szSearchPath )
{
char configPath[300];
if( NULL == szConfigXml || 0 == strlen(szConfigXml))
{
ConsolePrintf( PRIO_ERROR, RED"Path to config file was NULL"RESETCOLOR"\n" );
return false;
}
if (NULL != szSearchPath)
strncpy( searchPath, szSearchPath, sizeof( searchPath ) );
if( NULL != searchPath && '/' != szConfigXml[0])
snprintf( configPath, sizeof( configPath ), "%s/%s", searchPath, szConfigXml );
else
strncpy( configPath, szConfigXml, sizeof( configPath ) );
allowNetworkRun = true;
sem_wait( &vodXmlMutex );
bool success;
if( NULL != vodXml )
{
delete vodXml;
}
vodXml = new CVodXml( configPath );
success = ( NULL != vodXml );
sem_post( &vodXmlMutex );
if ( allNetworkDevices.Size() != 0 )
{
bool tm;
uint32_t bw;
if (vodXml->GetMostParameters( &tm, &bw ) )
{
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
allNetworkDevices[i]->SetAsyncBandwidth(bw);
allNetworkDevices[i]->SetTimingMaster(tm);
ShutdownMost(allNetworkDevices[i]);
}
}
}
if( success )
FindNewNetworkDevices();
retryCounter = 0;
return success;
}
bool CNetwork::ActionsPending()
{
bool isPending = false;
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
if( allNetworkDevices[i]->ActionsPending() )
{
isPending = true;
break;
}
}
return isPending;
}
bool CNetwork::ConnectSourceToSink( CMacAddr *SourceMacAddr, TChannelId SourceChannelId, CMacAddr *SinkMacAddr,
TChannelId SinkChannelId )
{
CNodeEntry *inNode = CNodeEntry::GetNodeEntry( SourceMacAddr );
CNodeEntry *outNode = CNodeEntry::GetNodeEntry( SinkMacAddr );
return ConnectSourceToSink( inNode, outNode, SourceChannelId, SinkChannelId );
}
uint8_t CNetwork::GetAmountOfLocalNodes()
{
return allNetworkDevices.Size();
}
bool CNetwork::SendMostControlMessage( TMostInstace mostInstance, uint32_t targetAddr, uint32_t nFBlock,
uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload )
{
bool success = false;
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance )
{
if (targetAddr < 0x300 || targetAddr > 0x3FF || targetAddr == 0x3C8)
{
success = allNetworkDevices[i]->SendMostControlMessage( mostInstance, targetAddr, nFBlock, nInst, nFunc,
nOpType, nPayloadLen, Payload );
}
else
{
success = true;
for (uint16_t j = 0; j < CNodeEntry::GetAmountOfNodeEntries(); j++)
{
CNodeEntry *node = CNodeEntry::GetNodeEntry(j);
if (NULL != node && node->deviceInstance == mostInstance &&
node->deviceType == targetAddr)
{
success &= allNetworkDevices[i]->SendMostControlMessage( mostInstance, node->nodeAddress, nFBlock, nInst, nFunc,
nOpType, nPayloadLen, Payload );
}
}
}
break;
}
}
return success;
}
bool CNetwork::SendMostControlMessage( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst,
uint32_t nFBlock, uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload )
{
bool success = false;
CNodeEntry *entry = CNodeEntry::GetNodeEntry( mostInstance, deviceId, devInst );
if( NULL == entry )
return success;
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance )
{
success = allNetworkDevices[i]->SendMostControlMessage( mostInstance, entry->nodeAddress, nFBlock, nInst,
nFunc, nOpType, nPayloadLen, Payload );
break;
}
}
return success;
}
bool CNetwork::ExecuteXmlScriptFromFile( TMostInstace mostInstance, uint32_t targetAddr, const char *szFile )
{
if (NULL == szFile)
return false;
bool success = false;
char scriptPath[300];
const char *pPath = szFile;
if( NULL != searchPath && '/' != szFile[0])
{
snprintf( scriptPath, sizeof( scriptPath ), "%s/%s", searchPath, szFile );
pPath = scriptPath;
}
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance )
{
allNetworkDevices[i]->ExecuteMcmScript( targetAddr, pPath );
success = true;
break;
}
}
return success;
}
bool CNetwork::ExecuteXmlScriptFromFile( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst,
const char *szFile )
{
CNodeEntry *entry = CNodeEntry::GetNodeEntry( mostInstance, deviceId, devInst );
if( NULL == entry )
return false;
return ExecuteXmlScriptFromFile( mostInstance, entry->nodeAddress, szFile );
}
bool CNetwork::ExecuteXmlScriptFromMemory( TMostInstace mostInstance, uint32_t targetAddr, const char *szBuffer,
uint32_t nBufferLen )
{
bool success = false;
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance )
{
allNetworkDevices[i]->ExecuteMcmScript( targetAddr, szBuffer, nBufferLen );
success = true;
break;
}
}
return success;
}
bool CNetwork::ExecuteXmlScriptFromMemory( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst,
const char *szBuffer, uint32_t nBufferLen )
{
CNodeEntry *entry = CNodeEntry::GetNodeEntry( mostInstance, deviceId, devInst );
if( NULL == entry )
return false;
return ExecuteXmlScriptFromMemory( mostInstance, entry->nodeAddress, szBuffer, nBufferLen );
}
uint32_t CNetwork::GetCounterPartOfRoute( const Route_t *pInRoute, Route_t **pOutRouteArray )
{
if( ( NULL == pInRoute ) || ( NULL == pOutRouteArray ) )
{
ConsolePrintf( PRIO_ERROR, RED"GetCounterPartOfRoute was called with wrong parameters"RESETCOLOR"\n" );
return 0;
}
*pOutRouteArray = NULL;
CSafeVector connectedTerminals;
CRouteTerminal terminal;
terminal.deviceType = pInRoute->deviceType;
terminal.instance = pInRoute->instance;
terminal.channelId = pInRoute->channelId;
sem_wait( &vodXmlMutex );
bool found = vodXml->GetRouteTerminals( &terminal, connectedTerminals );
sem_post( &vodXmlMutex );
if( !found )
return 0;
uint32_t arrayLen = connectedTerminals.Size();
*pOutRouteArray = ( Route_t * )calloc( arrayLen, sizeof( Route_t ) );
if( NULL == *pOutRouteArray )
{
ConsolePrintf( PRIO_ERROR, RED"GetCounterPartOfRoute failed to allocate memory"RESETCOLOR"\n" );
return 0;
}
for( uint32_t i = 0; i < arrayLen; i++ )
{
( *pOutRouteArray )[i].deviceType = connectedTerminals[i]->deviceType;
( *pOutRouteArray )[i].instance = connectedTerminals[i]->instance;
( *pOutRouteArray )[i].channelId = connectedTerminals[i]->channelId;
}
return arrayLen;
}
bool CNetwork::GetRingBreakDiagnosisResult( TMostInstace mostInstance, uint32_t targetAddr )
{
bool success = false;
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance )
{
allNetworkDevices[i]->GetRingBreakResultV3( 1, 0 );
success = true;
break;
}
}
return success;
}
void CNetwork::EnableMost(bool enabled)
{
allowNetworkRun = enabled;
for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ )
{
CNetworkDevice *device = allNetworkDevices[i];
if (enabled)
{
if (NetworkState_Available == device->GetNetState())
{
ConsolePrintf(PRIO_ERROR, RED"MOST is already in NET ON state"RESETCOLOR"\n");
return;
}
device->SetNetstate( NetworkState_Unknown );
bool isTimingMaster = device->IsTimingMaster();
uint32_t asyncBandwidth = device->GetAsyncBandwidth();
if( isTimingMaster )
device->MostNetworkStartupV3( 0xFFFF, asyncBandwidth );
}
else
{
device->SetNetstate( NetworkState_ShutdownInProgress );
device->ClearAllPendingActions();
device->MostNetworkShutdownV3();
}
}
}
void CNetwork::Run()
{
sleep( 5 );
if (retryCounter > 0 && (GetTickCount() - retryExecTime >= 60000))
retryCounter = 0;
if( allowNetworkRun )
FindNewNetworkDevices();
}
/*---------------------------------------------*/
/* Empty implementation of CNetworkListner */
/*---------------------------------------------*/
void CNetworkListner::OnNetworkState( uint8_t mostInstance, bool available, uint8_t maxPos, uint16_t packetBW )
{
ConsolePrintf( PRIO_LOW, "CNetwork::OnNetworkState\n" );
}
void CNetworkListner::OnChannelAvailable( CMacAddr *macAddr, TDeviceId deviceId, uint8_t devInst, TChannelId channelId,
TMostInstace mostInstance, EPDataType_t dataType, TBlockwidth reservedBandwidth, bool isSourceDevice,
bool inSocketCreated, bool outSocketCreated, bool socketsConnected, int32_t bufferSize,
uint32_t mostConnectionLabel, int16_t splittedOffset, int16_t splittedMaxBandwidth, uint16_t packetsPerXact,
const char *deviceName )
{
ConsolePrintf( PRIO_LOW, "CNetwork::OnCharacterDeviceAvailable(%s)\n", deviceName );
}
void CNetworkListner::OnChannelUnavailable( CMacAddr *macAddr, TChannelId channelId, uint8_t mostInstance )
{
ConsolePrintf( PRIO_LOW, "CNetwork::OnChannelUnavailable\n" );
}
void CNetworkListner::OnMostControlMessage( uint8_t devInst, uint32_t sourceAddr, uint32_t targetAddr,
uint32_t nFBlock, uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload )
{
ConsolePrintf( PRIO_LOW, "CNetwork::OnMostControlMessage\n" );
}
void CNetworkListner::OnRingBreakDiagnosisResultV3( uint8_t devInst, uint16_t nodeAddress, uint8_t result,
uint8_t position, uint8_t status, uint16_t id )
{
ConsolePrintf( PRIO_LOW, "CNetwork::OnRingBreakDiagnosisResultV2\n" );
}