diff options
Diffstat (limited to 'flash/uart_boot/client.c')
-rw-r--r-- | flash/uart_boot/client.c | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/flash/uart_boot/client.c b/flash/uart_boot/client.c new file mode 100644 index 0000000000..a98edc60cb --- /dev/null +++ b/flash/uart_boot/client.c @@ -0,0 +1,738 @@ +// 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; +} + + |