rockbox/flash/uart_boot/client.c
Jörg Hohensohn 6a4e4c87c2 source code for all my flash stuff, now finally in cvs
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4083 a1c6a512-1295-4272-9138-f99709370657
2003-11-30 11:37:43 +00:00

738 lines
18 KiB
C

// client.cpp : functions for monitor download and communication.
//
#include <stdio.h>
#include <stdlib.h>
#include "scalar_types.h" // (U)INT8/16/32
#include "Uart.h" // platform abstraction for UART
#include "minimon.h" // protocol of my little monitor
// do the baudrate configuration for the Player
int ConfigFirstlevelPlayer (tUartHandle serial_handle)
{
UINT32 result_nbr;
if(!UartConfig(serial_handle, 4800, eMARKPARITY, eTWOSTOPBITS, 8))
{
UINT32 dwErr = GET_LAST_ERR();
printf("Error %d setting up COM params for baudrate byte\n", dwErr);
exit(1);
}
// this will read as 0x19 when viewed with 2300 baud like the player does
result_nbr = UartWrite(serial_handle, (UINT8*)"\x86\xC0", 2);
if (result_nbr != 2)
{
UINT32 dwErr = GET_LAST_ERR();
printf("Error %d setting up COM params for baudrate byte\n", dwErr);
}
SLEEP(100); // wait for the chars to be sent, is there a better way?
// the read 0x19 means 14423 baud with 12 MHz
if(!UartConfig(serial_handle, 14400, eNOPARITY, eONESTOPBIT, 8))
{
printf("Error setting up COM params for 1st level loader\n");
exit(1);
}
return 0;
}
// do the baudrate configuration for the Recoder/FM
int ConfigFirstlevelRecorder (tUartHandle serial_handle)
{
UINT32 result_nbr;
if(!UartConfig(serial_handle, 4800, eNOPARITY, eTWOSTOPBITS, 8))
{
UINT32 dwErr = GET_LAST_ERR();
printf("Error %d setting up COM params for baudrate byte\n", dwErr);
exit(1);
}
// this will read as 0x08 when viewed with 2120 baud like the recorder does
result_nbr = UartWrite(serial_handle, (UINT8*)"\x00\x00", 2);
if(result_nbr != 2)
{
printf("Error transmitting baudrate byte\n");
exit(1);
}
SLEEP(100); // wait for the chars to be sent, is there a better way?
// the read 0x08 means 38400 baud with 11.0592 MHz
if(!UartConfig(serial_handle, 38400, eNOPARITY, eONESTOPBIT, 8))
{
UINT32 dwErr = GET_LAST_ERR();
printf("Error %d setting up COM params for 1st level loader\n", dwErr);
exit(1);
}
return 0;
}
// transfer a byte for the monitor download, with or without acknowledge
int DownloadByte(tUartHandle serial_handle, unsigned char byte, bool bAck)
{
unsigned char received;
bool bRecorder = true; // false for player
while (1)
{
UartWrite(serial_handle, &byte, 1);
if (bAck)
{
UartRead(serial_handle, &received, 1);
if (received == byte)
{
UartWrite(serial_handle, (UINT8*)"\x01", 1); // ack success
break; // exit the loop
}
else
{
printf("Error transmitting monitor byte 0x%02X, got 0x%0X\n", byte, received);
UartWrite(serial_handle, (UINT8*)"\x00", 1); // ack fail, try again
}
}
else
break; // no loop
}
return 1;
}
// download our little monitor, the box must have been just freshly switched on for this to work
int DownloadMonitor(tUartHandle serial_handle, bool bRecorder, char* szFilename)
{
FILE* pFile;
size_t filesize;
UINT8 byte;
unsigned i;
// hard-coded parameters
bool bAck = true; // configure if acknowledged download (without useful for remote pin boot)
UINT32 TargetLoad = 0x0FFFF000; // target load address
pFile = fopen(szFilename, "rb");
if (pFile == NULL)
{
printf("\nMonitor file %s not found, exiting\n", szFilename);
exit(1);
}
// determine file size
fseek(pFile, 0, SEEK_END);
filesize = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
// This is _really_ tricky! The box expects a BRR value in a nonstandard baudrate,
// which a PC can't generate. I'm using a higher one with some wild settings
// to generate a pulse series that:
// 1) looks like a stable byte when sampled with the nonstandard baudrate
// 2) gives a BRR value to the box which results in a baudrate the PC can also use
if (bRecorder)
{
ConfigFirstlevelRecorder(serial_handle);
}
else
{
ConfigFirstlevelPlayer(serial_handle);
}
UartWrite(serial_handle, bAck ? (UINT8*)"\x01" : (UINT8*)"\x00", 1); // ACK mode
// transmit the size, little endian
DownloadByte(serial_handle, (UINT8)( filesize & 0xFF), bAck);
DownloadByte(serial_handle, (UINT8)((filesize>>8) & 0xFF), bAck);
DownloadByte(serial_handle, (UINT8)((filesize>>16) & 0xFF), bAck);
DownloadByte(serial_handle, (UINT8)((filesize>>24) & 0xFF), bAck);
// transmit the load address, little endian
DownloadByte(serial_handle, (UINT8)( TargetLoad & 0xFF), bAck);
DownloadByte(serial_handle, (UINT8)((TargetLoad>>8) & 0xFF), bAck);
DownloadByte(serial_handle, (UINT8)((TargetLoad>>16) & 0xFF), bAck);
DownloadByte(serial_handle, (UINT8)((TargetLoad>>24) & 0xFF), bAck);
// transmit the command byte
DownloadByte(serial_handle, 0xFF, bAck); // 0xFF means execute the transferred image
// transmit the image
for (i=0; i<filesize; i++)
{
fread(&byte, 1, 1, pFile);
DownloadByte(serial_handle, byte, bAck);
}
fclose (pFile);
// now the image should have been started, red LED off
return 0;
}
// wait for a fixed string to be received (no foolproof algorithm,
// may overlook if the searched string contains repeatitions)
int WaitForString(tUartHandle serial_handle, char* pszWait)
{
int i = 0;
unsigned char received;
while(pszWait[i] != '\0')
{
UartRead(serial_handle, &received, 1);
printf("%c", received); // debug
if (received == pszWait[i])
i++; // continue
else
i=0; // mismatch, start over
}
return 0;
}
// send a sting and check the echo
int SendWithEcho(tUartHandle serial_handle, char* pszSend)
{
int i = 0;
unsigned char received;
while(pszSend[i] != '\0')
{
UartWrite(serial_handle, (unsigned char*)(pszSend + i), 1); // send char
do
{
UartRead(serial_handle, &received, 1); // receive echo
printf("%c", received); // debug
}
while (received != pszSend[i]); // should normally be equal
i++; // next char
}
return 0;
}
// rarely used variant: download our monitor using the built-in Archos monitor
int DownloadArchosMonitor(tUartHandle serial_handle, char* szFilename)
{
FILE* pFile;
size_t filesize;
UINT8 byte;
UINT16 checksum = 0;
unsigned i;
// the onboard monitor uses 115200 baud
if(!UartConfig(serial_handle, 115200, eNOPARITY, eONESTOPBIT, 8))
{
UINT32 dwErr = GET_LAST_ERR();
printf("Error %d setting up COM params for baudrate %d\n", dwErr, 115200);
exit(1);
}
// wait for receiving "#SERIAL#"
WaitForString(serial_handle, "#SERIAL#");
// send magic "SRL" command to get interactive mode
SendWithEcho(serial_handle, "SRL\r");
// wait for menu completion: "ROOT>" at the end
WaitForString(serial_handle, "ROOT>");
// send upload command "UP"
SendWithEcho(serial_handle, "UP\r");
pFile = fopen(szFilename, "rb");
if (pFile == NULL)
{
printf("\nMonitor file %s not found, exiting\n", szFilename);
exit(1);
}
// determine file size
fseek(pFile, 0, SEEK_END);
filesize = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
// calculate checksum
for (i=0; i<filesize; i++)
{
fread(&byte, 1, 1, pFile);
checksum += byte;
}
fseek(pFile, 0, SEEK_SET);
// send header
// size as 32 bit little endian
byte = (UINT8)( filesize & 0xFF);
UartWrite(serial_handle, &byte, 1);
byte = (UINT8)((filesize>>8) & 0xFF);
UartWrite(serial_handle, &byte, 1);
byte = (UINT8)((filesize>>16) & 0xFF);
UartWrite(serial_handle, &byte, 1);
byte = (UINT8)((filesize>>24) & 0xFF);
UartWrite(serial_handle, &byte, 1);
// checksum as 16 bit little endian
byte = (UINT8)( checksum & 0xFF);
UartWrite(serial_handle, &byte, 1);
byte = (UINT8)((checksum>>8) & 0xFF);
UartWrite(serial_handle, &byte, 1);
UartWrite(serial_handle, (unsigned char*)"\x00", 1); // kind (3 means flash)
UartWrite(serial_handle, (unsigned char*)"\x00", 1); // ignored byte
// wait for monitor to accept data
WaitForString(serial_handle, "#OKCTRL#");
// transmit the image
for (i=0; i<filesize; i++)
{
fread(&byte, 1, 1, pFile);
UartWrite(serial_handle, &byte, 1); // payload
}
fclose (pFile);
UartWrite(serial_handle, (unsigned char*)"\x00", 1); // ignored byte
// wait for menu completion: "ROOT>" at the end
WaitForString(serial_handle, "ROOT>");
// send start program command "SPRO"
SendWithEcho(serial_handle, "SPRO\r");
SLEEP(100); // wait a little while for startup
return 0;
}
/********** Target functions using the Monitor Protocol **********/
// read a byte using the target monitor
UINT8 ReadByte(tUartHandle serial_handle, UINT32 addr)
{
UINT8 send;
UINT8 received;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error!\n");
return 1;
}
// send the read command
send = BYTE_READ;
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
return received;
}
// write a byte using the target monitor
int WriteByte(tUartHandle serial_handle, UINT32 addr, UINT8 byte)
{
UINT8 send;
UINT8 received;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error, receiced 0x%02X!\n", received);
return 1;
}
// send the write command
send = BYTE_WRITE;
UartWrite(serial_handle, &send, 1);
// transmit the data
UartWrite(serial_handle, &byte, 1);
UartRead(serial_handle, &received, 1); // response
if (received != BYTE_WRITE)
{
printf("Protocol error!\n");
return 1;
}
return 0;
}
// read many bytes using the target monitor
int ReadByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer)
{
UINT8 send, received;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error!\n");
return 1;
}
while (size)
{
if (size >= 16)
{ // we can use a "burst" command
send = BYTE_READ16;
UartWrite(serial_handle, &send, 1); // send the read command
UartRead(serial_handle, pBuffer, 16); // data response
pBuffer += 16;
size -= 16;
}
else
{ // use single byte command
send = BYTE_READ;
UartWrite(serial_handle, &send, 1); // send the read command
UartRead(serial_handle, pBuffer++, 1); // data response
size--;
}
}
return 0;
}
// write many bytes using the target monitor
int WriteByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer)
{
UINT8 send, received;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error!\n");
return 1;
}
while (size)
{
if (size >= 16)
{ // we can use a "burst" command
send = BYTE_WRITE16;
UartWrite(serial_handle, &send, 1); // send the write command
UartWrite(serial_handle, pBuffer, 16); // transmit the data
UartRead(serial_handle, &received, 1); // response
if (received != BYTE_WRITE16)
{
printf("Protocol error!\n");
return 1;
}
pBuffer += 16;
size -= 16;
}
else
{ // use single byte command
send = BYTE_WRITE;
UartWrite(serial_handle, &send, 1); // send the write command
UartWrite(serial_handle, pBuffer++, 1); // transmit the data
UartRead(serial_handle, &received, 1); // response
if (received != BYTE_WRITE)
{
printf("Protocol error!\n");
return 1;
}
size--;
}
}
return 0;
}
// write many bytes using the target monitor
int FlashByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer)
{
UINT8 send, received;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error!\n");
return 1;
}
while (size)
{
if (size >= 16)
{ // we can use a "burst" command
send = BYTE_FLASH16;
UartWrite(serial_handle, &send, 1); // send the write command
UartWrite(serial_handle, pBuffer, 16); // transmit the data
UartRead(serial_handle, &received, 1); // response
if (received != BYTE_FLASH16)
{
printf("Protocol error!\n");
return 1;
}
pBuffer += 16;
size -= 16;
}
else
{ // use single byte command
send = BYTE_FLASH;
UartWrite(serial_handle, &send, 1); // send the write command
UartWrite(serial_handle, pBuffer++, 1); // transmit the data
UartRead(serial_handle, &received, 1); // response
if (received != BYTE_FLASH)
{
printf("Protocol error!\n");
return 1;
}
size--;
}
}
return 0;
}
// read a 16bit halfword using the target monitor
UINT16 ReadHalfword(tUartHandle serial_handle, UINT32 addr)
{
UINT8 send;
UINT8 received;
UINT16 halfword;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error!\n");
return 1;
}
// send the read command
send = HALFWORD_READ;
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
halfword = received << 8; // highbyte
UartRead(serial_handle, &received, 1);
halfword |= received; // lowbyte
return halfword;
}
// write a 16bit halfword using the target monitor
int WriteHalfword(tUartHandle serial_handle, UINT32 addr, UINT16 halfword)
{
UINT8 send;
UINT8 received;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error!\n");
return 1;
}
// send the write command
send = HALFWORD_WRITE;
UartWrite(serial_handle, &send, 1);
// transmit the data
send = halfword >> 8; // highbyte
UartWrite(serial_handle, &send, 1);
send = halfword & 0xFF; // lowbyte
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != HALFWORD_WRITE)
{
printf("Protocol error!\n");
return 1;
}
return 0;
}
// change baudrate using target monitor
int SetTargetBaudrate(tUartHandle serial_handle, long lClock, long lBaudrate)
{
UINT8 send;
UINT8 received;
UINT8 brr;
long lBRR;
lBRR = lClock / lBaudrate;
lBRR = ((lBRR + 16) / 32) - 1; // with rounding
brr = (UINT8)lBRR;
// send the command
send = BAUDRATE;
UartWrite(serial_handle, &send, 1);
UartWrite(serial_handle, &brr, 1); // send the BRR value
UartRead(serial_handle, &received, 1); // response ack
if (received != BAUDRATE)
{ // bad situation, now we're unclear about the baudrate of the target
printf("Protocol error!\n");
return 1;
}
SLEEP(100); // give it some time to settle
// change our baudrate, too
UartConfig(serial_handle, lBaudrate, eNOPARITY, eONESTOPBIT, 8);
return 0;
}
// call a subroutine using the target monitor
int Execute(tUartHandle serial_handle, UINT32 addr, bool bReturns)
{
UINT8 send;
UINT8 received;
// send the address command
send = ADDRESS;
UartWrite(serial_handle, &send, 1);
// transmit the address, big endian
send = (UINT8)((addr>>24) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>16) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)((addr>>8) & 0xFF);
UartWrite(serial_handle, &send, 1);
send = (UINT8)(addr & 0xFF);
UartWrite(serial_handle, &send, 1);
UartRead(serial_handle, &received, 1); // response
if (received != ADDRESS)
{
printf("Protocol error!\n");
return 1;
}
// send the execute command
send = EXECUTE;
UartWrite(serial_handle, &send, 1);
if (bReturns)
{ // we expect the call to return control to minimon
UartRead(serial_handle, &received, 1); // response
if (received != EXECUTE)
{
printf("Protocol error!\n");
return 1;
}
}
return 0;
}