/***************************************************************************
* Copyright ( C ) 2005 - 2007 Nicolas Hadacek < hadacek @ kde . org > *
* *
* 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 . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "cmdline.h"
# if defined(HAVE_READLINE)
# include <readline / readline.h>
# include <readline / history.h>
# else
# include <stdio.h>
# endif
# include <signal.h>
# include <tqtimer.h>
# include "devices/list/device_list.h"
# include "devices/base/device_group.h"
# include "common/global/about.h"
# include "progs/base/prog_config.h"
# include "progs/base/hardware_config.h"
# include "devices/pic/pic/pic_memory.h"
# include "devices/pic/prog/pic_prog.h"
# include "progs/list/prog_list.h"
# include "common/cli/cli_log.h"
# include "cli_prog_manager.h"
# include "cli_debug_manager.h"
//-----------------------------------------------------------------------------
const CLI : : CommandData CLI : : NORMAL_COMMAND_DATA [ ] = {
{ " connect " , NeedProgrammer | NeedDevice ,
I18N_NOOP ( " Connect programmer. " ) } ,
{ " run " , NeedProgrammer | NeedDevice ,
I18N_NOOP ( " Run device (release reset). " ) } ,
{ " stop " , NeedProgrammer | NeedDevice ,
I18N_NOOP ( " Stop device (hold reset). " ) } ,
{ " program " , NeedProgrammer | InputHex | NeedDevice ,
I18N_NOOP ( " Program device memory: \" program <hexfilename> \" . " ) } ,
{ " verify " , NeedProgrammer | InputHex | NeedDevice ,
I18N_NOOP ( " Verify device memory: \" verify <hexfilename> \" . " ) } ,
{ " read " , NeedProgrammer | OutputHex | NeedDevice ,
I18N_NOOP ( " Read device memory: \" read <hexfilename> \" . " ) } ,
{ " erase " , NeedProgrammer | NeedDevice ,
I18N_NOOP ( " Erase device memory. " ) } ,
{ " blank_check " , NeedProgrammer | NeedDevice ,
I18N_NOOP ( " Blank check device memory. " ) } ,
{ " upload_firmware " , NeedProgrammer | InputHex ,
I18N_NOOP ( " Upload firmware to programmer: \" upload_firmware <hexfilename> \" . " ) } ,
{ 0 , NoCommandProperty , 0 }
} ;
const KCmdLineOptions CLI : : OPTIONS [ ] = {
{ " r " , 0 , 0 } ,
{ " range <name> " , I18N_NOOP ( " Memory range to operate on. " ) , 0 } ,
{ " range-list " , I18N_NOOP ( " Return the list of memory ranges. " ) , 0 } ,
KCmdLineLastOption
} ;
//-----------------------------------------------------------------------------
const Programmer : : Group * CLI : : _progGroup = 0 ;
const Device : : Data * CLI : : _device = 0 ;
HexBuffer : : Format CLI : : _format = HexBuffer : : IHX32 ;
TQString CLI : : _port , CLI : : _targetSelfPowered , CLI : : _hardware ;
PURL : : Directory CLI : : _firmwareDir ;
PURL : : Url CLI : : _hexUrl , CLI : : _coffUrl ;
Device : : Memory * CLI : : _memory = 0 ;
CLI : : Interactive * CLI : : _interactive = 0 ;
//-----------------------------------------------------------------------------
CLI : : ExitCode CLI : : Main : : formatList ( )
{
log ( Log : : LineType : : Normal , i18n ( " Supported hex file formats: " ) ) ;
for ( uint i = 0 ; i < HexBuffer : : Nb_Formats ; i + + )
log ( Log : : LineType : : Normal , TQString ( " " ) + HexBuffer : : FORMATS [ i ] ) ;
return OK ;
}
CLI : : ExitCode CLI : : Main : : programmerList ( )
{
log ( Log : : LineType : : Normal , i18n ( " Supported programmers: " ) ) ;
Programmer : : Lister : : ConstIterator it ;
for ( it = Programmer : : lister ( ) . begin ( ) ; it ! = Programmer : : lister ( ) . end ( ) ; it + + )
log ( Log : : LineType : : Normal , " " + TQString ( it . data ( ) - > name ( ) ) ) ;
return OK ;
}
CLI : : ExitCode CLI : : Main : : hardwareList ( )
{
log ( Log : : LineType : : Normal , i18n ( " Supported hardware configuration for programmers: " ) ) ;
Programmer : : Lister : : ConstIterator it ;
for ( it = Programmer : : lister ( ) . begin ( ) ; it ! = Programmer : : lister ( ) . end ( ) ; it + + ) {
: : Hardware : : Config * config = it . data ( ) - > hardwareConfig ( ) ;
if ( config = = 0 ) continue ;
FOR_EACH ( PortType , type ) {
if ( ! it . data ( ) - > isPortSupported ( type ) ) continue ;
log ( Log : : LineType : : Normal , " - " + TQString ( it . data ( ) - > name ( ) ) + " [ " + type . label ( ) + " ]: " ) ;
TQStringList list = config - > hardwareNames ( type ) ;
for ( uint k = 0 ; k < uint ( list . count ( ) ) ; k + + ) log ( Log : : LineType : : Normal , " " + list [ k ] ) ;
}
delete config ;
}
return OK ;
}
CLI : : ExitCode CLI : : Main : : deviceList ( )
{
TQValueVector < TQString > devices ;
if ( _progGroup = = 0 ) {
log ( Log : : LineType : : Normal , i18n ( " Supported devices: " ) ) ;
devices = Programmer : : lister ( ) . supportedDevices ( ) ;
} else {
log ( Log : : LineType : : Normal , i18n ( " Supported devices for \" %1 \" : " ) . tqarg ( _progGroup - > label ( ) ) ) ;
devices = _progGroup - > supportedDevices ( ) ;
}
qHeapSort ( devices ) ;
TQString s ;
for ( uint i = 0 ; i < uint ( devices . count ( ) ) ; i + + ) s + = " " + devices [ i ] ;
log ( Log : : LineType : : Normal , s + " \n " ) ;
return OK ;
}
CLI : : ExitCode CLI : : Main : : portList ( )
{
if ( _progGroup ) log ( Log : : LineType : : Normal , i18n ( " Detected ports supported by \" %1 \" : " ) . tqarg ( _progGroup - > label ( ) ) ) ;
else log ( Log : : LineType : : Normal , i18n ( " Detected ports: " ) ) ;
FOR_EACH ( PortType , type ) {
if ( _progGroup & & ! _progGroup - > isPortSupported ( type ) ) continue ;
TQString s = " - " + type . label ( ) + " : " ;
if ( ! Port : : isAvailable ( type ) ) {
log ( Log : : LineType : : Normal , s + i18n ( " support disabled. " ) ) ;
continue ;
}
TQStringList list = Port : : probedDeviceList ( type ) ;
if ( list . count ( ) = = 0 ) log ( Log : : LineType : : Normal , s + i18n ( " no port detected. " ) ) ;
else {
log ( Log : : LineType : : Normal , s ) ;
for ( uint k = 0 ; k < uint ( list . count ( ) ) ; k + + ) log ( Log : : LineType : : Normal , " " + list [ k ] ) ;
}
}
return OK ;
}
CLI : : ExitCode CLI : : Main : : rangeList ( )
{
log ( Log : : LineType : : Normal , i18n ( " Memory ranges for PIC/dsPIC devices: " ) ) ;
FOR_EACH ( Pic : : MemoryRangeType , type ) log ( Log : : LineType : : Normal , TQString ( " %1 " ) . tqarg ( type . key ( ) ) ) ;
return OK ;
}
CLI : : ExitCode CLI : : Main : : prepareCommand ( const TQString & command )
{
const CommandData * data = findCommandData ( command ) ;
CommandProperties properties = static_cast < CommandProperties > ( data - > properties ) ;
if ( _device = = 0 & & ( properties & NeedDevice ) ) return errorExit ( i18n ( " Device not specified. " ) , ARG_ERROR ) ;
if ( _progGroup = = 0 & & ( properties & NeedProgrammer ) ) return errorExit ( i18n ( " Programmer not specified. " ) , ARG_ERROR ) ;
if ( ( properties & InputHex ) | | ( properties & OutputHex ) ) {
if ( _hexUrl . isEmpty ( ) ) return errorExit ( i18n ( " Hex filename not specified. " ) , ARG_ERROR ) ;
//if ( !_filename.isLocalFile() ) return errorExit(i18n("Only local files are supported."), ARG_ERROR);
PURL : : File file ( _hexUrl , * _view ) ;
delete _memory ;
_memory = 0 ;
if ( properties & NeedDevice ) _memory = _device - > group ( ) . createMemory ( * _device ) ;
if ( properties & InputHex ) {
if ( _memory ) {
if ( ! file . openForRead ( ) ) return FILE_ERROR ;
TQStringList errors , warnings ;
Device : : Memory : : WarningTypes warningTypes ;
if ( ! _memory - > load ( file . stream ( ) , errors , warningTypes , warnings ) )
return errorExit ( i18n ( " Could not load hex file \" %1 \" . " ) . tqarg ( errors [ 0 ] ) , FILE_ERROR ) ;
if ( warningTypes ! = Device : : Memory : : NoWarning )
log ( Log : : LineType : : Warning , i18n ( " Hex file seems incompatible with device \" %1 \" . " ) . tqarg ( warnings . join ( " " ) ) ) ;
}
} else if ( properties & OutputHex ) {
if ( ! _force & & _hexUrl . exists ( ) ) return errorExit ( i18n ( " Output hex filename already exists. " ) , FILE_ERROR ) ;
}
}
return OK ;
}
CLI : : Main : : Main ( )
: MainBase ( HasForce | HasInteractiveMode )
{
_range = new Device : : MemoryRange ;
Programmer : : manager = new Programmer : : CliManager ( this ) ;
Programmer : : manager - > setView ( _view ) ;
Debugger : : manager = new Debugger : : CliManager ;
}
CLI : : Main : : ~ Main ( )
{
delete _range ;
}
CLI : : ExitCode CLI : : Main : : list ( const TQString & command )
{
if ( MainBase : : list ( command ) = = OK ) return OK ;
if ( command = = " format-list " ) return formatList ( ) ;
if ( command = = " programmer-list " ) return programmerList ( ) ;
if ( command = = " hardware-list " ) return hardwareList ( ) ;
if ( command = = " port-list " ) return portList ( ) ;
if ( command = = " device-list " ) return deviceList ( ) ;
if ( command = = " range-list " ) return rangeList ( ) ;
Q_ASSERT ( false ) ;
return OK ;
}
CLI : : ExitCode CLI : : Main : : prepareRun ( bool & interactive )
{
// argument
if ( _args - > count ( ) > 1 ) return errorExit ( i18n ( " Too many arguments. " ) , ARG_ERROR ) ;
if ( _args - > count ( ) = = 1 ) {
PURL : : Url url ( _args - > url ( 0 ) ) ;
ExitCode code = OK ;
if ( url . fileType ( ) = = PURL : : Hex ) code = executeSetCommand ( " hex " , url . filepath ( ) ) ;
else if ( url . fileType ( ) = = PURL : : Coff ) code = executeSetCommand ( " coff " , url . filepath ( ) ) ;
else return errorExit ( i18n ( " Argument file type not recognized. " ) , ARG_ERROR ) ;
if ( code ! = OK ) return code ;
}
interactive = _args - > isSet ( " cli " ) ;
if ( interactive ) {
_interactive = new Interactive ( this ) ;
log ( Log : : LineType : : Normal , i18n ( " Interactive mode: type help for help " ) ) ;
log ( Log : : LineType : : Normal , TQString ( ) ) ;
return ExitCode ( tqApp - > exec ( ) ) ;
}
// range
if ( _args - > isSet ( " range-list " ) ) return list ( " range-list " ) ;
ExitCode code = extractRange ( _args - > getOption ( " range " ) ) ;
if ( code ! = OK ) return code ;
return OK ;
}
CLI : : ExitCode CLI : : Main : : extractRange ( const TQString & range )
{
delete _range ;
_range = 0 ;
if ( ! range . isEmpty ( ) ) {
if ( _device = = 0 ) return errorExit ( i18n ( " Cannot specify range without specifying device. " ) , ARG_ERROR ) ;
if ( _device - > group ( ) . name ( ) = = " pic " ) {
FOR_EACH ( Pic : : MemoryRangeType , type ) {
if ( range ! = type . key ( ) ) continue ;
if ( ! static_cast < const Pic : : Data * > ( _device ) - > isReadable ( type ) ) return errorExit ( i18n ( " Memory range not present on this device. " ) , ARG_ERROR ) ;
_range = new Pic : : MemoryRange ( type ) ;
break ;
}
if ( _range = = 0 ) return errorExit ( i18n ( " Memory range not recognized. " ) , ARG_ERROR ) ;
} else return errorExit ( i18n ( " Memory ranges are not supported for the specified device. " ) , ARG_ERROR ) ;
} else _range = new Device : : MemoryRange ;
return OK ;
}
CLI : : ExitCode CLI : : Main : : executeCommand ( const TQString & command )
{
Programmer : : Base * programmer = Programmer : : manager - > programmer ( ) ;
if ( command = = " connect " ) return ( Programmer : : manager - > connectDevice ( ) ? OK : EXEC_ERROR ) ;
if ( command = = " disconnect " ) {
if ( programmer = = 0 | | programmer - > state ( ) = = Programmer : : NotConnected )
return okExit ( i18n ( " Programmer is already disconnected. " ) ) ;
return ( Programmer : : manager - > disconnectDevice ( ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " run " ) {
if ( programmer & & programmer - > state ( ) = = Programmer : : Running ) return okExit ( i18n ( " Programmer is already running. " ) ) ;
return ( Programmer : : manager - > run ( ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " stop " ) {
if ( programmer & & programmer - > state ( ) ! = Programmer : : Running ) return okExit ( i18n ( " Programmer is already stopped. " ) ) ;
return ( Programmer : : manager - > halt ( ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " step " ) {
if ( ! _progGroup - > isDebugger ( ) ) return errorExit ( i18n ( " Debugging is not supported for specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
if ( programmer & & programmer - > state ( ) = = Programmer : : Running ) return ( Programmer : : manager - > halt ( ) ? OK : EXEC_ERROR ) ;
return ( Programmer : : manager - > step ( ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " start " ) {
if ( ! _progGroup - > isDebugger ( ) ) return errorExit ( i18n ( " Debugging is not supported for specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
return ( Programmer : : manager - > restart ( ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " program " ) {
if ( _progGroup - > isSoftware ( ) ) return errorExit ( i18n ( " Reading device memory not supported for specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
return ( Programmer : : manager - > program ( * _memory , * _range ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " verify " ) {
if ( _progGroup - > isSoftware ( ) )
return errorExit ( i18n ( " Reading device memory not supported for specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
return ( Programmer : : manager - > verify ( * _memory , * _range ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " read " ) {
if ( _progGroup - > isSoftware ( ) )
return errorExit ( i18n ( " Reading device memory not supported for specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
if ( ! Programmer : : manager - > read ( * _memory , * _range ) ) return EXEC_ERROR ;
PURL : : File file ( _hexUrl , * _view ) ;
if ( ! file . openForWrite ( ) ) return FILE_ERROR ;
if ( ! _memory - > save ( file . stream ( ) , _format ) )
return errorExit ( i18n ( " Error while writing file \" %1 \" . " ) . tqarg ( _hexUrl . pretty ( ) ) , FILE_ERROR ) ;
return OK ;
}
if ( command = = " erase " ) {
if ( _progGroup - > isSoftware ( ) )
return errorExit ( i18n ( " Erasing device memory not supported for specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
return ( Programmer : : manager - > erase ( * _range ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " blank_check " ) {
if ( _progGroup - > isSoftware ( ) )
return errorExit ( i18n ( " Blank-checking device memory not supported for specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
return ( Programmer : : manager - > blankCheck ( * _range ) ? OK : EXEC_ERROR ) ;
}
if ( command = = " upload_firmware " ) {
if ( ! ( _progGroup - > properties ( ) & : : Programmer : : CanUploadFirmware ) )
return errorExit ( i18n ( " Uploading firmware is not supported for the specified programmer. " ) , NOT_SUPPORTED_ERROR ) ;
if ( Programmer : : manager - > programmer ( ) = = 0 ) Programmer : : manager - > createProgrammer ( 0 ) ; // no device specified
return ( Programmer : : manager - > programmer ( ) - > uploadFirmware ( _hexUrl ) ? OK : EXEC_ERROR ) ;
}
Q_ASSERT ( false ) ;
return EXEC_ERROR ;
}
CLI : : ExitCode CLI : : Main : : checkProgrammer ( )
{
if ( _progGroup = = 0 ) return OK ;
if ( _progGroup - > isSoftware ( ) & & _progGroup - > supportedDevices ( ) . isEmpty ( ) )
return errorExit ( i18n ( " Please check installation of selected software debugger. " ) , NOT_SUPPORTED_ERROR ) ;
if ( _device & & ! _progGroup - > isSupported ( _device - > name ( ) ) )
return errorExit ( i18n ( " The selected device \" %1 \" is not supported by the selected programmer. " ) . tqarg ( _device - > name ( ) ) , NOT_SUPPORTED_ERROR ) ;
if ( ! _hardware . isEmpty ( ) ) {
: : Hardware : : Config * config = _progGroup - > hardwareConfig ( ) ;
Port : : Description pd = static_cast < Programmer : : CliManager * > ( Programmer : : manager ) - > portDescription ( ) ;
bool ok = ( config = = 0 | | config - > hardwareNames ( pd . type ) . tqcontains ( _hardware ) ) ;
delete config ;
if ( ! ok ) return errorExit ( i18n ( " The selected programmer does not supported the specified hardware configuration ( \" %1 \" ). " ) . tqarg ( _hardware ) , NOT_SUPPORTED_ERROR ) ;
}
return OK ;
}
CLI : : ExitCode CLI : : Main : : executeSetCommand ( const TQString & property , const TQString & value )
{
if ( property = = " programmer " ) {
_progGroup = 0 ;
if ( value . isEmpty ( ) ) return OK ;
_progGroup = Programmer : : lister ( ) . group ( value . lower ( ) ) ;
if ( _progGroup ) return checkProgrammer ( ) ;
return errorExit ( i18n ( " Unknown programmer \" %1 \" . " ) . tqarg ( value . lower ( ) ) , ARG_ERROR ) ;
}
if ( property = = " hardware " ) { _hardware = value ; return OK ; }
if ( property = = " device " | | property = = " processor " ) {
if ( value . isEmpty ( ) ) {
_device = 0 ;
return OK ;
}
TQString s = value . upper ( ) ;
_device = Device : : lister ( ) . data ( s ) ;
Debugger : : manager - > updateDevice ( ) ;
if ( _device = = 0 ) return errorExit ( i18n ( " Unknown device \" %1 \" . " ) . tqarg ( s ) , ARG_ERROR ) ;
Debugger : : manager - > init ( ) ;
return checkProgrammer ( ) ;
}
if ( property = = " format " ) {
if ( value . isEmpty ( ) ) {
_format = HexBuffer : : IHX32 ;
return OK ;
}
TQString s = value . lower ( ) ;
for ( uint i = 0 ; i < HexBuffer : : Nb_Formats ; i + + )
if ( s = = HexBuffer : : FORMATS [ i ] ) {
_format = HexBuffer : : Format ( i ) ;
return OK ;
}
return errorExit ( i18n ( " Unknown hex file format \" %1 \" . " ) . tqarg ( s ) , ARG_ERROR ) ;
}
if ( property = = " port " ) { _port = value ; return OK ; }
if ( property = = " firmware-dir " ) { _firmwareDir = value ; return OK ; }
if ( property = = " target-self-powered " ) { _targetSelfPowered = value . lower ( ) ; return OK ; }
if ( property = = " hex " ) {
PURL : : Url url = PURL : : Url : : fromPathOrUrl ( value ) ;
if ( url . isRelative ( ) ) _hexUrl = PURL : : Url ( runDirectory ( ) , value ) ;
else _hexUrl = url ;
return OK ;
}
if ( property = = " coff " ) {
PURL : : Url url = PURL : : Url : : fromPathOrUrl ( value ) ;
if ( url . isRelative ( ) ) _coffUrl = PURL : : Url ( runDirectory ( ) , value ) ;
else _coffUrl = url ;
if ( _device & & ! Debugger : : manager - > init ( ) ) return ARG_ERROR ;
return OK ;
}
return errorExit ( i18n ( " Unknown property \" %1 \" " ) . tqarg ( property ) , ARG_ERROR ) ;
}
TQString CLI : : Main : : executeGetCommand ( const TQString & property )
{
if ( property = = " programmer " ) {
if ( _progGroup = = 0 ) return i18n ( " <not set> " ) ;
return _progGroup - > name ( ) ;
}
if ( property = = " hardware " ) {
if ( ! _hardware . isEmpty ( ) ) return _hardware ;
if ( _progGroup = = 0 ) return i18n ( " <not set> " ) ;
Port : : Description pd = static_cast < Programmer : : CliManager * > ( Programmer : : manager ) - > portDescription ( ) ;
: : Hardware : : Config * config = _progGroup - > hardwareConfig ( ) ;
if ( config ) return config - > currentHardware ( pd . type ) + " " + i18n ( " <from config> " ) ;
delete config ;
return i18n ( " <not set> " ) ;
}
if ( property = = " device " | | property = = " processor " ) {
if ( _device = = 0 ) return i18n ( " <not set> " ) ;
return _device - > name ( ) ;
}
if ( property = = " format " ) return HexBuffer : : FORMATS [ _format ] ;
if ( property = = " port " ) {
if ( ! _port . isEmpty ( ) ) return _port ;
if ( _progGroup = = 0 ) return i18n ( " <not set> " ) ;
Port : : Description pd = Programmer : : GroupConfig : : portDescription ( * _progGroup ) ;
TQString s = pd . type . key ( ) ;
if ( pd . type . data ( ) . withDevice ) s + = " ( " + pd . device + " ) " ;
return s + " " + i18n ( " <from config> " ) ;
}
if ( property = = " firmware-dir " ) {
if ( ! _firmwareDir . isEmpty ( ) ) return _firmwareDir . pretty ( ) ;
if ( _progGroup = = 0 ) return i18n ( " <not set> " ) ;
return Programmer : : GroupConfig : : firmwareDirectory ( * _progGroup ) + " " + i18n ( " <from config> " ) ;
}
if ( property = = " target-self-powered " ) {
if ( ! _targetSelfPowered . isEmpty ( ) ) return _targetSelfPowered ;
return TQString ( readConfigEntry ( Programmer : : Config : : TargetSelfPowered ) . toBool ( ) ? " true " : " false " ) + " " + i18n ( " <from config> " ) ;
}
if ( property = = " hex " ) {
if ( ! _hexUrl . isEmpty ( ) ) return _hexUrl . pretty ( ) ;
return i18n ( " <not set> " ) ;
}
if ( property = = " coff " ) {
if ( ! _coffUrl . isEmpty ( ) ) return _coffUrl . pretty ( ) ;
return i18n ( " <not set> " ) ;
}
log ( Log : : LineType : : SoftError , i18n ( " Unknown property \" %1 \" " ) . tqarg ( property ) ) ;
return TQString ( ) ;
}
//-----------------------------------------------------------------------------
int main ( int argc , char * * argv )
{
CLI : : Main main ;
Piklab : : AboutData * about = new Piklab : : AboutData ( " piklab-prog " , I18N_NOOP ( " Piklab Programmer Utility " ) , I18N_NOOP ( " Command-line programmer/debugger. " ) ) ;
CLI : : OptionList list = main . optionList ( I18N_NOOP ( " Hex filename for programming. " ) ) ;
Piklab : : init ( about , argc , argv , false , list . ptr ( ) ) ;
return main . doRun ( ) ;
}