Here is some sample code for Remote Software Update via TCP/IP in Java

This example updates the firmware in Rabbit modules via Ethernet from a host computer using TCP/IP instead of HTTP or FTP.

The following contains the important snippets, the support stuff depends on your application.

At first, a failure rate (requiring reload of the firmware via serial cable – NOT GOOD) of 1 in 5 was encountered. Adding a bit of time delay between the writing of the image to flash and the exit(0) command seemed to solve the problem so far . This time delay was accomplished accidentally by adding code to send status messages back to the host.

This was tested for the RCM4200.

---------------------- Dynamic C Code fer da Rabbit----------------------------------

…the define statements and such…

#use RCM42xx.LIB
#define BU_TEMP_USE_SFLASH
#define BU_TEMP_PAGE_OFFSET 0
#use “board_update.lib”
//TCPIP Defines
#define TCPCONFIG 1
#define _PRIMARY_STATIC_IP “169.254.56.11” //this gets changed later
#define _PRIMARY_NETMASK “255.255.0.0”
#define MY_GATEWAY “10.10.6.1”
#define MY_NAMESERVER “10.10.6.1”
#define PORT 23
#define TCP_BUF_SIZE 4096
#use “dcrtcp.lib” //tcpip library

… setup code similar to this…

//this is rough code – add garnish as necessary!

sock_init_or_exit(1);

tcp_listen(&socket,PORT,0,0,NULL,0);

printf("Waiting for connection…
");
while(!sock_established(&socket) && sock_bytesready(&socket)==-1)
tcp_tick(&socket);

printf("Connection received…
");

loop here watching the port waiting for the command to do stuff, including
perform a firmware update

aha – code received to do the update, so call

receiveAndInstallNewFirmware(socket, 0);

//receiveAndInstallNewFirmware won’t return – it will exit the program
//on success or fail

…the actual Rabbit function code…
// Java code for the host listed farther below

//----------------------------------------------------------------------------
// cleanUpFirmwareInstall
//
// Prints status message and sends it to host, then cleans up any loose ends
// from the firmware install process and exits.
//

int cleanUpFirmwareInstall(tcp_Socket *socket, char *pMsg)
{

printf(pMsg);
sock_flushnext(socket);
sock_write(socket, pMsg, strlen(pMsg));
sock_close(socket);
while(tcp_tick(socket)) {}

while (buCloseFirmware() == -EBUSY);
exit(0);

}//end of cleanUpFirmwareInstall
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// installNewFirmware
//
// Replaces the software running in the Rabbit micro-controller. Verifies the
// new firmware image stored in the temporary location and then installs it
// over the old code.
//
// NOTE: The firmware update process was failing 1 out of 5 times until
// time delay (by adding code sending message to host) was inserted
// before the exit(0) call. Unsure why this solved the problem.
//
// Return Codes:
// Note that this function will either succeed and reboot to new firmware,
// or it will fail with one of the following error codes:
//
// -EILSEQ: Not a valid firmware_info_t struct (bad marker bytes
// or unsupported version of structure).
// -EBADMSG: Bad CRC (structure has been corrupted).
// -ENODATA: Source not open, or firmware info not found in source.
// -EPERM: Firmware was compiled for a different target.
// -EBADDATA: CRC-32 mismatch, firmware image corrupted.
// -EBADMSG: CRC-32 mismatch after installing.
// -ENOMEM: Couldn’t allocate buffer to copy firmware.
//
// Error codes when using a FAT file for temporary storage:
// -EINVAL: Couldn’t parse BU_TEMP_FILE.
// -ENOENT: File BU_TEMP_FILE does not exist.
// -EMFILE: Too many open files.
//
// Error codes when using the serial flash for temporary storage:
// -ENODEV: Can’t find/read the serial flash.
//
// On success, returns 1 regardless of the number of bytes read from the socket.
//

int installNewFirmware(tcp_Socket *socket)
{

char buffer[200];

firmware_info_t fi;
int i;
int result;
int progress;

printf( "Verifying and installing new firmware…
");

result = buOpenFirmwareTemp(BU_FLAG_NONE);

if (result){
sprintf(buffer, "Error %d opening firmware image.
", result);
cleanUpFirmwareInstall(socket, buffer);
}

// buGetInfo is a non-blocking call, and may take multiple attempts
// before the file is completely open.
do {
result = buGetInfo( &fi);
} while ( (result == -EBUSY));

if (result){
sprintf(buffer, "Error %d getting firmware image info.
", result);
cleanUpFirmwareInstall(socket, buffer);
}

printf( "Found %s v%u.%02x…
", fi.program_name,
fi.version >> 8, fi.version & 0xFF);

printf( "Attempting to install new version…
");
progress = 0;

do{
printf( “\r verify %u.%02u%%\r”, progress / 100, progress % 100);

  //verify the firmware image
  result = buVerifyFirmware(&progress);

} while (result == -EAGAIN);

if (result){
sprintf(buffer, "Error %d while verifying image.
", result);
cleanUpFirmwareInstall(socket, buffer);
}

printf( "Verify complete, installing new firmware…
");

//install the firmware image
result = buInstallFirmware();

if (result){
//put the firmware running in ram back into flash on failure
//buInstallFirmware supposedly does this, but have had issues with that
buRestoreFirmware(0);

  sprintf(buffer, "Error %d while installing firmware.

", result);
cleanUpFirmwareInstall(socket, buffer);
}

//send message to host and exit

sprintf(buffer, "Install successful: rebooting.
");
cleanUpFirmwareInstall(socket, buffer);

return result;

}//end of installNewFirmware
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// receiveAndInstallNewFirmware
//
// Receives a Rabbit firmware image file from the host and overwrites the
// existing code.
//
// The image is received in 1024 byte packets, with the last packet being
// smaller as necessary.
//
// NOTE: The firmware update functions alter the Port C configuration.
// Currently, this function will halt the program whether or not
// the update succeeds. This eliminates the need to reset Port C. If
// That behavior is changed, then Port C will need to be reset before
// program execution can continue.
//
// Return Codes:
//
// Return codes:
// Most return codes come from install_firmware (see above).
//
// Additional return codes for tftp_and_install:
// -EPERM: buTempCreate not supported on this hardware.
// -ENODEV: Couldn’t read from serial flash.
// -EBUSY: Timeout waiting for FAT filesystem.
// -ENODATA: Download didn’t contain a valid firmware image for this
// device.
// <0: Error opening FAT file, see fat_Open for full list of
// error codes and their meanings.
//

int receiveAndInstallNewFirmware(tcp_Socket *socket, int pPktID)
{

int bytesRead, offset;
char codeBuffer[CODE_BUFFER_SIZE];
char bufferIn[5], bufferOut[5];
int x,y, z, bufPtr, packetCount;
char shiftReg;
int result;

printf("Loading new firmware…
");

//read the checksum byte and check validity of the command packet
sock_fastread(socket,bufferIn,1);
if ( ((pPktID + bufferIn[0]) & 0xff) != 0) return -1;

packetCount = 0;

// set P2 back to active drive for use with the serial flash
WrPortI(PCDCR, &PCDCRShadow, (PCDCRShadow & 0xfb));

while ( (result = buTempCreate()) == -EBUSY);
if (result){
printf( "Error %d calling buTempCreate!
", result);
//send the error code back as MSB:LSB
send3Bytes(socket, ERROR, (result >> 8) & 0xff, result & 0xff);
return result;
}

//request first data packet from host
send3Bytes(socket, SEND_DATA_CMD, NO_STATUS, NO_STATUS);

printf("Receiving firmware packets…
");

//process packets until exit command packet received from host
do{

  //wait for data or exit command packet from host
  do{

     codeBuffer[0] = NO_ACTION; //clean out the command byte

     //wait for data packet from host - last packet is not full sized so
     //just assume every packet is complete if a byte is received
     if (sock_bytesready(socket) &gt; 0)
        bytesRead=sock_fastread(socket, codeBuffer, CODE_BUFFER_SIZE);

  } while(tcp_tick(socket) &amp;&amp; codeBuffer[0] == NO_ACTION);

  // if the packet is data, store it in the temporary storage location
  if (codeBuffer[0] == DATA_CMD){

     packetCount++;
     printf( "Packet #: %d...

", packetCount);

     //request next data packet from host while processing the previous one
     send3Bytes(socket, SEND_DATA_CMD, NO_STATUS, NO_STATUS);

     if (bytesRead &gt; 0){

        // buTempWrite is non-blocking, so it may take multiple calls to
        // complete the write -- must call it repeatedly while updating the
        // offset to make sure it writes the entire buffer

        //the first byte is a command byte, the rest are data bytes, so skip
        //the command byte at index 0
        offset = 1;

        while (offset &lt; bytesRead)
        {
           result = buTempWrite( &amp;codeBuffer[offset], bytesRead - offset);

           if (result == -EBUSY){
              // resources busy, try again without any changes
           }
           else if (result &lt; 0){
              printf(
              	"Error %d writing firmware to temp location.

", result);
send3Bytes(
socket, ERROR, (result >> 8) & 0xff, result & 0xff);
return(result);
} else {
offset += result;
}
}
}//if (bytesRead > 0)
}// if (codeBuffer[0] == DATA_CMD)

} while(tcp_tick(socket) && codeBuffer[0] != EXIT_CMD);

//install the newly downloaded firmware
return installNewFirmware(socket);

// if installNewFirmware returned without exiting the program, then the
// install failed – exit the program to force a restart from known state

printf( "Install failed -- exiting program.

");
while (buCloseFirmware() == -EBUSY);
exit(0);

return(result);

}//end of receiveAndInstallNewFirmware
//----------------------------------------------------------------------------

…the actual Java code for the host…

…setup code similar to this…

    //ipAddr is that of the Rabbit module
    socket = new Socket(ipAddr, 23);

    //set amount of time in milliseconds that a read from the socket will
    //wait for data - this prevents program lock up when no data is ready
    socket.setSoTimeout(250);

do stuff here – talk to the Rabbit, give it commands

when user clicks button to upload firmware, do this call:

…actual Java code…

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// class InstallFirmwareSettings
//
// This class is used to pass in all necessary settings to the
// installNewRabbitFirmware function.
//

class InstallFirmwareSettings extends Object{

public byte loadFirmwareCmd;
public byte noAction;
public byte error;
public byte sendDataCmd;
public byte dataCmd;
public byte exitCmd;

}//end of class InstallFirmwareSettings
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Capulin1::installNewRabbitFirmware
//
// Transmits the Rabbit firmware image to the UT board to replace the existing
// code.
//
// See corresponding function in the parent class Board.
//

public void installNewRabbitFirmware()
{

//create an object to hold codes specific to the UT board for use by the
//firmware installer method

InstallFirmwareSettings settings = new InstallFirmwareSettings();
settings.loadFirmwareCmd = LOAD_FIRMWARE_CMD;
settings.noAction = NO_ACTION;
settings.error = ERROR;
settings.sendDataCmd = SEND_DATA_CMD;
settings.dataCmd = DATA_CMD;
settings.exitCmd = EXIT_CMD;

installNewRabbitFirmwareHelper(
                           "UT", "Rabbit\\CAPULIN UT BOARD.bin", settings);

}//end of Capulin1::installNewRabbitFirmware
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Board::installNewRabbitFirmwareHelper
//
// Transmits the Rabbit firmware code to the specified board to replace the
// existing code.
//
// The firmware in the Rabbit is stored in flash memory. There is a slight
// danger in installing new firmware because the Rabbit may become inoperable
// if a power glitch occurs during the process – a reload via serial cable
// would then be required.
//
// Since there is a danger of locking up the Rabbit and the flash memory can be
// written to a finite number of times, the code is not sent each time the
// system starts as is done with the FPGA code. Rather, it is only updated
// by explicit command.
//
// This function uses TCP/IP and transmits to the single board handled by
// this Board object. If multiple boards are being loaded simultaneously,
// the load time increases significantly.
//
// This function uses the “binary file” (*.bin) produced by the Dynamic C
// compiler.
//
// The file is transmitted in 1025 byte blocks: one command byte followed by
// 1024 data bytes. The last block is truncated as necessary.
//
// The remote should send the command SEND_DATA when it is ready for each
// block, including the first one.
//

void installNewRabbitFirmwareHelper(String pBoardType, String pFilename,
InstallFirmwareSettings pS)
{

int CODE_BUFFER_SIZE = 1025; //transfer command word and 1024 data bytes
byte[] codeBuffer;
codeBuffer = new byte[CODE_BUFFER_SIZE];
int remoteStatus;
int timeOutRead;
int bufPtr;
int pktCounter = 0;

boolean fileDone = false;

FileInputStream inFile = null;

try {

    sendBytes(pS.loadFirmwareCmd); //send command to initiate loading

    logger.logMessage(pBoardType + " " + ipAddrS +
                                     " loading Rabbit firmware..." + "

");

    timeOutRead = 0;
    inFile = new FileInputStream(pFilename);
    int c, inCount;

    while(timeOutRead &lt; FIRMWARE_LOAD_TIMEOUT){

        inBuffer[0] = pS.noAction; //clear request byte from host
        //clear status word (upper byte) from host
        inBuffer[1] = pS.noAction;
        //clear status word (lower byte) from host
        inBuffer[2] = pS.noAction;

        remoteStatus = 0;

        //check for a request from the remote if connected
        if (byteIn != null){
            inCount = byteIn.available();
            //0 = buffer offset, 2 = number of bytes to read
            if (inCount &gt;= 3) {byteIn.read(inBuffer, 0, 3);}
            remoteStatus = (int)((inBuffer[0]&lt;&lt;8) &amp; 0xff00)
                                               + (int)(inBuffer[1] &amp; 0xff);
        }

        //trap and respond to messages from the remote
        if (inBuffer[0] == pS.error){
            logger.logMessage(pBoardType + " " + ipAddrS +
             " error loading firmware, error code: " + remoteStatus + "

");
return;
}

        //send data packet when requested by remote
        if (inBuffer[0] == pS.sendDataCmd &amp;&amp; !fileDone){

            bufPtr = 0; c = 0;
            codeBuffer[bufPtr++] = pS.dataCmd; // command byte = data packet

            //be sure to check bufPtr on left side or a byte will get read
            //and ignored every time bufPtr test fails
            while (bufPtr

I am using a similar code in my RCM4200 but it only works first time after a JTAG program updating. Second updating attempt returns 0 after buInstallFirmware() but when restartung the firmware is not the new one.
Any idea?

I use the serial port to program when using a wired connection – is that the same as JTAG updating?

I would try getting the update working with the simplest possible program, i.e. one that does nothing more than prints “version x.xx” to the console.

Then add more and more of your functionality to the program until the update fails. This will tell you if it is a code size issue or if your program is doing something funny that’s upsetting the uploader functionality (such as jacking with port setups, etc.)

Do you think there is a program size limit for the remote updating? My program size is around 350KB