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