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