// main.c // STM32 boot loader application // Written by Dale Wheat - 28 January 2008 // notes: // control chip via serial handshaking lines: // DTR - reset (pin 4 on PC side, pin 6 on STM3210B-EVAL) - normally -12V (mark) but toggles ~8x during WinXP boot // RTS - boot mode #include #include #include #include #include // codes used by the STM32 bootloader protocol #define SYNC 0x7F #define ACK 0x79 #define NACK 0x1F // commands used by the STM32 bootloader protocol #define CMD_GET 0x00 // get bootloader version and list of supported commands #define CMD_GET_VERSION_RPS 0x01 // get bootloader version and (fake in 2.0) read protection status #define CMD_GET_ID 0x02 // get device ID #define CMD_READ_MEMORY 0x11 // read memory #define CMD_GO 0x21 // go #define CMD_WRITE_MEMORY 0x31 // write memory #define CMD_ERASE 0x43 // erase // usage() - describe command line parameters void usage(void) { printf("usage: STM32boot [options] [file]\n" "Options:\n" "\t-c comport (e.g., COM1, COM2) default=COM1\n" "\t-b baudrate (e.g., 9600, 115200) default=115200\n" "\t-a address\n" "\t-i identify chip\n" "\t-e erase (optimized)\n" "\t-E erase entire FLASH\n" //"\t-b blank check\n" "\t-v verify after programming\n" //"\t-f compare to file\n" "\t-o output to file\n" "\t-x execute\n" "\t-t terminal\n" "\t-r reset\n" "\t-q quiet mode\n" "\t-d lots of debugging output\n" "\t-? help\n" "\nExample: stm32boot -c COM1 -b 115200 -r -e -v -x firmware.bin\n" ); } // main() - main program function int main(int argc, char *argv[]) { unsigned char argv_comport = 0; // COM port parameter index (0=unspecified) unsigned char comport_name[12]; // fully qualified name of COM port HANDLE hComm = INVALID_HANDLE_VALUE; // communication device handle (COM port) DCB dcb; // device control block for serial port DWORD baudrate; // baudrate COMMTIMEOUTS timeouts; // serial port timeout values DWORD number; // number of bytes written unsigned char buffer[260]; // communication buffer HANDLE hFile; // file handle DWORD file_size; // size in bytes of file DWORD remaining_bytes; // bytes left to program DWORD buffer_size; // size of data in buffer unsigned char *file_buffer; // dynamically allocated file buffer unsigned char *file_buffer_p; // moveable pointer to file buffer union { unsigned char bytes[4]; // for sending one byte at a time, in reverse order unsigned int value; // for assigning } address; unsigned int base_address; unsigned char checksum; // this is not a checksum volatile unsigned int i; // various usage struct { unsigned char identify_flag:1; unsigned char erase_flag:1; unsigned char erase_entire_flag:1; unsigned char blank_check_flag:1; unsigned char verify_flag:1; unsigned char execute_flag:1; unsigned char output_flag:1; unsigned char reset_flag:1; unsigned char terminal_flag:1; } flags = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char verbosity = 1; // how much talking is OK (0=none; 1(default)=some; 2=lots) unsigned char argv_filename = 0; // filename parameter index (0=unspecified) unsigned int flash_kb, sram_kb; // FLASH, SRAM memory size in KB unsigned int page, pages; // page counter for multi-page operations baudrate = 115200; // default baud rate base_address = 0x08000000; // assume beginning of FLASH memory // command line parameters if((argc == 1) || ((argc == 2) && (strcmp(argv[1], "-?") == 0))) { usage(); // describe usage exit(0); // nothing else to do } else { // interpret the command line parameters as supplied by the user for(i = 1; i < argc; i++) { if(strcmp(argv[i], "-c") == 0) { // COM port if((i + 1) >= argc) { fprintf(stderr, "error: -c parameter omitted\n"); exit(1); } argv_comport = i + 1; // point to next parameter if(strlen(argv[argv_comport]) > 6) { fprintf(stderr, "error: '%s' is an invalid COM port\n", argv[argv_comport]); exit(1); } i++; // skip parameter } else if(strcmp(argv[i], "-b") == 0) { // baud rate if((i + 1) >= argc) { fprintf(stderr, "error: -b parameter omitted\n"); exit(1); } baudrate = atoi(argv[i + 1]); // convert string to integer if(baudrate < 4800) { fprintf(stderr, "error: baudrate must be at least 4800\n"); exit(1); } if(baudrate > 115200) { fprintf(stderr, "error: baudrate may be at most 115200\n"); exit(1); } switch(baudrate) { //case 1200: // doesn't work here //case 2400: // doesn't work here case 4800: case 9600: case 14400: case 19200: case 38400: case 57600: case 115200: break; // all of these are OK default: fprintf(stderr, "error: invalid baud rate %i\n", baudrate); exit(1); break; } i++; // skip parameter } else if(strcmp(argv[i], "-a") == 0) { // base address: 0x08000000=FLASH (default), 0x20000000=SRAM if((i + 1) >= argc) { fprintf(stderr, "error: -a parameter omitted\n"); exit(1); } //base_address = atoi(argv[i + 1]); // convert string to integer base_address = strtol(argv[i + 1], NULL, 0); // conver string to integer if(base_address < 0x08000000) { fprintf(stderr, "error: base address must be at least 0x08000000\n"); exit(1); } // more address checks should be performed here //printf("[base_address = 0x%08X]\n", base_address); // *** debug *** i++; // skip parameter } else if(strcmp(argv[i], "-i") == 0) { flags.identify_flag = 1; } else if(strcmp(argv[i], "-e") == 0) { flags.erase_flag = 1; } else if(strcmp(argv[i], "-E") == 0) { flags.erase_entire_flag = 1; } else if(strcmp(argv[i], "-b") == 0) { flags.blank_check_flag = 1; } else if(strcmp(argv[i], "-v") == 0) { flags.verify_flag = 1; } else if(strcmp(argv[i], "-o") == 0) { flags.output_flag = 1; } else if(strcmp(argv[i], "-x") == 0) { flags.execute_flag = 1; } else if(strcmp(argv[i], "-t") == 0) { flags.terminal_flag = 1; } else if(strcmp(argv[i], "-r") == 0) { flags.reset_flag = 1; // reset chip using DTR } else if(strcmp(argv[i], "-q") == 0) { verbosity = 0; // quiet mode } else if(strcmp(argv[i], "-d") == 0) { verbosity = 2; // debug mode } else if(strcmp(argv[i], "-?") == 0) { usage(); // describe usage } else { if(argv[i][0] == '-') { fprintf(stderr, "error: '%s' is an unknown option\n", argv[i]); exit(1); } if(argv_filename) { fprintf(stderr, "error: only one filename allowed\n"); exit(1); } argv_filename = i; // this must be the filename } } } if(verbosity) printf("STM32boot v0.0 by Dale Wheat\n"); // compose COM port filename strcpy(comport_name, "\\\\.\\"); if(argv_comport == 0) { strcat(comport_name, "COM1"); // the default COM port } else { strcat(comport_name, argv[argv_comport]); // append indicated COM port parameter } hComm = CreateFile(comport_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if(hComm == INVALID_HANDLE_VALUE) { switch(GetLastError()) { case ERROR_FILE_NOT_FOUND: fprintf(stderr, "error: that port does not exist\n"); exit(1); case ERROR_ACCESS_DENIED: fprintf(stderr, "error: access denied. Perhaps that port is already open or in use by another program?\n"); exit(1); default: fprintf(stderr, "error: could not open COM port because of unknown error: %i\n", GetLastError()); exit(1); } } // COM port timeout values // TO DO: evaluate timeouts correctly in terms of baud rate timeouts.ReadIntervalTimeout = 50; // 50 ms between received characters timeouts.ReadTotalTimeoutMultiplier = 5; timeouts.ReadTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 0; // not used timeouts.WriteTotalTimeoutConstant = 0; // not used if(!SetCommTimeouts(hComm, &timeouts)) { fprintf(stderr, "error: could not set new serial port timeouts"); exit(1); } // configure serial port for correct communication parameters if(!GetCommState(hComm, &dcb)) { fprintf(stderr, "error: could not get existing communication parameters"); exit(1); } dcb.BaudRate = CBR_9600; // baud rate = 9600 (this should always work - we test the requested baud rate later) dcb.fParity = TRUE; // use parity dcb.fOutxCtsFlow = FALSE; // no dcb.fOutxDsrFlow = FALSE; // no dcb.fDtrControl = DTR_CONTROL_DISABLE; // no //dcb.fDtrControl = DTR_CONTROL_ENABLE; // let's see... takes DTR to +12 dcb.fDsrSensitivity = FALSE; // no dcb.fOutX = FALSE; // no dcb.fInX = FALSE; // no dcb.fErrorChar = TRUE; // report parity errors dcb.fNull = FALSE; // no dcb.fRtsControl = RTS_CONTROL_DISABLE; // no dcb.ByteSize = 8; // 8 data bits dcb.Parity = EVENPARITY; // even parity dcb.StopBits = ONESTOPBIT; // one stop bit dcb.ErrorChar = '?'; // parity error substitution character if(!SetCommState(hComm, &dcb)) { fprintf(stderr, "error: could not set communication parameters\n"); exit(1); } // now try to set the baud rate //dcb.BaudRate = 115200; // baud rate = 115,200 (default) //dcb.BaudRate = 230400; // baud rate = 230,400 - doesn't work here //dcb.BaudRate = 128000; // baud rate = 128,000 - doesn't work here //dcb.BaudRate = 256000; // baud rate = 256,000 - doesn't work here dcb.BaudRate = baudrate; if(!SetCommState(hComm, &dcb)) { fprintf(stderr, "error: could not set baud rate to %i. (suggestions: 115200, 57600, 38400, 19200, 14400, 9600, 4800, 2400, 1200)\n", dcb.BaudRate); exit(1); } if(flags.reset_flag) { // reset the chip via the DTR handshaking line // note: DTR clear=-12V, set=+12V if(!EscapeCommFunction(hComm, SETDTR)) { fprintf(stderr, "error: could not set DTR serial handshaking line (chip reset)\n"); exit(1); } ReadFile(hComm, buffer, 1, &number, NULL); // dummy read that is intended to time out if(!EscapeCommFunction(hComm, CLRDTR)) { fprintf(stderr, "error: could not clear DTR serial handshaking line (chip reset)\n"); exit(1); } } // there might be incoming garbage after the chip is first powered on, so clear out the incoming queue if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read from serial port while clearing queue\n"); exit(1); } // write the sync byte to the chip buffer[0] = SYNC; // SYNC byte if(!WriteFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not write sync byte"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write sync byte"); exit(1); } // get ACK byte from chip... maybe if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read ACK byte from chip"); exit(1); } // check number of bytes actually read - from here we can deduce the state of the chip: // if 1 byte received: // if it is "ACK" (0x79) then the chip is sync'd and ready to go // if it is 0x00 then it might be garbage received while chip was being powered up // if it is anything else, then ??? // if 0 bytes received: // chip/board could be powered off // serial cable could be disconnected // chip is already sync'd... // chip is not in boot loader mode - must have switches set and then chip reset if(number == 1) { if(buffer[0] == ACK) { if(verbosity > 1) printf("Chip sync'd!\n"); // received ACK } else if(buffer[0] == NACK) { if(verbosity > 1) printf("Chip was already sync'd\n"); // received NACK } else { fprintf(stderr, "error: chip is in unknown state (response = 0x%02x)\n", (unsigned char) buffer[0]); exit(1); } } else { buffer[0] = 0x00; // dummy byte if(!WriteFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not send dummy byte to test chip synchronization\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not send dummy byte to test chip synchronization\n"); exit(1); } if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read ACK byte from chip (2nd attempt)\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: No response from chip. Check connections, verify switches and reset the chip.\n"); exit(1); } if(buffer[0] == ACK) { if(verbosity > 1) printf("Chip sync'd!\n"); } else if(buffer[0] == NACK) { if(verbosity > 1) printf("Chip was already sync'd\n"); } else { fprintf(stderr, "error: chip is in unknown state (response = 0x%02x)\n", (unsigned char) buffer[0]); exit(1); } } #if 0 // send "Get" command - should return bootloader version and supported command list buffer[0] = CMD_GET; // Get command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Get command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: could not send both bytes of Get command\n"); exit(1); } memset(buffer, 0, sizeof(buffer)); // clear communications buffer // should receive ACK in response if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not receive ACK to Get command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive first expected byte (ACK) in response to Get command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive ACK in response to Get command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // now comes the message byte count if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read byte count in response to Get command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive byte count in response to Get command\n"); exit(1); } if(buffer[0] != 11) { fprintf(stderr, "error: did not receive expected byte count in response to Get command: expected 11, received %i\n", (unsigned char) buffer[0]); exit(1); } // read remainder of response i = ((unsigned char) buffer[0]) + 1; // bad idea here if(!ReadFile(hComm, buffer, i, &number, NULL)) { fprintf(stderr, "error: could not read remainder of response to Get command\n"); exit(1); } if(number != i) {fprintf(stderr, "error: did not receive expected number of bytes in response to Get command: expected 11, received %i\n", number); exit(1); } // interpret bootloader version number if(buffer[0] == 0x20) { printf("Bootloader version 2.0 detected\n"); // the only one we know about today } else { fprintf(stderr, "error: unknown bootloader version: %02X\n", (unsigned char) buffer[0]); exit(1); // exit? or continue? } // // list supported commands // printf("Supported commands:\n"); // for(i = 1; i < number; i++) { // switch((unsigned char) buffer[i]) { // case 0x00: printf("\t0x00 Get\n"); break; // case 0x01: printf("\t0x01 Get Version and Read Protection Status\n"); break; // case 0x02: printf("\t0x02 Get ID\n"); break; // case 0x11: printf("\t0x11 Read Memory\n"); break; // case 0x21: printf("\t0x21 Go\n"); break; // case 0x31: printf("\t0x31 Write Memory\n"); break; // case 0x43: printf("\t0x43 Erase\n"); break; // case 0x63: printf("\t0x63 Write Protect\n"); break; // case 0x73: printf("\t0x73 Write Unprotect\n"); break; // case 0x82: printf("\t0x82 Readout Protect\n"); break; // case 0x92: printf("\t0x92 Readout Unprotect\n"); break; // default: printf("\t0x%02X Unknown command\n", (unsigned char) buffer[i]); break; // } // } // get final ACK for Get command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read final ACK in response to Get command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive final ACK in response to Get command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive final ACK in response to Get command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } #endif // Get Version and 'Read Protection Status' command reports bootloader version and ... nothing else meaningful buffer[0] = CMD_GET_VERSION_RPS; // Get Version and Read Protection Status command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Get Version command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of the Get Version command\n"); exit(1); } // get the initial ACK to the Get Version command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read acknowledgement to Get Version command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read acknowledgment to Get Version command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive ACK in response to Get Version command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // get the bootloader version if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read bootloader version number in response to Get Version command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read bootloader versions number in response to Get Version command\n"); exit(1); } if(buffer[0] == 0x20) { if(verbosity) printf("Bootloader version 2.0 detected\n"); } else { fprintf(stderr, "error: unknown bootloader versions reported: 0x%02X\n", (unsigned char) buffer[0]); exit(1); } // get the 'read protection status' which is not implemented in this device if(!ReadFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not read the 'Read Protection Status'\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not read the 'Read Protection Status'\n"); exit(1); } //printf("Read Protection Status: 0x%02X 0x%02X\n", (unsigned char) buffer[0], (unsigned char) buffer[1]); // always 0, 0 // get the final ACK from the Get Version command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read final ACK in response to Get Version command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive final ACK in response to Get Version command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive final ACK in response to Get Version command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // Get ID command returns chip ID (same as JTAG ID) buffer[0] = CMD_GET_ID; // Get ID command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send the Get ID command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of the Get ID command\n"); exit(1); } // get the initial ACK in response to the Get ID command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not receive initial ACK in response to Get ID command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive initial ACK in response to the Get ID command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive ACK in response to the Get ID command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // receive number of bytes - 1 in the product ID if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read byte count in response to Get ID command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive byte count in response to Get ID command\n"); exit(1); } if(buffer[0] != 3) { fprintf(stderr, "error: received incorrect byte count in response to Get ID command (expected 3, received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // receive product ID i = buffer[0] + 1; // another bad idea if(!ReadFile(hComm, buffer, i, &number, NULL)) { fprintf(stderr, "error: could not read product ID in response to Get ID command\n"); exit(1); } if(number != i) { fprintf(stderr, "error: received incorrect number of bytes in product ID in response to Get ID command (expected 4, received 0x%02X)\n", number); exit(1); } if(flags.identify_flag) { // report product ID if(verbosity) printf("Product ID: "); if(verbosity) for(i = 0; i < number; i++) printf("%02X", buffer[i]); if((buffer[0] == 0x06) && (buffer[1] == 0x41) && (buffer[2] == 0x00) && (buffer[3] == 0x41)) { if(verbosity) printf(" STM32F10xxx family\n"); } else { if(verbosity) printf(" unknown device\n"); } } // get the final ACK in response to the Get ID command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not receive final ACK in respons to Get ID command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive final ACK in response to Get ID command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive final ACK in response to Get ID command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // now read & report memory sizes // 0x1FFFF7E0, 0x1FFFF7E1 (2 bytes) = FLASH in Kbytes (yes, it is) // 0x1FFFF7E2, 0x1FFFF7E3 (2 Bytes) = SRAM in Kbytes (not, it isn't) if(verbosity > 1) printf("Reading memory size... "); // send Read Memory command buffer[0] = CMD_READ_MEMORY; // Read Memory command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Read Memory command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of Read Memory command\n"); exit(1); } // get initial ACK in response to Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read initial ACK in response to Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive initial ACK in response to Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive initial ACK in response to Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send memory address plus checksum address.value = 0x1FFFF7E0; // information section if(!WriteFile(hComm, &address.bytes[3], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[3] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[3] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[2], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[2] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[2] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[1], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[1] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[1] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[0], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[0] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[0] for Read Memory command\n"); exit(1); } checksum = address.bytes[0] ^ address.bytes[1] ^ address.bytes[2] ^ address.bytes[3]; // this is not a checksum if(!WriteFile(hComm, &checksum, 1, &number, NULL)) { fprintf(stderr, "error: could not write address checksum for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address checksum for Read Memory command\n"); exit(1); } // get ACK in response to address checksum for Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read address checksum ACK for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read address checksum ACK for Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: address (range or checksum) failure in response to Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send number of bytes + 1 to receive + complement i = 4; // 4 bytes buffer[0] = i - 1; // byte count - 1 buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send byte count in Read Memory command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send byte count in Read Memory command\n"); exit(1); } // get ACK for byte count in Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read ACK for byte count in Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read ACK for byte count in Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive ACK for byte count in Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // get data if(!ReadFile(hComm, buffer, i, &number, NULL)) { fprintf(stderr, "error: could not receive data for Read Memory command\n"); exit(1); } if(number != i) { fprintf(stderr, "error: did not receive data for Read Memory command\n"); exit(1); } if(verbosity > 1) printf("ok\n"); flash_kb = (buffer[1] << 8) + buffer[0]; sram_kb = (buffer[3] << 8) + buffer[2]; if(flags.identify_flag) { printf("Flash memory size: %i KB\n", flash_kb); printf("SRAM memory size: "); // preface if(sram_kb = 0xFFFF) { // Rev A silicon - assuming performance line parts switch(flash_kb) { case 32: printf("10"); break; case 64: case 128: printf("20"); break; default: printf("???"); break; } } else { printf("%i", sram_kb); // actual SRAM size } printf(" KB\n"); } if(argv_filename) { // load file into file buffer if(verbosity > 1) printf("Reading file... "); hFile = CreateFile(argv[argv_filename], FILE_READ_DATA, 0, NULL, OPEN_EXISTING, 0, 0); if(hFile == INVALID_HANDLE_VALUE) { fprintf(stderr, "error: could not open file for reading\n"); exit(1); } file_size = GetFileSize(hFile, NULL); // get file size if(file_size == INVALID_FILE_SIZE) { fprintf(stderr, "error: could not determine file size\n"); exit(1); } if(file_size == 0) { fprintf(stderr, "error: file is empty\n"); exit(1); } if(file_size > (flash_kb * 1024)) { fprintf(stderr, "error: file is larger than chip's FLASH memory\n"); exit(1); } file_buffer = malloc(file_size); // allocate memory for file buffer if(file_buffer == NULL) { fprintf(stderr, "error: could not allocate enough memory for file buffer\n"); exit(1); } if(!ReadFile(hFile, file_buffer, file_size, &number, NULL)) { fprintf(stderr, "error: could not read file\n"); exit(1); } if(number != file_size) { fprintf(stderr, "error: did not read file\n"); exit(1); } if(verbosity > 1) printf("ok\n"); if(verbosity > 1) printf("File size = %i\n", file_size); CloseHandle(hFile); // close file handle } if(flags.erase_flag || flags.erase_entire_flag) { // send Erase command if(verbosity) printf("Erasing device... "); buffer[0] = CMD_ERASE; // Erase command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Erase command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of Erase command\n"); exit(1); } // receive initial ACK in response to Erase command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not receive initial ACK in response to Erase command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive initial ACK in response to Erase command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive initial ACK in response to Erase command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } if(flags.erase_entire_flag) { // erase 'em all // send erase page count (0xFF = infinity) buffer[0] = 0xFF; // all pages buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send page count (0xFF) for Erase command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of page count for Erase command\n"); exit(1); } } else { // optimized erase based on file size if(argv_filename == 0) { fprintf(stderr, "error: file required for optimized erase\n"); exit(1); } // build list of pages that need to be erased pages = (file_size / 1024) + 1; // the actual number of 1K pages that need to be erased buffer[0] = pages - 1; // number of pages that need to be erased - 1 //printf("[file size = %i, pages to erase = %i]\n", file_size, pages); // *** debug *** checksum = buffer[0]; // initial value for checksum for(page = 0; page < pages; page++) { //printf("[erase page %i]\n", page); // *** debug *** buffer[page + 1] = page; checksum ^= page; } //printf("[checksum = 0x%02X]\n", checksum); // *** debug *** buffer[pages + 1] = checksum; //for(i = 0; i < (pages + 2); i++) { printf("buffer[%i] = 0x%02X\n", i, buffer[i]); } // *** debug *** //printf("[sending %i bytes]\n", pages + 2); // *** debug *** // send page count, list of pages to be erased along with checksum if(!WriteFile(hComm, buffer, (pages + 2), &number, NULL)) { fprintf(stderr, "error: could not send list of pages to be erased\n"); exit(1); } if(number != (pages + 2)) { fprintf(stderr, "error: did not send complete list of pages to be erased\n"); exit(1); } } Sleep(pages * 50); // supposedly 40ms max erase time per page; probly faster to adjust serial port timeout and respond immediately // wait for final ACK in response to the Erase command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not receive final ACK in response to Erase command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive final ACK in response to Erase command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive final ACK in response to Erase command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } if(verbosity) printf("ok\n"); } if(argv_filename) { if(flags.output_flag == 1) { // read file from chip and write to file // open output file for writing if(verbosity > 1) printf("Creating output file '%s' ... ", argv[argv_filename]); hFile = CreateFile(argv[argv_filename], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile == INVALID_HANDLE_VALUE) { fprintf(stderr, "error: could not create output file\n"); exit(1); } if(verbosity > 1) printf("ok\n"); if(verbosity > 1) printf("Reading chip "); for(page = 0; page < (flash_kb * 4); page++) { if(verbosity) if((page & 0x03) == 0x00) printf("."); // tick mark per 1K to show progress // send the Read Memory command //if(verbosity > 1) printf("Reading device... "); buffer[0] = CMD_READ_MEMORY; // Read Memory command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Read Memory command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of Read Memory command\n"); exit(1); } // get initial ACK in response to the Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read initial ACK in response to Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive initial ACK in response to Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive initial ACK in response to Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send memory address plus checksum address.value = 0x08000000 + (page * 256); if(!WriteFile(hComm, &address.bytes[3], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[3] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[3] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[2], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[2] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[2] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[1], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[1] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[1] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[0], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[0] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[0] for Read Memory command\n"); exit(1); } checksum = address.bytes[0] ^ address.bytes[1] ^ address.bytes[2] ^ address.bytes[3]; // this is not a checksum if(!WriteFile(hComm, &checksum, 1, &number, NULL)) { fprintf(stderr, "error: could not write address checksum for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address checksum for Read Memory command\n"); exit(1); } // get ACK in response to address checksum for Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read address checksum ACK for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read address checksum ACK for Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: address (range or checksum) failure in response to Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send number of bytes + 1 to receive + complement i = 256; // 256 bytes buffer[0] = i - 1; // byte count - 1 buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send byte count in Read Memory command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send byte count in Read Memory command\n"); exit(1); } // get ACK for byte count in Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read ACK for byte count in Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read ACK for byte count in Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive ACK for byte count in Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // get data if(!ReadFile(hComm, buffer, i, &number, NULL)) { fprintf(stderr, "error: could not receive data for Read Memory command\n"); exit(1); } if(number != i) { fprintf(stderr, "error: did not receive data for Read Memory command\n"); exit(1); } // write data to file if(!WriteFile(hFile, buffer, 256, &number, NULL)) { fprintf(stderr, "error: could not write to output file\n"); exit(1); } if(number != 256) { fprintf(stderr, "error: did not write all bytes to output file\n"); exit(1); } } if(verbosity) printf(" done\n"); CloseHandle(hFile); // close the new file } else { // write to chip if(verbosity) printf("Writing file '%s' to device... ", argv[argv_filename]); remaining_bytes = file_size; // initialize byte downcounter //address.value = 0x08000000; // start of FLASH memory address.value = base_address; file_buffer_p = file_buffer; //printf("[starting address = 0x%08X, remaining bytes = %i]\n", address.value, remaining_bytes); // *** debug *** while(remaining_bytes) { //printf("[writing to 0x%08X - %i bytes]\n", address.value, remaining_bytes); // *** debug *** // send Write Memory command buffer[0] = CMD_WRITE_MEMORY; // Write Memory command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Write Memory command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of Write Memory command\n"); exit(1); } // receive initial ACK in response to Write Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not receive initial ACK in response to Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive initial ACK in response to Write Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive initial ACK in response to Write Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send memory address plus checksum if(!WriteFile(hComm, &address.bytes[3], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[3] for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[3] for Write Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[2], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[2] for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[2] for Write Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[1], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[1] for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[1] for Write Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[0], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[0] for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[0] for Write Memory command\n"); exit(1); } checksum = address.bytes[0] ^ address.bytes[1] ^ address.bytes[2] ^ address.bytes[3]; // this is not a checksum if(!WriteFile(hComm, &checksum, 1, &number, NULL)) { fprintf(stderr, "error: could not write address checksum for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address checksum for Write Memory command\n"); exit(1); } // get ACK in response to address checksum for Write Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read address checksum ACK for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read address checksum ACK for Write Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: address (range or checksum) failure in response to Write Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send byte count for Write Memory command buffer_size = (remaining_bytes > 256) ? 256 : remaining_bytes; // a maximum of 256 bytes, or however many bytes are remaining to be sent buffer[0] = buffer_size - 1; if(!WriteFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not send byte count for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not send byte count for Write Memory command\n"); exit(1); } // send data if(!WriteFile(hComm, file_buffer_p, buffer_size, &number, NULL)) { fprintf(stderr, "error: could not send data for Write Memory command\n"); exit(1); } if(number != buffer_size) { fprintf(stderr, "error: did not send data for Write Memory command\n"); exit(1); } // calculate & transmit data checksum, which includes "byte count - 1" buffer[0] = buffer_size - 1; for(i = 0; i < buffer_size; i++) buffer[0] ^= file_buffer_p[i]; if(!WriteFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not send data checksum for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not send data checksum for Write Memory command\n"); exit(1); } // get final ACK in response to Write Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read final ACK for Write Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read final ACK for Write Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: write or checksum failure in response to Write Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // end-of-loop calculations remaining_bytes -= buffer_size; // that many less to do address.value += buffer_size; file_buffer_p += buffer_size; } if(verbosity) printf("ok\n"); //printf("[sent %i bytes]\n", address.value - 0x08000000); // *** debug *** } } if(flags.verify_flag) { if(argv_filename == 0) { fprintf(stderr, "error: verify requires filename\n"); exit(1); } if(verbosity) printf("Verifying... "); remaining_bytes = file_size; // initialize byte downcounter //address.value = 0x08000000; // start of FLASH memory address.value = base_address; file_buffer_p = file_buffer; while(remaining_bytes) { // send the Read Memory command buffer[0] = CMD_READ_MEMORY; // Read Memory command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Read Memory command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of Read Memory command\n"); exit(1); } // get initial ACK in response to the Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read initial ACK in response to Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive initial ACK in response to Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive initial ACK in response to Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send memory address plus checksum if(!WriteFile(hComm, &address.bytes[3], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[3] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[3] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[2], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[2] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[2] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[1], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[1] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[1] for Read Memory command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[0], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[0] for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[0] for Read Memory command\n"); exit(1); } checksum = address.bytes[0] ^ address.bytes[1] ^ address.bytes[2] ^ address.bytes[3]; // this is not a checksum if(!WriteFile(hComm, &checksum, 1, &number, NULL)) { fprintf(stderr, "error: could not write address checksum for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address checksum for Read Memory command\n"); exit(1); } // get ACK in response to address checksum for Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read address checksum ACK for Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read address checksum ACK for Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: address (range or checksum) failure in response to Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send number of bytes + 1 to receive + complement buffer_size = (remaining_bytes > 256) ? 256 : remaining_bytes; // a maximum of 256 bytes, or however many bytes are remaining to be verified buffer[0] = buffer_size - 1; buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send byte count in Read Memory command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send byte count in Read Memory command\n"); exit(1); } // get ACK for byte count in Read Memory command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read ACK for byte count in Read Memory command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read ACK for byte count in Read Memory command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive ACK for byte count in Read Memory command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // get data if(!ReadFile(hComm, buffer, buffer_size, &number, NULL)) { fprintf(stderr, "error: could not receive data for Read Memory command\n"); exit(1); } if(number != buffer_size) { fprintf(stderr, "error: did not receive data for Read Memory command\n"); exit(1); } // compare memory and file contents //buffer[0] = 0x55; // rig it to fail if(memcmp(buffer, file_buffer_p, buffer_size) != 0) { fprintf(stderr, "error: verify error\n"); exit(1); } // end-of-loop calculations remaining_bytes -= buffer_size; // that many less to do address.value += buffer_size; file_buffer_p += buffer_size; } if(verbosity) printf("ok\n"); } if(flags.execute_flag) { // send the Go command if(verbosity) printf("Executing newly downloaded code... "); buffer[0] = CMD_GO; // Go command buffer[1] = ~buffer[0]; // complement if(!WriteFile(hComm, buffer, 2, &number, NULL)) { fprintf(stderr, "error: could not send Go command\n"); exit(1); } if(number != 2) { fprintf(stderr, "error: did not send both bytes of Go command\n"); exit(1); } // get initial ACK in response to Go command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read initial ACK in response to Go command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not receive initial ACK in response to Go command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: did not receive initial ACK in response to Go command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } // send Go address plus checksum //address.value = 0x08000000; // beginning of FLASH memory address.value = base_address; if(!WriteFile(hComm, &address.bytes[3], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[3] for Go command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[3] for Go command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[2], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[2] for Go command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[2] for Go command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[1], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[1] for Go command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[1] for Go command\n"); exit(1); } if(!WriteFile(hComm, &address.bytes[0], 1, &number, NULL)) { fprintf(stderr, "error: could not write address[0] for Go command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address[0] for Go command\n"); exit(1); } checksum = address.bytes[0] ^ address.bytes[1] ^ address.bytes[2] ^ address.bytes[3]; // this is not a checksum if(!WriteFile(hComm, &checksum, 1, &number, NULL)) { fprintf(stderr, "error: could not write address checksum for Go command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not write address checksum for Go command\n"); exit(1); } // get ACK in response to address checksum for Go command if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read address checksum ACK for Go command\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not read address checksum ACK for Go command\n"); exit(1); } if(buffer[0] != ACK) { fprintf(stderr, "error: address (range or checksum) failure in response to Go command (received 0x%02X)\n", (unsigned char) buffer[0]); exit(1); } if(verbosity) printf("ok\n"); } if(flags.terminal_flag) { if(verbosity) printf("Entering terminal mode. Type Ctrl-C to exit.\n"); // clear any junk from input queue if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read junk from input queue in terminal mode\n"); exit(1); } // loop until program is terminated while(1) { // handle incoming data if(!ReadFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not read from serial port in terminal mode\n"); exit(1); } if(number) { buffer[number] = '\0'; // nul terminate received string printf("%s", buffer); // print received string } // handle outgoing data if(kbhit()) { buffer[0] = getchar(); if(!WriteFile(hComm, buffer, 1, &number, NULL)) { fprintf(stderr, "error: could not transmit character in terminal mode\n"); exit(1); } if(number != 1) { fprintf(stderr, "error: did not transmit character in terminal mode\n"); exit(1); } } } } free(file_buffer); // release allocated memory buffer CloseHandle(hComm); // close com port handle return 0; // done } // [end-of-file]