📄 flash.cpp
字号:
/** \file
This file contains code used to implement an amplifier firmware flashing
utility. This utility may be used to update the firmware of all the
Copley Controls amplifiers on a CANopen network.
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "CML.h"
#include "can/can_copley.h"
CML_NAMESPACE_USE();
/***************************************************************************/
/**
The download class is a thread that handles downloading firmware to one
amplifier on the network.
*/
/***************************************************************************/
class Downloader: public Thread
{
Semaphore sem;
int id;
public:
Downloader( int i ): sem(0), id(i){};
void run( void );
const Error *wait( int32 timeout );
};
/***************************************************************************/
/**
This class extends the more generic Firmware object. The only addition
is a simple display which shows the progress of the download.
*/
/***************************************************************************/
class MyFirmware: public Firmware
{
int display;
public:
MyFirmware()
{
display=0;
}
void progress( uint32 addr );
};
/* local data */
CanOpen canOpen;
MyFirmware fw;
char *canDevice = 0;
char *filename = "";
int32 canBPS = 1000000;
static void showerr( const Error *err, char *str );
static void HandleArgs( int argc, char **argv );
/***************************************************************************/
/**
Main routine for firmware downloader.
This function downloads a new amplifier firmware file to every amplifier
detected on the CANopen network.
It works by creating 127 seperate threads (one for each valid CANopen node ID).
These threads each try to talk to their respective amplifier, and if an amp
is found they will download the firmware of the amplifier.
The result is a very quick firmware update since all amplifiers are updated
in parallel.
Note that if an error occurs during the firmware download, the amplifier's
firmware will need to be updated one at a time through the serial interface
using the CME-2 program.
*/
/***************************************************************************/
int main( int argc, char **argv )
{
// cml.SetDebugLevel( LOG_EVERYTHING );
// cml.SetFlushLog( true );
// Handle any passed parameters
HandleArgs( argc, argv );
// Open the CAN and CANopen networks.
CopleyCAN can( canDevice );
can.SetBaud( canBPS );
const Error *err = canOpen.Open( can );
if( err )
{
printf( "Error opening CANopen network:\n %s\n", err->toString() );
exit(1);
}
// Load the firmware file into RAM
printf( "Downloading firmware file %s\n", filename );
err = fw.Load( filename );
showerr( err, "Loading firmware" );
// Create and start the downloader threads
Downloader *dnld[127];
int i;
for( i=1; i<128; i++ )
{
dnld[i-1] = new Downloader(i);
if( !dnld[i-1] )
{
printf( "Error creating downloader for id %d\n", i );
}
else
{
dnld[i-1]->start();
}
}
// Wait for the download to finish.
printf( "All downloaders created, waiting\n" );
for( i=0; i<127; i++ )
{
dnld[i]->wait( 120000 );
}
printf( "\n" );
return 0;
}
/***************************************************************************/
/**
If the passed error object is not OK, then display it and exit
*/
/***************************************************************************/
static void showerr( const Error *err, char *str )
{
if( err )
{
printf( "Error %s: %s\n", str, err->toString() );
exit(1);
}
}
/***************************************************************************/
/**
This is the main code of the downloader thread. It tries to open it's
amplifier object, and if that is successful it downloads the firmware
to it.
After the firmware downloads (or if the amplifier can't be opened), the
thread posts to it's semaphore and exits.
*/
/***************************************************************************/
void Downloader::run( void )
{
CopleyNode node;
const Error *err;
err = node.Init( canOpen, id );
if( err ) goto fail;
// Make sure this is the right type of node.
NodeIdentity ident;
err = node.GetIdentity( ident );
if( err ) goto fail;
if( ident.vendorID != 0x000000AB )
goto fail;
printf( "Doing download %d\n", id );
err = node.FirmwareUpdate(fw);
if( err )
printf( "Error downloading to %d: %s\n", id, err->toString() );
fail:
sem.Put();
return;
}
/***************************************************************************/
/**
Wait for the download thread to finish.
@param timeout Time to wait (milliseconds)
*/
/***************************************************************************/
const Error *Downloader::wait( int32 timeout )
{
return sem.Get(timeout);
}
/***************************************************************************/
/**
Progress display for the firmware object.
@param addr Address being read from the firmware object.
*/
/***************************************************************************/
void MyFirmware::progress( uint32 addr )
{
uint32 length = getLength();
int ct = (addr*40)/length;
if( ct > display )
{
display = ct;
printf( "*" );
fflush(stdout);
}
}
/***************************************************************************/
/**
Handle the command line arguments.
*/
/***************************************************************************/
static void HandleArgs( int argc, char **argv )
{
if( argc < 2 )
{
printf( "Usage: %s [options] <filename>\n"
" <filename> is the name of the firmware file\n"
"\n"
"options:\n"
" -c <can device> - specify the can device to use.\n"
" -b <bit rate> - specify bit rate \n", *argv );
exit(0);
}
argv++;
while( --argc > 1 )
{
if( !strcmp( *argv, "-c" ) )
{
--argc; ++argv;
canDevice = *argv++;
}
else if( !strcmp( *argv, "-b" ) )
{
--argc; ++argv;
canBPS = atol( *argv++ );
if( canBPS < 10000 || canBPS > 1000000 )
{
printf( "Bad bit rate: %ld\n", (long)canBPS );
exit(1);
}
}
}
filename = *argv;
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -