/*! Time-stamp: <@(#)ATDemoMain.cpp   07/05/2007 - 15:46:04   P.Hoogervorst>
 *********************************************************************
 *  @file   : ATDemoMain.cpp
 *
 *  Project : ATPlayRec; Commandline Play and Record application for Alitronika devices.
 *			  Supports Linux and windows operating System.
 *			  
 *			: Devices supported (USB and PCI)
 *				-ATDEMO
 *				-AT20, AT200
 *				-AT30, AT30R1, AT300
 *				-AT4, AT40, AT40X, AT40R1, AT400
 *				-AT70, AT72, AT73, AT700, AT720, AT730
 *				-AT8, AT80, AT82, AT800, AT820, AT1800
 *				-AT660
 *				-AT780
 *				-AT2700, AT2800, AT3800, AT2780, AT2900
 *
 *  Package : 
 *
 *  Company : Engineering Spirit NL
 *
 *  Author  : P.Hoogervorst                              Date: 07/05/2007
 *
 *  Purpose : Implementation of methods for class 
 *
 *********************************************************************
 * Version History:
 *
 * V 0.10  07/05/2007  BN : First Revision
 *
 *********************************************************************
 */

/**********************************************************************************************************/
// operating system specific operations
#ifndef LINUX
#pragma warning (disable : 4996)
#pragma warning (disable : 4005)
#endif

/**********************************************************************************************************/
// includes
#include <stdio.h>
#include <stdlib.h>
#include "ATDemo.h"
#include "Support/getopt.h"
#include "Support/strfunc.h"

/** Action enumeration */
typedef enum {
	None,
	Play,
	Record,
	Init,
} EAction;

/**********************************************************************************************************/
// static functions 

/*!
 * Print some device information
 *
 * @param *pATBoardPlayRec : Pointer to the class that controls the ATBoard
 */
static void PrintDeviceInfo(CATBoardPlayRec *pATBoardPlayRec);
void PrintHelp();
void PrintModHelp();
EAction ProcessCommandline(int argc, char **argv);

char * s_pFilename;

/**********************************************************************************************************/
// Option that are modified by command line parameters

SPlayOpt POptions = 
{
	TRUE,					///< enable bit rate re multiplexing
	0,						///< set file bit rate to 0. This means tsrate determents the bit rate 
	0UL,					///< set output bit rate to 0 bit/s, so the file bitrate will overwrite it.
	1,						///< The play loop count
	-1,						///< Undefined device
};

SRecOpt ROptions =
{
	0UL,					
	60UL					///< record a file of 60secs
};

STunDVBTOpt TunDVBTOptions =
{
	522000000UL,			///< set tuning frequency to 522MHz
	BANDWIDTH_8_7_MHZ,		///< set bandwidth to 8MHz
	FALSE,					///< set bandwidth group selection to 0
	FALSE					///< defaults to old model tuner
};

STunDVBT2Opt TunDVBT2Options =
{
	522000000UL,			///< set tuning frequency to 522MHz
	BANDWIDTH_8_7_MHZ,		///< set bandwidth to 8MHz
	0						///< PLP ID
};

STunDVBSS2Opt TunDVBSS2Options = 
{
	1500000000UL,			///< set tuning frequency to 1500MHz
	22500000UL,				///< set symbol rate to 22.5MSymbols/s
	SEC_TONE_OFF,			///< LNB 22kHz tone enable
	SEC_VOLTAGE_OFF,		///< LNB voltage
	FALSE					///< LNB +1V long cable enable
};

STunDVBCAnnexAOpt TunDVBCAnnexAOptions =
{
	658000000UL,			///< set tuning frequency to 658MHz
	6900000UL,				///< set symbol rate to 6.9MSymbols/s
	INVERSION_AUTO,			///< set inversion selection to AUTO
	QAM_AUTO,				///< set QAM mode selection to AUTO
	FALSE					///< defaults to old model tuner
};

STunDVBCAnnexBOpt TunDVBCAnnexBOptions =
{
	70000000UL,				///< set tuning frequency to 70MHz
	QAM_64					///< set QAM mode selection to QAM64
};

SModDVBTOpt ModDVBTOptions =
{
	TRUE,						///< select RF output
	0UL,						///< if RF is selected, IF output frequency can be 0
	70000000UL,					///< RF output frequency
	-200,						///< -35dBm 
	QAM_64,						///< set qam mode to QAM_64
	TRANSMISSION_MODE_8K,		///< set transmission mode to 8K
	GUARD_INTERVAL_1_32,		///< set guard interval to 1/32
	FEC_7_8,					///< set FEC code rate to 7/8
	BANDWIDTH_8_7_MHZ,			///< set bandwidth to 8MHz
	INVERSION_OFF,				///< set spectral inversion of
	FALSE,						///< disable DVB-H mode
	FALSE,						///< disable DVB-H time slicing
	FALSE,						///< disable DVB-H MPE FEC
	FALSE,						///< disable DVB-H Indepth interleaver.
	0							///< cell ID is zero
};

SModDVBCOpt ModDVBCOptions =
{
	TRUE,						///< select RF output
	0UL,						///< if RF is selected, IF output frequency can be 0
	700000000UL,				///< RF output frequency
	-200,						///< -20dBm 
	QAM_64,						///< set qam mode to QAM_16
	FLT_ALPHA_15,				///< set filter roll off to 15%
	INTLEAV_I12_J17,			///< set interleaver to I12/J17
	INVERSION_OFF,				///< set inversion off
	5500000UL,					///< set symbol rate to 5MSymbols/s
	FALSE						///< disable annex B mode
};

SModDVBS2Opt ModDVBS2Options =
{
	TRUE,						///< selects if RF output is selected or IF output. 1: RF is selected, 0: IF is selected
	0UL,						///< (absolute) IF frequency in Hz for. (ranges: 49-51MHz, 99-101MHz)
	1000000000UL,				///< (absolute) RF frequency in Hz for. (range: 950-2150MHz)
	-20,						///< (absolute) output level for the modulators in 0.1dBm units. (range: -45 to -10dBm in 0.5dBm steps)
	QPSK,						///< modulation type
	FEC_1_2,					///< FEC code rate
	FLT_ALPHA_35,				///< set alpha filter roll off factor
	INVERSION_OFF,				///< spectral inversion selection
	22500000,					///< symbol rate in Symbols per second (1-45MSymbols/s)
	DVBS_MODE_S					///< set dvb mode
};

SModDVBATSCOpt ModDVBATSCOptions =
{
	TRUE,						///< select RF output
	0UL,						///< if RF is selected, IF output frequency can be 0
	70000000UL,					///< RF output frequency
	-200,						///< -20dBm 
	INVERSION_OFF				///< set spectral inversion of
};

/**********************************************************************************************************/

CAtBoardManager *BoardManager = NULL;
CATBoardPlayRec *pATBoardCtrl = NULL;

void SysConsoleHandlersCallBack()
{
	Message(E_VERBOSE_SILENT, "Closing down.......");
  
	if (pATBoardCtrl)
	{
		PlayFileBreak((CATBoardPlayRec*)pATBoardCtrl);
		RecordFileBreak((CATBoardPlayRec*)pATBoardCtrl);
	}
}

// main entrance function
int main (int argc, char **argv)
{
	SetProgramName("ATPlayRec");
	Message(E_VERBOSE_SILENT, "*****************************************************************");

	SysSetupConsoleHandlers();

	// Instantiate the board manager
	BoardManager = CAtBoardManager::Instance ();

#if 0	// For command line parameter testing only.
	memset(&POptions, 0xAA, sizeof(POptions));
	memset(&ROptions, 0xAA, sizeof(ROptions));
	memset(&TunDVBTOptions, 0xAA, sizeof(TunDVBTOptions));
	memset(&TunDVBCAnnexAOptions, 0xAA, sizeof(TunDVBCAnnexAOptions));
	memset(&TunDVBCAnnexBOptions, 0xAA, sizeof(TunDVBCAnnexBOptions));
	memset(&ModDVBTOptions, 0xAA, sizeof(ModDVBTOptions));
	memset(&ModDVBCOptions, 0xAA, sizeof(ModDVBCOptions));
	memset(&ModDVBATSCOptions, 0xAA, sizeof(ModDVBATSCOptions));
#endif

	// decode command line options and do the action
	EAction Action = ProcessCommandline(argc, argv);
	if (Action == None)
	{
		PrintHelp();
		return 1;
	}

	// Get a device list
	CAtDeviceList DeviceList;

	BoardManager->GetDeviceList(DeviceList);

	SBoardOpenParams BoardOpenParams;

	// Set the default board index
	BoardOpenParams.m_BoardPos = POptions.m_DeviceNr;

	// Use the first board found. If none are found, use the demo board.
	if(DeviceList.GetFreeSize() == 0)
	{
		Message(E_VERBOSE_SILENT, "No (free) device(s) found. Using demo board.");

		// set demo board open parameters
		BoardOpenParams.m_BoardPos = -1;
		BoardOpenParams.m_pBoardName = NULL;
	}
	else
	{
		if (POptions.m_DeviceNr < 0)
		{
			if (DeviceList.GetFirstFreeBoard(&BoardOpenParams))
			{
				Message(E_VERBOSE_1, "Connecting to first free board found.");
			}
			else
			{
				Message(E_VERBOSE_SILENT, "No (free) device(s) found. Using demo board.");

				// set demo board open parameters
				BoardOpenParams.m_BoardPos = -1;
				BoardOpenParams.m_pBoardName = NULL;
			}
		}
		else
		{
			BOOL bRet = DeviceList.GetFirstBoard(&BoardOpenParams);

			while(bRet && BoardOpenParams.m_BoardPos!=POptions.m_DeviceNr)
			{
				bRet = DeviceList.GetNextBoard(&BoardOpenParams);
			}

			if (!bRet || !DeviceList.IsBoardFree(&BoardOpenParams))
			{
				Message(E_VERBOSE_SILENT, "Requested device could not be found or is in use. Using demo board.");

				// set demo board open parameters
				BoardOpenParams.m_BoardPos = -1;
				BoardOpenParams.m_pBoardName = NULL;
			}

		}
	}

	const ATDEVICEINFO *pDevInfo = DeviceList.GetDeviceInfo(&BoardOpenParams);

	// Create all board types
	CATBoardPlayRec			ATBoardPlayRec;
	CATBoardTunDVBT			ATBoardTunDVBT;
	CATBoardTunDVBT2		ATBoardTunDVBT2;
	CATBoardTunDVBCAnnexA	ATBoardTunDVBCAnnexA;
	CATBoardTunDVBCAnnexB	ATBoardTunDVBCAnnexB;
	CATBoardModDVBT			ATBoardModDVBT;
	CATBoardModDVBC			ATBoardModDVBC;
	CATBoardModDVBS2		ATBoardModDVBS2;
	CATBoardModDVBATSC		ATBoardModDVBATSC;
	CATBoardTunDVBSS2		ATBoardTunDVBSS2;
	
	BOOL bInit = FALSE;

	Message(E_VERBOSE_1, "Open and initializing board....");

	switch (Action)
	{
	case Play:
		// Initialize optional front-ends
		if (pDevInfo)
		{
			if (pDevInfo->DeviceHasDVB_C_Mod)
			{
				// set DVB-C modulator
				pATBoardCtrl = &ATBoardModDVBC;
				pATBoardCtrl->BoardOpen(BoardOpenParams);
				Message(E_VERBOSE_2, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBC((CATBoardModDVBC *)pATBoardCtrl, ModDVBCOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_T_Mod == TYPE_DVB_T_T)
			{
				// set DVB-T modulator
				pATBoardCtrl = &ATBoardModDVBT;
				pATBoardCtrl->BoardOpen(BoardOpenParams);
				Message(E_VERBOSE_2, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBT((CATBoardModDVBT *)pATBoardCtrl, ModDVBTOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_T_Mod == TYPE_DVB_T_ATSC)
			{
				// set DVB-ATSC modulator
				pATBoardCtrl = &ATBoardModDVBATSC;
				pATBoardCtrl->BoardOpen(BoardOpenParams);
				Message(E_VERBOSE_2, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBATSC((CATBoardModDVBATSC *)pATBoardCtrl, ModDVBATSCOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_S_Mod)
			{
				// set DVB-S/S2 modulator
				pATBoardCtrl = &ATBoardModDVBS2;
				pATBoardCtrl->BoardOpen(BoardOpenParams);
				Message(E_VERBOSE_2, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBS2((CATBoardModDVBS2 *)pATBoardCtrl, ModDVBS2Options))
					goto _CloseBoard;
			}
			else
			{
				pATBoardCtrl = &ATBoardPlayRec;
				pATBoardCtrl->BoardOpen(BoardOpenParams);
				Message(E_VERBOSE_2, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
			}
		}
		else
		{
			pATBoardCtrl = &ATBoardPlayRec;
			pATBoardCtrl->BoardOpen(BoardOpenParams);
			Message(E_VERBOSE_2, "Open and initializing board done");
			PrintDeviceInfo(pATBoardCtrl);
		}

		// Perform the actual play action
		if (pATBoardCtrl && !PlayFile(pATBoardCtrl, s_pFilename, POptions))
			Message(E_VERBOSE_SILENT, "Play terminated with an error");
		break;

	case Init:
		bInit = TRUE;
	case Record:
		if (pDevInfo)
		{
			if (pDevInfo->DeviceHasDVB_C == TYPE_DVB_C_ANNEXA || pDevInfo->DeviceHasDVB_C == TYPE_DVB_C_ANNEXC || pDevInfo->DeviceHasDVB_C == TYPE_DVB_C_ANNEXAC_SONY)
			{
				// set DVB-C tuner annexA,C
				pATBoardCtrl = &ATBoardTunDVBCAnnexA;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (pDevInfo->DeviceHasDVB_C == TYPE_DVB_C_ANNEXAC_SONY)
					TunDVBCAnnexAOptions.m_bIsSonyTuner = TRUE;
				if (!SetTunDVBCAnnexA((CATBoardTunDVBCAnnexA *)pATBoardCtrl, TunDVBCAnnexAOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_C == TYPE_DVB_C_ANNEXB)
			{
				// set DVB-C tuner annexB
				pATBoardCtrl = &ATBoardTunDVBCAnnexB;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetTunDVBCAnnexB((CATBoardTunDVBCAnnexB *)pATBoardCtrl, TunDVBCAnnexBOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_T == TYPE_DVB_T_T || pDevInfo->DeviceHasDVB_T == TYPE_DVB_T_T_SONY)
			{
				// set DVB-T tuner
				pATBoardCtrl = &ATBoardTunDVBT;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (pDevInfo->DeviceHasDVB_T == TYPE_DVB_T_T_SONY)
					TunDVBTOptions.m_bIsSonyTuner = TRUE;
				if (!SetTunDVBT((CATBoardTunDVBT *)pATBoardCtrl, TunDVBTOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_T == TYPE_DVB_T_T2_SONY)
			{
				pATBoardCtrl = &ATBoardTunDVBT2;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				
				if (!SetTunDVBT2((CATBoardTunDVBT2*)pATBoardCtrl, TunDVBT2Options))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_S == TYPE_DVB_S_S2)
			{
				// set DVB-S/S2 tuner
				pATBoardCtrl = &ATBoardTunDVBSS2;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetTunDVBSS2((CATBoardTunDVBSS2 *)pATBoardCtrl, TunDVBSS2Options))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_S == TYPE_DVB_S_S)
			{
				Message(E_VERBOSE_SILENT, "DVB-S tuner not supported");
				goto _Exit;
			}
			else
			if (pDevInfo->DeviceHasDVB_C_Mod)
			{
				// set DVB-T tuner
				pATBoardCtrl = &ATBoardModDVBC;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBC((CATBoardModDVBC *)pATBoardCtrl, ModDVBCOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_T_Mod == TYPE_DVB_T_T)
			{
				// set DVB-T modulator
				pATBoardCtrl = &ATBoardModDVBT;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBT((CATBoardModDVBT *)pATBoardCtrl, ModDVBTOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_T_Mod == TYPE_DVB_T_ATSC)
			{
				// set DVB-ATSC modulator
				pATBoardCtrl = &ATBoardModDVBATSC;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBATSC((CATBoardModDVBATSC *)pATBoardCtrl, ModDVBATSCOptions))
					goto _CloseBoard;
			}
			else
			if (pDevInfo->DeviceHasDVB_S_Mod)
			{
				// set DVB-S/S2 modulator
				pATBoardCtrl = &ATBoardModDVBS2;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_2, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
				if (!SetModDVBS2((CATBoardModDVBS2 *)pATBoardCtrl, ModDVBS2Options))
					goto _CloseBoard;
			}
			else
			{
				pATBoardCtrl = &ATBoardPlayRec;
				pATBoardCtrl->BoardOpen(BoardOpenParams, bInit);
				Message(E_VERBOSE_1, "Open and initializing board done");
				PrintDeviceInfo(pATBoardCtrl);
			}
		}
		else
		{
			pATBoardCtrl = &ATBoardPlayRec;
			pATBoardCtrl->BoardOpen(BoardOpenParams);
			Message(E_VERBOSE_1, "Open and initializing board done");
			PrintDeviceInfo(pATBoardCtrl);
		}

		// Perform the actual record action (only at record mode)
		if (bInit == FALSE)
		{
			if (pATBoardCtrl &&  !RecordFile(pATBoardCtrl, s_pFilename, ROptions))
				Message(E_VERBOSE_SILENT, "Record terminated with an error");
		}
		break;
	}

_CloseBoard:
	// close the board
	pATBoardCtrl->BoardClose();
_Exit:
	return 0;
}

// Print some device information 
static void PrintDeviceInfo(CATBoardPlayRec *pATBoardPlayRec)
{
	CATBoard *pTheBoard = pATBoardPlayRec->GetCurBoard();
	
	char TmpStr[MAX_TMP_STR_LEN];

	// print friendly name
	u32 nLength = ATDEV_INFO_MAX_STR_LEN;
	char * pFriendlyName = new char[nLength];
	pTheBoard->GetFriendlyName(pFriendlyName, nLength);

	sprintf(TmpStr, "Board found: %s", pFriendlyName);
	Message(E_VERBOSE_SILENT, TmpStr);

	if (pFriendlyName)
		delete pFriendlyName;

	// print API version information
	ATVERSIONINFO * pAPIInfo = NULL;
	pAPIInfo = pTheBoard->GetAPIVersion();
	sprintf(TmpStr, "API version %d.%d", pAPIInfo->Mayor, pAPIInfo->Minor);
	Message(E_VERBOSE_2, TmpStr);

	// print driver version information
	ATVERSIONINFO * pDriverInfo = NULL;
	pDriverInfo = pTheBoard->GetDriverVersion();
	
	if(pDriverInfo  != NULL)
	{
		sprintf(TmpStr, "Driver version %d.%d", pDriverInfo->Mayor, pDriverInfo->Minor);
		Message(E_VERBOSE_2, TmpStr);
	}
}


struct CItemValue
{
	const char *Name;
	int			Value;
};

int GetItemValue(const CItemValue *pItem, const char *pstrArg)
{
	while (pItem->Name != NULL)
	{
		if (__stricmp(pItem->Name, pstrArg) == 0)
		{
			return pItem->Value;
		}
		pItem++;
	}
	return -1;
}

const CItemValue FecItems[] =
{
	{	"FEC_1_2",  FEC_1_2	},
	{	"FEC_2_3",  FEC_2_3	},
	{	"FEC_3_4",  FEC_3_4	},
	{	"FEC_4_5",  FEC_4_5	},
	{	"FEC_5_6",  FEC_5_6	},
	{	"FEC_7_8",  FEC_7_8	},
	{	"FEC_8_9",  FEC_8_9	},
	{	"FEC_1_4",  FEC_1_4	},
	{	"FEC_1_3",  FEC_1_3	},
	{	"FEC_2_5",  FEC_2_5	},
	{	"FEC_3_5",  FEC_3_5	},
	{	"FEC_9_10", FEC_9_10},
	{	NULL,		-1		}
};

const CItemValue BandwidthItems[] =
{
	{	"8_MHZ", BANDWIDTH_8_7_MHZ	},
	{	"7_MHZ", BANDWIDTH_7_6_MHZ	},
	{	"6_MHZ", BANDWIDTH_6_MHZ  	},
	{	"5_MHZ", BANDWIDTH_5_MHZ	},
	{	NULL, -1					}
};

const CItemValue ModulationItems[] =
{
	{	"QPSK",		QPSK	},
	{	"QAM_16",	QAM_16	},
	{	"QAM_64",	QAM_64	},
	{	"QAM_32",	QAM_32	},
	{	"QAM_128",	QAM_128	},
	{	"QAM_256",	QAM_256	},
	{	"8PSK",		PSK8	},
	{	"16APSK",	APSK16	},
	{	"32APSK",	APSK32	},
	{	NULL, -1			}
};	

const CItemValue TransmissionModeItems[] =
{
	{	"2K", TRANSMISSION_MODE_2K	},
	{	"4K", TRANSMISSION_MODE_4K	},
	{	"8K", TRANSMISSION_MODE_8K	},
	{	NULL, -1					}
};

const CItemValue GuardItervalItems[] =
{
	{	"4", GUARD_INTERVAL_1_4		},
	{	"8", GUARD_INTERVAL_1_8		},
	{	"16", GUARD_INTERVAL_1_16	},
	{	"32", GUARD_INTERVAL_1_32	},
	{	NULL, -1					}
};

const CItemValue InversionItems[] =
{
	{	"ON", INVERSION_ON		},
	{	"OFF", INVERSION_OFF	},
	{	NULL, -1				}
};

const CItemValue InterleaverItems[] =
{
	{	"I128_J1", INTLEAV_I128_J1	},
	{	"I128_J2", INTLEAV_I128_J2	},
	{	"I128_J3", INTLEAV_I128_J3	},
	{	"I128_J4", INTLEAV_I128_J4	},
	{	"I128_J5", INTLEAV_I128_J5	},
	{	"I128_J6", INTLEAV_I128_J6	},
	{	"I128_J7", INTLEAV_I128_J7	},
	{	"I128_J8", INTLEAV_I128_J8	},
	{	"I64_J2", INTLEAV_I64_J2	},
	{	"I32_J4", INTLEAV_I32_J4	},
	{	"I16_J8", INTLEAV_I16_J8	},
	{	"I8_J16", INTLEAV_I8_J16	},
	{	"I12_J17", INTLEAV_I12_J17	},
	{	NULL, -1							}
};

const CItemValue FilterRollOffItems[] =
{
	{	"12",	FLT_ALPHA_12	},
	{	"13",	FLT_ALPHA_13	},
	{	"15",	FLT_ALPHA_15	},
	{	"18",	FLT_ALPHA_18	},
	{	"20",	FLT_ALPHA_20	},
	{	"25",	FLT_ALPHA_25	},
	{	"35",	FLT_ALPHA_35	},
	{	NULL, -1				}
};

const CItemValue DvbSModeItems[] =
{
	{	"DVB_S",	DVBS_MODE_S		},
	{	"DVB_DSNG",	DVBS_MODE_DSNG	},
	{	"DVB_S2",	DVBS_MODE_S2	},
	{	NULL,		-1				}
};

const CItemValue LNBVoltItems[] =
{
	{	"LNB_VOLT_13",	SEC_VOLTAGE_13	},
	{	"LNB_VOLT_18",	SEC_VOLTAGE_18	},
	{	"LNB_VOLT_OFF",	SEC_VOLTAGE_OFF	},
	{	NULL,			-1				}
};

enum EOptCodes
{
	EOPT_HELP = 'h',
	EOPT_VERBOSE = 'v',
	EOPT_PLAY = 'p',
	EOPT_RECORD = 'r',
	EOPT_LENGTH = 'l',
	EOPT_LOOP = 'c',

	EOPT_FILEBITRATE = 0,
	EOPT_OUTPUTBITRATE, 
	EOPT_SPECTINVERT, 
	EOPT_IFOUT,
	EOPT_FEC,
	EOPT_GUARD,
	EOPT_DVBH,
	EOPT_CELLID,
	EOPT_RFLEVEL,
	EOPT_INTERLEAVE,
	EOPT_INIT,
	EOPT_ANNEXB,
	EOPT_FLTROLLOFF,
	EOPT_DVBSMODE,
	EOPT_LNBTONE,
	EOPT_LNBVOLT,
	EOPT_LNBVOLTHIGH,
	EOPT_PLPID,
	EOPT_TIME,

	EOPT_FREQ = 'f',
	EOPT_SYMBRATE = 's',
	EOPT_MODULATION = 'm',
	EOPT_BANDWIDTH = 'b',
	EOPT_TMODE = 't',
	EOPT_DEVNR = 'd',
};


// Return 'true' is no errors occurred
EAction ProcessCommandline(int argc, char **argv)
{
	// Define the command line options. The string, declared
	// first, contains a list of the short options. The struct
	// contains the long options.
	char * ShortOptions = "h?p:r:l:c:v:f:s:m:b:t:d:";
	static const struct CmdLineOption LongOptions[] =
	{
		// General
		{"help", no_argument, NULL, EOPT_HELP},
		{"verbose", required_argument, NULL, EOPT_VERBOSE},
		// Commands
		{"play", required_argument, NULL, EOPT_PLAY},
		{"record", required_argument, NULL, EOPT_RECORD},
		// Play - Record
		{"f_bitrate", required_argument, NULL, EOPT_FILEBITRATE},
		{"o_bitrate", required_argument, NULL, EOPT_OUTPUTBITRATE},
		{"length", required_argument, NULL, EOPT_LENGTH},
		{"loop", required_argument, NULL, EOPT_LOOP},
		{"time", required_argument, NULL, EOPT_TIME},

		// Other
		{"frequency", required_argument, NULL, EOPT_FREQ},
		{"symbolrate", required_argument, NULL, EOPT_SYMBRATE},
		{"fec", required_argument, NULL, EOPT_FEC},
		{"bandwidth", required_argument, NULL, EOPT_BANDWIDTH},
		{"modulation", required_argument, NULL, EOPT_MODULATION},
		{"tmode", required_argument, NULL, EOPT_TMODE},
		{"guard", required_argument, NULL, EOPT_GUARD},
		{"inversion", required_argument, NULL, EOPT_SPECTINVERT},
		{"DVBH", no_argument, NULL, EOPT_DVBH},
		{"ANNEXB", no_argument, NULL, EOPT_ANNEXB},
		{"fltrolloff", required_argument, NULL, EOPT_FLTROLLOFF},
		{"DvbSMode", required_argument, NULL, EOPT_DVBSMODE},
		{"CellId", required_argument, NULL, EOPT_CELLID},
		{"IF", no_argument, NULL, EOPT_IFOUT},
		{"RFLevel", required_argument, NULL, EOPT_RFLEVEL},
		{"interleaver", required_argument, NULL, EOPT_INTERLEAVE},
		{"device", required_argument, NULL, EOPT_DEVNR},
		{"init", no_argument, NULL, EOPT_INIT},
		{"LNBTone", no_argument, NULL, EOPT_LNBTONE},
		{"LNBVolt", required_argument, NULL, EOPT_LNBVOLT},
		{"LNBHighVolt", no_argument, NULL, EOPT_LNBVOLTHIGH},
		{"PLPID", required_argument, NULL, EOPT_PLPID},
		
		{NULL, no_argument, NULL, 0}
	};

	EAction Action = None;
	char * TunerType = NULL;

	// Parse the arguments passed to the program.
	int NextOption = 0;
	extern int	opterr;
	opterr = 1;

	do
	{
		NextOption = getopt_long(argc, argv, ShortOptions, LongOptions, NULL);
		switch(NextOption)
		{
		case EOPT_HELP:								// Print Help
//			PrintHelp();
			return None;

		case EOPT_PLAY:								// Play mode
			if(Action == None)
			{
				Action = Play;

				if(optarg==NULL)
				{
					Error("No filename specified!");
				}
				s_pFilename = optarg;

				break;
			}
			Error("Play & Record simultaneously not supported!");
			break;

		case EOPT_RECORD:								// Record mode
			if(Action == None)
			{
				Action = Record;

				if(optarg==NULL)
				{
					Error("No filename specified!");
				}
				s_pFilename = optarg;

				break;
			}
			Error("Play & Record simultaneously not supported!");
			break;

		case EOPT_LENGTH:
			if(optarg==NULL)
			{
				Error("recording length (in MByte) not specified!");
			}
			else
				ROptions.m_nFileSize = atoi(optarg); 
			break;

		case EOPT_LOOP:
			if(optarg==NULL)
			{
				Error("Loop count value not specified!");
			}
			else
				POptions.m_loopcount = atoi(optarg); 
			break;

		case EOPT_TIME:
			if(optarg==NULL)
			{
				Error("recording time (in secs) not specified!");
			}
			else
				ROptions.m_nFileTime = atoi(optarg); 
			break;

		case EOPT_VERBOSE:
			if(optarg==NULL)
			{
				Error("Verbose value not specified!");
			}
			else
				SetVerboseLevel((EVerbose)atoi(optarg));
			break;

		case EOPT_FREQ:									// Set frequency
			if(optarg==NULL)
			{
				Error("No frequency specified!");
			}
			TunDVBT2Options.m_nFrequency = 
			TunDVBTOptions.m_nFrequency = 
			TunDVBCAnnexAOptions.m_nFrequency = 
			TunDVBCAnnexBOptions.m_nFrequency = 
			TunDVBSS2Options.m_nFrequency = 
			ModDVBTOptions.m_nRfFrequency = 
			ModDVBS2Options.m_nRfFrequency =
			ModDVBCOptions.m_nRfFrequency = (u32)(1000000 * atof(optarg));
			break;

		case EOPT_FILEBITRATE:					// Set output bitrate
			if(optarg == NULL)
			{
				Error("No file bitrate specified");
			}
			//printf("bitRate %s \n", optarg);
			POptions.m_dFileBitrate = atol(optarg);
			//printf("bitRate %f \n",Options.Bitrate);

			break;

		case EOPT_OUTPUTBITRATE:					// Set output bitrate
			if(optarg == NULL)
			{
				Error("No output bitrate specified");
			}
			//printf("bitRate %s \n", optarg);
			POptions.m_dOutputBitrate = atol(optarg);
			//printf("bitRate %f \n",Options.Bitrate);

			break;

		case EOPT_SYMBRATE:						// Set Symbol rate
			if(optarg==NULL)
			{
				Error("No Symbol rate specified!");
			}
			TunDVBCAnnexAOptions.m_nSymbolRate = 
			TunDVBSS2Options.m_nSymbolRate = 
			ModDVBS2Options.m_nSymbolRate = 
			ModDVBCOptions.m_nSymbolRate = atol(optarg);
			break;

		case EOPT_FEC:							// Set FEC rate
			if ((ModDVBS2Options.m_FECCodeRate = ModDVBTOptions.m_FECCodeRate = (src_code_rate_t)GetItemValue(FecItems, optarg)) < 0)
				Error("No FEC-rate specified!");
			break;

		case EOPT_FLTROLLOFF:
			if ((ModDVBS2Options.m_FltRollOff = (src_filter_rolloff_t)GetItemValue(FilterRollOffItems, optarg)) < 0)
				Error("No rolloff specified!");
			break;

		case EOPT_BANDWIDTH:			//Set bandwidth
			if ((TunDVBT2Options.m_BandWidth = TunDVBTOptions.m_BandWidth = ModDVBTOptions.m_Bandwidth = (src_bandwidth_t)GetItemValue(BandwidthItems, optarg)) < 0)
				Error("No Bandwidth specified!");
			break;

		case EOPT_MODULATION:			//Set modulation
			if ((TunDVBCAnnexAOptions.m_Modulation = TunDVBCAnnexBOptions.m_Modulation = ModDVBS2Options.m_Modulation = ModDVBTOptions.m_Modulation = ModDVBCOptions.m_Modulation = (src_modulation_t)GetItemValue(ModulationItems, optarg)) < 0)
				Error("No modulation specified!");
			break;

		case EOPT_TMODE:				//Set TRANSMISSIONMODE
			if ((ModDVBTOptions.m_TranMode = (src_transmit_mode_t)GetItemValue(TransmissionModeItems, optarg)) < 0)
				Error("No transmission mode specified!");
			break;

		case EOPT_GUARD:				//Set guard interval
			if ((ModDVBTOptions.m_GuardInt = (src_guard_interval_t)GetItemValue(GuardItervalItems, optarg)) < 0)
				Error("No guard interval specified!");
			break;

		case EOPT_SPECTINVERT:			//Set inversion
			if ((ModDVBS2Options.m_Inversion = ModDVBTOptions.m_Inversion = ModDVBCOptions.m_Inversion = TunDVBCAnnexAOptions.m_Invert = (src_spectral_inversion_t)GetItemValue(InversionItems, optarg)) < 0)
			{
				Error("No inversion specified!");
			}
			break;

		case EOPT_DVBH:					//Set DVB-H
			{
				ModDVBTOptions.m_bDvbHEn = TRUE;
			}
			break;

		case EOPT_DVBSMODE:					//Set DVB-S mode (dvb-s, dvb-dsng, dvb-s2
			if ((ModDVBS2Options.m_DvbModeSel = (src_dvbs_mode_t)GetItemValue(DvbSModeItems, optarg)) < 0)
				Error("No DvbSMode specified!");
			break;

		case EOPT_ANNEXB:
			{
				ModDVBCOptions.m_bAnnexBEn = TRUE;
			}
			break;

		case EOPT_CELLID:				//Set DVB-H Cellid
			if (optarg==NULL)
			{
				Error("No dvb_h_cell_id specified!");
			}
			ModDVBTOptions.m_nDvbHCellId = atoi(optarg); 
			break;

		case EOPT_IFOUT:				//Set to IF output
			{
				ModDVBS2Options.m_bRfIfSel = ModDVBTOptions.m_bRfIfSel = ModDVBCOptions.m_bRfIfSel = 0;
			}
			break;

		case EOPT_RFLEVEL:				//Set RF output level
			if (optarg==NULL)
			{
				Error("No RF output specified!");
			}
			ModDVBS2Options.m_iRfoutputLevel = ModDVBTOptions.m_iRfoutputLevel = ModDVBCOptions.m_iRfoutputLevel = (s32)(10 * atof(optarg));
			break;

		case EOPT_INTERLEAVE:				//Set interleaver
			if ((ModDVBCOptions.m_Interleaver = (src_interleaver_t)GetItemValue(InterleaverItems, optarg)) < 0)
			{
				Error("No interleaver specified!");
			}
			break;

		case EOPT_DEVNR:
			if (optarg==NULL)
			{
				Error("No device number specified");
			}
			else
			{
				POptions.m_DeviceNr = atoi(optarg);
			}
			break;

		case EOPT_INIT:
			{
				Action = Init;
			}
			break;

		case EOPT_LNBTONE:
			{
				TunDVBSS2Options.m_LNBTone = (src_sec_tone_mode_t)SEC_TONE_ON;
			}
			break;
		case EOPT_LNBVOLT:
			{
				if ((TunDVBSS2Options.m_LNBVolt = (src_sec_voltage_t)GetItemValue(LNBVoltItems, optarg)) < 0)
					Error("LNB voltage not specified!");
			}
			break;
		case EOPT_LNBVOLTHIGH:
			{
				TunDVBSS2Options.m_LNBHighVolt = TRUE;
			}
			break;

		case EOPT_PLPID:
			if (optarg==NULL)
			{
				Error("No PLP ID specified!");
			}
			else
			{
				TunDVBT2Options.m_nPLPId = atoi(optarg);
			}
			break;

		case -1:								// End of list
			break;

		case '?':								// Unknown option
		default:								// Unexpected error
			Message(E_VERBOSE_SILENT, "  @@@ Incorrect command line option\n");
//			PrintHelp();
			return None;
		}
	}
	while(NextOption != -1);

	return Action;
}


void ListDevices()
{
	SBoardOpenParams BoardOpenParams;

	CAtDeviceList DeviceList;
	BoardManager->GetDeviceList(DeviceList);

	printf("Connected devices\n");

	if (DeviceList.GetFirstBoard(&BoardOpenParams))
	{
		do 
		{
			BOOL bIsFree = DeviceList.IsBoardFree(&BoardOpenParams);
			printf("%2d : %s \t(%s)\n", BoardOpenParams.m_BoardPos, DeviceList.GetFriendlyName(&BoardOpenParams), bIsFree ? "Available" : "In use");
		}
		while(DeviceList.GetNextBoard(&BoardOpenParams));
	}
	printf("\n");
}

#define LINEOPT(a)	" " a "\n"
#define LINEDESC(a)	"\t\t" a "\n"

//
//	test command lines:
//	-p d:\ts\TT1.ts --bitrate 35000000 --frequency 500 --symbolrate 30000000 --RFLevel -5.5 --bandwidth 7_MHz --modulation QAM_16 --tmode 4K --fec FEC_2_3 --guard 4 --inversion ON --interleaver I128_J3 --IF --DVBH --CellId 2048 -l 33
//	-r  d:\ts\rec_test.ts -l 36
//

void PrintHelp()
{
	const char *ProgName = GetProgramName();

	printf("%s is a program for performing basic operations on the Alitronika\n", ProgName);
	printf("ASI input/output, DVB Receivers and Modulator devices.\n");
	printf("Features: Play from a transport stream file\n");
	printf("          Record to a file.\n\n");

	ListDevices();

	printf("Help on command line options:\n");
	printf("\t1: Play\n");
	printf("\t2: Record\n");
	printf("\t3: Modulator settings\n");
	printf("\t4: Receiver settings\n");
	printf("\t9: exit\n");

	bool bRepeat = true;

	while (bRepeat)
	{
		printf("\r==> ");
		int Ch = getchar();
		const char *pText = NULL;

		switch(Ch)
		{
		case '1':	// Play
			{
				pText =
					"ASI Play\n"
					LINEOPT("-p, --play\t<filename>")
					LINEDESC("Play a file to ASI output.")
					LINEOPT("--f_bitrate\t<bitrate>")
					LINEDESC("File Bitrate in Bits/sec (ex. 14900000).")
					"             \t\t\tIf omitted, the file's measured bitrate is used.\n"
					LINEOPT("--o_bitrate\t<bitrate>")
					LINEDESC("Output Bitrate in Bits/sec (ex. 16000000)")
					LINEOPT("-c, --loop\t<count> (ex. --loop 2)")
					LINEDESC("Play file looping count.")
					LINEOPT("--device\t<DevNr> (ex. --device 0)")
					LINEDESC("Specify the index number of the device.")
					LINEOPT("-v")
					LINEDESC("Verbose level 0~4, 0: Silent, 4: Screaming.")
					"\n"
					"Example:\n %s --play teststream.ts --o_bitrate 16000000 -c 10\n"
					;
			}
			break;

		case '2':	// Record
			{
				pText =
					"ASI Record\n"
					LINEOPT("-r, --record\t<filename>")
					LINEDESC("Record ASI input to a file")
					LINEOPT("-l, --length\t<nr of MB>")
					LINEDESC("Record file length. 0 (or option not used) is infinite")
					LINEOPT("--time\t<nr of secs>")
					LINEDESC("Record file time. 0 (or option not used) is infinite")
					LINEDESC("If both file length option and file time option are specified,")
					LINEDESC("the first one that expires stops the recording.")
					LINEOPT("--device\t<DevNr> (ex. --device 0)")
					LINEDESC("Specify the index number of the device.")
					LINEOPT("-v")
					LINEDESC("Verbose level 0~4, 0: Silent, 4: Screaming.")
					"\n"
					"Example:\n %s --record teststream.ts --length 50\n"
					;
			}
			break;

		case '3':	// Modulate
			{
				pText =
					"Modulation\n"
					LINEOPT("-p, --play\t<filename>")
					LINEDESC("Play a file to the Modulator")
					LINEOPT("-f, --frequency\t<Freq>")
					LINEDESC("RF Frequency in MHz (ex. 107.45)")
					LINEOPT("-s, --symbolrate\t<MSym/sec>")
					LINEDESC("Nr of Symbols/sec (ex. 5457800)")
					LINEOPT("--RFLevel\t<Level in dB>")
					LINEDESC("RF level: DVBC, DVBT: -35.0 ~ 2.0; DVBS2: -45.0 ~ -10; in 0.5dB steps (ex. -9.5)")
					LINEOPT("--IF")
					LINEDESC("Enable IF output and disable RF output")
					LINEOPT("--ANNEXB")
					LINEDESC("Enable DVBC modulator AnnexB mode")
					LINEOPT("-b, --bandwidth\t<BW>")
					LINEDESC("Bandwidth in Megahertz:")
					LINEDESC("8_MHz, 7_MHz, 6_MHz, 5_MHz")
					LINEOPT("-m, --modulation\t<mod type>")
					LINEDESC("Modulation type:")
					LINEDESC("QPSK, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256, 8PSK, 16APSK, 32APSK")
					LINEOPT("-t, --tmode\t<mode>")
					LINEDESC("Transmission mode: 2K, 4K, 8K")
					LINEOPT("--fec\t\t<fec rate>\tForward error correction:")
					LINEDESC("FEC_1_2, FEC_2_3, FEC_3_4, FEC_4_5, FEC_5_6, FEC_7_8")
					LINEDESC("FEC_8_9, FEC_1_4, FEC_1_3, FEC_2_5, FEC_3_5, FEC_9_10")
					LINEOPT("--guard\t<1/interval>")
					LINEDESC("1/n Interval: 4, 8, 16, 32")
					LINEOPT("--fltrolloff\t<rolloff>")
					LINEDESC("rolloff: 12, 13, 15, 18, 20, 25, 35")
					LINEOPT("--inversion\t<ON/OFF>")
					LINEDESC("Use spectral inversion: ON, OFF")
					LINEOPT("--interleaver\t<interleaving>")
					LINEDESC("Interleaver setting:")
					LINEDESC("I128_J1, I64_J2, I32_J4, I16_J8, I8_J16, I12_J17")
					LINEOPT("--DVBH")
					LINEDESC("Enable DVB-H mode")
					LINEOPT("--DvbSMode\t<DvbSMode>")
					LINEDESC("Select DVB-S mode: DVB_S, DVB_DSNG, DVB_S2")
					LINEOPT("--CellId\t<cell ID>")
					LINEDESC("DVB-H Cell ID (ex. 16462)")
					LINEOPT("--device\t<DevNr> (ex. --device 0)")
					LINEDESC("Specify the index number of the device.")
					LINEOPT("-v")
					LINEDESC("Verbose level 0~4, 0: Silent, 4: Screaming.")
					"\n"
					"Example DVB-T:\n %s --play teststream.ts --frequency 500.0 --RFLevel -20 --modulation QAM_64 --bandwidth 8_MHz  --guard 32 --tmode 8K --fec FEC_7_8 --inversion OFF\n"
					"Example DVB-H:\n %s --play teststream.ts  --DVBH --frequency 500.0 --RFLevel -20 --modulation QAM_64 --bandwidth 8_MHz  --guard 32 --tmode 4K --fec FEC_7_8 --inversion OFF\n"
					"Example DVB-ATSC:\n %s --play teststream.ts --frequency 500.0 --RFLevel -20 --inversion OFF\n"
					"Example DVB-C annexA:\n %s --play teststream.ts --frequency 500 --RFLevel -20 --modulation QAM_64 --symbolrate 6900000 --inversion OFF\n"
					"Example DVB-C annexB:\n %s --play teststream.ts --ANNEXB --frequency 500 --RFLevel -20 --modulation QAM_64 --interleaver I128_J1 --inversion OFF\n"
					"Example DVB-S:\n %s --play teststream.ts --DvbSMode DVB_S --frequency 1000 --RFLevel -20 --modulation QPSK --fec FEC_1_2 --fltrolloff 35 --symbolrate 22500000 --inversion OFF\n"
					"Example DVB-DSNG:\n %s --play teststream.ts --DvbSMode DVB_DSNG --frequency 1000 --RFLevel -20 --modulation QPSK --fec FEC_1_2 --fltrolloff 35 --symbolrate 22500000 --inversion OFF\n"
					"Example DVB-S2:\n %s --play teststream.ts --DvbSMode DVB_S2 --frequency 1000 --RFLevel -20 --modulation QPSK --fec FEC_1_2 --fltrolloff 35 --symbolrate 22500000 --inversion OFF\n"
					;
			}
		    break;

		case '4':	// Receive
			{
				pText =
					"Receiving\n"
					LINEOPT("-r, --record\t<filename>")
					LINEDESC("Record receiver input to a file")
					LINEOPT("-l, --length\t<nr of MB>")
					LINEDESC("Record file length. 0 (or option not used) is infinite")
					LINEOPT("--time\t<nr of secs>")
					LINEDESC("Record file time. 0 (or option not used) is infinite")
					LINEDESC("If both file length option and file time option are specified,")
					LINEDESC("the first one that expires stops the recording.")
					LINEOPT("--frequency\t<Freq>")
					LINEDESC("RF Frequency in MHz (ex. 107.45)")
					LINEOPT("--symbolrate\t<MSym/sec>")
					LINEDESC("Nr of Symbols/sec (ex. 5457800)")
					LINEOPT("--bandwidth\t<BW>")
					LINEDESC("Bandwidth in Megahertz:")
					LINEDESC("8_MHz, 7_MHz, 6_MHz, 5_MHz")
					LINEOPT("--inversion\t<ON/OFF>")
					LINEDESC("Use spectral inversion: ON, OFF")
					LINEOPT("--modulation\t<mod type>")
					LINEDESC("Modulation type:")
					LINEDESC("QPSK, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256")
					LINEOPT("--LNBTone")
					LINEDESC("LNB Enable 22kHz Tone")
					LINEOPT("--LNBVolt")
					LINEDESC("Set LNB voltage: LNB_VOLT_OFF, LNB_VOLT_13, LNB_VOLT_18")
					LINEOPT("--LNBHighVolt")
					LINEDESC("LNB Enable +1V for lang cable compensation")
					LINEOPT("--device\t<DevNr> (ex. --device 0)")
					LINEDESC("Specify the index number of the device.")
					LINEOPT("--PLPID\t<PlpID> (ex. --PLPID 0)")
					LINEDESC("Specify PLP ID number. (DVB T2 mode only)")
					LINEOPT("-v")
					LINEDESC("Verbose level 0~4, 0: Silent, 4: Screaming.")
					"\n"
					"Example DVB-T:\n \t%s --record teststream.ts --length 50 --frequency 522.0 --bandwidth 8_MHz\n"
					"Example DVB-C annexA:\n \t%s --record teststream.ts --length 50 --frequency 658.0 --symbolrate 6900000\n"
					"Example DVB-C annexB:\n \t%s --record teststream.ts --length 50 --frequency 658.0 --modulation QAM_64\n"
					"Example DVB-S/S2:\n \t%s --record teststream.ts --length 50 --frequency 1500.0 --symbolrate 22500000 --LNBTone --LNBHighVolt --LNBVolt LNB_VOLT_18\n"
					"Example DVB-T2:\n \t%s --record teststream.ts --length 50 --frequency 522.0 --bandwidth 8_MHz --PLPID 0\n"
					;
			}
		    break;

		case '\n':
		case '\r':
			break;

		default:
			bRepeat = false;
		    break;
		}
		if (pText)
			printf(pText, ProgName, ProgName, ProgName, ProgName, ProgName, ProgName, ProgName, ProgName);
	}
}
