/* * 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 #include #include "SafeVector.h" #include "MacAddr.h" #include "Types.h" #include "Console.h" #include "ConnectionInfo.h" #define MY_IPC_HEADER "most mac dev-type instance channel-id type bandwidth direction con-label buffer state offset offset-max p-xact dev-name" #define MY_IPC_HEADER_LINE_END MY_IPC_HEADER"\n" CConnectionInfo::CConnectionInfo() : deviceType( 0 ), deviceInstance( 0 ), channelId( 0 ), mostInstance( 0 ), dataType( EP_Unknown ), reservedBandwidth( 0 ), bufferSize( 0 ), isTX( false), inSocketCreated( false ), outSocketCreated( false ), socketsConnected( false ), mostConnectionLabel( 0xFFFFFFFF ), splittedOffset( 0 ), splittedMaxBandwidth( 0 ), packetsPerXact( 0 ) { macAddr = new CMacAddr(); deviceName[0] = '\0'; } CConnectionInfo::CConnectionInfo( CMacAddr *macAddr, TChannelId cId, uint8_t mInst, bool isTx ) : deviceType( 0 ), deviceInstance( 0 ), channelId( cId ), mostInstance(mInst), dataType( EP_Unknown ), reservedBandwidth( 0 ), bufferSize( 0 ), isTX( isTx ), inSocketCreated( false ), outSocketCreated( false ), socketsConnected( false ), mostConnectionLabel( 0xFFFFFFFF ), splittedOffset( -1 ), splittedMaxBandwidth( -1 ), packetsPerXact( 0 ) { this->macAddr = new CMacAddr( macAddr ); //Copy the object deviceName[0] = '\0'; } CConnectionInfo::~CConnectionInfo() { if( NULL != macAddr ) { delete macAddr; macAddr = NULL; } } CConnectionInfoContainer::CConnectionInfoContainer() { } CConnectionInfoContainer::~CConnectionInfoContainer() { DestroyAllInfos(); } uint32_t CConnectionInfoContainer::GetAllInfoAmount() { return allInfos.Size(); } CConnectionInfo *CConnectionInfoContainer::GetInfo( uint32_t index ) { if( index >= allInfos.Size() ) { ConsolePrintf( PRIO_ERROR, RED"CConnectionInfoContainer::GetInfo was called with index out of range"RESETCOLOR"\n" ); return NULL; } return allInfos[index]; } bool CConnectionInfoContainer::Compare( CConnectionInfo *c, CConnectionInfo *t ) { if( NULL == c || NULL == t ) { ConsolePrintf( PRIO_ERROR, RED"Compare parameter error"RESETCOLOR"\n" ); return false; } return ( ( c->bufferSize == t->bufferSize ) && ( c->channelId == t->channelId ) && ( c->dataType == t->dataType ) && ( c->deviceType == t->deviceType ) && ( c->mostConnectionLabel == t->mostConnectionLabel ) && ( c->mostInstance == t->mostInstance ) && ( c->reservedBandwidth == t->reservedBandwidth ) && ( 0 == strcmp( c->deviceName, t->deviceName ) ) && ( c->isTX == t->isTX ) && ( *c->macAddr == *t->macAddr ) && ( c->packetsPerXact == t->packetsPerXact ) ); } bool CConnectionInfoContainer::Compare( CConnectionInfoContainer *remote ) { if( NULL == remote || ( remote->GetAllInfoAmount() != GetAllInfoAmount() ) ) return false; bool equal = true; for( uint32_t i = 0; equal && i < allInfos.Size(); i++ ) { equal = false; CConnectionInfo *t = allInfos[i]; if( NULL == t ) break; for( uint32_t j = 0; !equal && j < remote->GetAllInfoAmount(); j++ ) { CConnectionInfo *c = remote->GetInfo( j ); if( NULL == c ) break; if( Compare( c, t ) ) { equal = true; break; } } } return equal; } bool CConnectionInfoContainer::ExistsEntry( CConnectionInfo *c ) { if( NULL == c ) return false; bool exists = false; for( uint32_t i = 0; !false && i < allInfos.Size(); i++ ) { CConnectionInfo *t = allInfos[i]; if( NULL == t ) break; if( Compare( c, t ) ) { exists = true; break; } } return exists; } CConnectionInfo *CConnectionInfoContainer::GetInfo( CMacAddr *macAddr, TChannelId channelId, uint8_t mostInstance ) { CConnectionInfo *instance = NULL; if( NULL == macAddr ) { return NULL; } for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL != temp && *temp->macAddr == *macAddr && temp->channelId == channelId && temp->mostInstance == mostInstance ) { instance = temp; break; } } return instance; } uint8_t CConnectionInfoContainer::GetAmountOfDevices( TMostInstace mostInstance, TDeviceId deviceId ) { uint8_t amount = 0; CSafeVector allMacs; for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL != temp && temp->deviceType == deviceId && temp->mostInstance == mostInstance && NULL != temp->macAddr ) { bool update = true; for( uint32_t j = 0; j < allMacs.Size(); j++ ) { if( *allMacs[j] == *temp->macAddr ) { update = false; break; } } if( update ) { allMacs.PushBack( temp->macAddr ); ++amount; } } } return amount; } CConnectionInfo *CConnectionInfoContainer::GetInfo( CMacAddr *macAddr, TChannelId channelId, uint8_t mostInstance, bool isTx ) { CConnectionInfo *instance = GetInfo( macAddr, channelId, mostInstance ); if( NULL == instance ) { instance = new CConnectionInfo( macAddr, channelId, mostInstance, isTx ); allInfos.PushBack( instance ); } return instance; } void CConnectionInfoContainer::AddInfo( CConnectionInfo *info ) { if( NULL == info ) { ConsolePrintf( PRIO_ERROR, RED"AddInfo parameter error"RESETCOLOR"\n" ); return; } allInfos.PushBack( info ); } void CConnectionInfoContainer::DestroyAllInfos() { allInfos.RemoveAll(true); } void CConnectionInfoContainer::DestroyInfo( CMacAddr *macAddr, TChannelId channelId, uint8_t mostInstance ) { if( NULL == macAddr ) { ConsolePrintf( PRIO_ERROR, RED"DestroyInstance was called with invalid parameters."RESETCOLOR"\n" ); return; } for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL != temp && *temp->macAddr == *macAddr && temp->channelId == channelId && temp->mostInstance == mostInstance ) { allInfos.Remove(temp); delete temp; break; } } } void CConnectionInfoContainer::PrintTable( bool hideTx, bool hideRx ) { char macString[32]; char sizeString[10]; char stateString[32]; char offsetString[32]; char lastDeviceName[64]; const char *typeString; int16_t lastMaxOffset = -1; lastDeviceName[0] = '\0'; ConsolePrintfStart( PRIO_HIGH, "Index | MOST | MAC-ADDRESS | DEV | INST | ID | Type | BW | Dir | Con-Label | Buffer | State |DEVICE-NAME \n" ); ConsolePrintfContinue( "------|------|-------------------|------|------|-----|-------|-----|-----|-----------|--------|--------|-------------\n" ); for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if ( NULL == temp ) continue; if( hideTx && temp->isTX ) continue; if( hideRx && !temp->isTX ) continue; switch( temp->dataType ) { case EP_Synchron: typeString = "SYNC "; break; case EP_Asynchron: typeString = "ASYNC"; break; case EP_Control: typeString = "CTRL "; break; case EP_Isochron: typeString = "ISOC "; break; case EP_Unused: typeString = "EMPTY"; break; case EP_Unknown: default: typeString = "ERROR"; break; } if( NULL == temp->macAddr || NULL == temp->macAddr->ToString() ) strncpy( macString, "Unknown MAC Addr.", sizeof( macString ) ); else strncpy( macString, temp->macAddr->ToString(), sizeof( macString ) ); if( 0 > temp->bufferSize ) strncpy( sizeString, "None", sizeof( sizeString ) ); else snprintf( sizeString, sizeof ( sizeString ), "%04d", temp->bufferSize ); const char *goodStr = GREEN"X"; const char *badStr = RED"o"; snprintf( stateString, sizeof ( stateString ), "%s%s%s"RESETCOLOR, ( temp->inSocketCreated ? goodStr : badStr ), ( temp->outSocketCreated ? goodStr : badStr ), ( temp->socketsConnected ? goodStr : badStr ) ); offsetString[0] = '\0'; if( -1 != temp->splittedOffset && -1 != temp->splittedMaxBandwidth ) { if( 0 == temp->splittedOffset ) { lastMaxOffset = temp->splittedMaxBandwidth; if( 0 != strlen( temp->deviceName ) ) strncpy( lastDeviceName, temp->deviceName, sizeof( lastDeviceName ) ); } snprintf( offsetString, sizeof( offsetString ), " (offset %d/%d)", temp->splittedOffset, ( 0 == temp->splittedOffset ? temp->splittedMaxBandwidth : lastMaxOffset ) ); } ConsolePrintfContinue( "%02d ", i ); ConsolePrintfContinue( "| %02d ", temp->mostInstance ); ConsolePrintfContinue( "| %s ", macString ); ConsolePrintfContinue( "| %03X ", temp->deviceType ); ConsolePrintfContinue( "| %02d ", temp->deviceInstance ); ConsolePrintfContinue( "| %03d ", temp->channelId ); ConsolePrintfContinue( "| %s ", typeString ); ConsolePrintfContinue( "| %03d ", temp->reservedBandwidth ); ConsolePrintfContinue( "| %s ", ( temp->isTX ? "TX" : "RX" ) ); ConsolePrintfContinue( "| %03X ", ( temp->mostConnectionLabel != 0xFFFFFFFF ) ? temp-> mostConnectionLabel : 0xFFF ); ConsolePrintfContinue( "| %s ", sizeString ); ConsolePrintfContinue( "| %s ", stateString ); ConsolePrintfContinue( "| %s", ( '\0' == offsetString[0] ) ? temp->deviceName : lastDeviceName ); ConsolePrintfContinue( "%s\n", offsetString ); } ConsolePrintfExit( "------|------|-------------------|------|------|-----|-------|-----|-----|-----------|--------|--------|-------------\n" ); } uint32_t CConnectionInfoContainer::SerializeToString( char *pBuffer, uint32_t bufferLen ) { if( NULL == pBuffer || 0 == bufferLen ) { ConsolePrintf( PRIO_ERROR, RED"SerializeToString was called with wrong parameters"RESETCOLOR"\n" ); return 0; } uint32_t bytesUsed = strlen( pBuffer ); if (bytesUsed > bufferLen) { ConsolePrintf(PRIO_ERROR, RED"CConnectionInfoContainer::SerializeToString given buffer"\ " is too small!"RESETCOLOR); return 0; } const char *typeString = NULL; char stringBuffer[200]; strncpy( pBuffer, MY_IPC_HEADER_LINE_END, bufferLen ); for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *sourceInfo = allInfos[i]; if ( NULL == sourceInfo ) continue; switch( sourceInfo->dataType ) { case EP_Synchron: typeString = "SYNC"; break; case EP_Asynchron: typeString = "ASYNC"; break; case EP_Control: typeString = "CTRL"; break; case EP_Isochron: typeString = "ISOC"; break; case EP_Unused: typeString = "EMPTY"; break; case EP_Unknown: default: typeString = "ERROR"; break; } snprintf( stringBuffer, sizeof ( stringBuffer ), "%d %s %d %d %d %s %d %s %d %d %c%c%c %d %d %d %s\n", sourceInfo->mostInstance, sourceInfo->macAddr->ToString(), sourceInfo->deviceType, sourceInfo->deviceInstance, sourceInfo->channelId, typeString, sourceInfo->reservedBandwidth, ( sourceInfo->isTX ? "TX" : "RX" ), sourceInfo->mostConnectionLabel, sourceInfo->bufferSize, ( sourceInfo->inSocketCreated ? 'X' : '0' ), ( sourceInfo->outSocketCreated ? 'X' : '0' ), ( sourceInfo->socketsConnected ? 'X' : '0' ), sourceInfo->splittedOffset, sourceInfo->splittedMaxBandwidth, sourceInfo->packetsPerXact, sourceInfo->deviceName ); strncat( pBuffer, stringBuffer, ( bufferLen - bytesUsed ) ); bytesUsed = strlen( pBuffer ); } return strlen( pBuffer ) + 1; } bool CConnectionInfoContainer::DeserializeFromString( char *pBuffer ) { if( NULL == pBuffer || 0 == strlen( pBuffer ) ) { ConsolePrintf( PRIO_ERROR, RED"DeserializeFromString was called with wrong parameters"RESETCOLOR"\n" ); return false; } DestroyAllInfos(); char *helpPtr; char *token = strtok_r( pBuffer, "\n", &helpPtr ); bool first = true; while( NULL != token ) { if( first ) { first = false; if( 0 != strcmp( MY_IPC_HEADER, token ) ) { ConsolePrintf( PRIO_ERROR, RED"DeserializeFromString: Incompatible header found, aborting\n"\ "Expected:'%s'\n"\ "Got: '%s'"\ RESETCOLOR"\n", MY_IPC_HEADER, token ); return false; } } else { CConnectionInfo *info = new CConnectionInfo(); uint32_t mostInstance; char macString[20]; uint32_t deviceType; uint32_t deviceInstance; uint32_t channelId; char typeString[10]; uint32_t reservedBandwidth; char deviceDirection[10]; uint32_t mostConnectionLabel; uint32_t bufferSize; int32_t offset; int32_t maxOffset; uint32_t xact; char connectString[10]; sscanf( token, "%d %s %d %d %d %s %d %s %d %d %s %d %d %d %s\n", &mostInstance, macString, &deviceType, &deviceInstance, &channelId, typeString, &reservedBandwidth, deviceDirection, &mostConnectionLabel, &bufferSize, connectString, &offset, &maxOffset, &xact, info->deviceName ); info->mostInstance = mostInstance; info->deviceType = deviceType; info->deviceInstance = deviceInstance; info->channelId = channelId; info->reservedBandwidth = reservedBandwidth; info->mostConnectionLabel = mostConnectionLabel; info->bufferSize = bufferSize; info->splittedOffset = offset; info->splittedMaxBandwidth = maxOffset; info->packetsPerXact = xact; info->isTX = strstr( deviceDirection, "TX" ); if( NULL != connectString && 3 == strlen( connectString ) ) { info->inSocketCreated = connectString[0] == 'X'; info->outSocketCreated = connectString[1] == 'X'; info->socketsConnected = connectString[2] == 'X'; } if( NULL == info->macAddr ) info->macAddr = new CMacAddr(); info->macAddr->CopyValuesFromString( macString ); if( strstr( typeString, "ASYNC" ) ) { info->dataType = EP_Asynchron; } else if( strstr( typeString, "SYNC" ) ) { info->dataType = EP_Synchron; } else if( strstr( typeString, "CTRL" ) ) { info->dataType = EP_Control; } else if( strstr( typeString, "ISOC" ) ) { info->dataType = EP_Isochron; } else if( strstr( typeString, "EMPTY" ) ) { info->dataType = EP_Unused; } else { info->dataType = EP_Unknown; } allInfos.PushBack( info ); } token = strtok_r( NULL, "\n", &helpPtr ); } return true; } uint32_t CConnectionInfoContainer::GetAmountOfCDevs() { uint32_t amount = 0; for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL != temp && NULL != temp->deviceName && 0 != strlen( temp->deviceName ) ) ++amount; } return amount; } CConnectionInfo *CConnectionInfoContainer::GetConnectionInfoOfCdev( uint32_t cdevInst ) { uint32_t amount = 0; CConnectionInfo *info = NULL; for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL != temp && NULL != temp->deviceName && 0 != strlen( temp->deviceName ) ) { if( cdevInst == amount ) { info = temp; break; } ++amount; } } return info; } CConnectionInfo *CConnectionInfoContainer::GetConnectionInfoOfCdev( uint32_t cdevInst, uint32_t splittedIndex ) { uint32_t amountCdev = 0; uint32_t amountSplit = 0; CConnectionInfo *infoCdev = NULL; CConnectionInfo *infoSplitted = NULL; for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL == infoCdev ) { if( NULL != temp && NULL != temp->deviceName && 0 != strlen( temp->deviceName ) ) { if( cdevInst == amountCdev ) { infoCdev = temp; if( 0 != infoCdev->splittedOffset ) { ConsolePrintf( PRIO_ERROR, RED"CConnectionInfoContainer::GetConnectionInfoOfCdev"\ " was called for a non splitted CDEV"RESETCOLOR"\n" ); break; } } ++amountCdev; } } else { if( ( 0 == temp->splittedOffset ) || ( -1 == temp->splittedOffset ) ) break; if( amountSplit == splittedIndex ) { infoSplitted = temp; break; } ++amountSplit; } } return infoSplitted; } uint32_t CConnectionInfoContainer::GetAmountOfSinks() { uint32_t amount = 0; for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *sourceInfo = allInfos[i]; if( NULL == sourceInfo || NULL == sourceInfo->macAddr || NULL == sourceInfo->macAddr->ToString() ) continue; if( NULL == sourceInfo->deviceName || 0 == strlen( sourceInfo->deviceName ) ) continue; if( !sourceInfo->socketsConnected ) continue; for( uint32_t j = 0; j < allInfos.Size(); j++ ) { CConnectionInfo *sinkInfo = allInfos[j]; if( i == j ) continue; if( NULL == sinkInfo->macAddr || NULL == sinkInfo->macAddr->ToString() ) continue; if( !sinkInfo->socketsConnected ) continue; if( sourceInfo->mostConnectionLabel != sinkInfo->mostConnectionLabel ) continue; if( sourceInfo->mostInstance != sinkInfo->mostInstance ) continue; ++amount; } } return amount; } CConnectionInfo *CConnectionInfoContainer::GetConnectionInfoOfSink( uint32_t sinkInst ) { uint32_t amount = 0; CConnectionInfo *info = NULL; for( uint32_t i = 0; NULL == info && i < allInfos.Size(); i++ ) { CConnectionInfo *sourceInfo = allInfos[i]; if( NULL == sourceInfo || NULL == sourceInfo->macAddr || NULL == sourceInfo->macAddr->ToString() ) continue; if( NULL == sourceInfo->deviceName || 0 == strlen( sourceInfo->deviceName ) ) continue; if( !sourceInfo->socketsConnected ) continue; for( uint32_t j = 0; NULL == info && j < allInfos.Size(); j++ ) { CConnectionInfo *sinkInfo = allInfos[j]; if( i == j ) continue; if( NULL == sinkInfo->macAddr || NULL == sinkInfo->macAddr->ToString() ) continue; if( !sinkInfo->socketsConnected ) continue; if( sourceInfo->mostConnectionLabel != sinkInfo->mostConnectionLabel ) continue; if( sourceInfo->mostInstance != sinkInfo->mostInstance ) continue; if( sinkInst == amount ) { info = sinkInfo; } ++amount; } } return info; } CConnectionInfo *CConnectionInfoContainer::GetConnectionInfoByMacAddress( const uint8_t *mac ) { if( NULL == mac ) return NULL; char macAddr[20]; snprintf( ( char * )&macAddr, sizeof( macAddr ), "%02X-%02X-%02X-%02X-%02X-%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); CConnectionInfo *info = NULL; for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL != temp && NULL != temp->macAddr ) { if( 0 == strcmp( temp->macAddr->ToString(), macAddr ) ) { info = temp; break; } } } return info; } CConnectionInfo *CConnectionInfoContainer::GetRemoteConnectionInfoByMacAddress( const uint8_t *mac ) { if( NULL == mac ) return NULL; char macAddr[20]; snprintf( ( char * )&macAddr, sizeof( macAddr ), "%02X-%02X-%02X-%02X-%02X-%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); CConnectionInfo *remoteInfo = NULL; CConnectionInfo *info = GetConnectionInfoByMacAddress( mac ); if( NULL == info ) return NULL; for( uint32_t i = 0; i < allInfos.Size(); i++ ) { CConnectionInfo *temp = allInfos[i]; if( NULL != temp && NULL != temp->macAddr ) { if( 0 == strcmp( temp->macAddr->ToString(), macAddr ) ) continue; if( ( temp->mostInstance == info->mostInstance ) && ( temp->mostConnectionLabel == info->mostConnectionLabel ) && temp->socketsConnected ) { remoteInfo = temp; break; } } } return remoteInfo; }