From b3595cb0d56291c06fe75b8418eb6c6fbd6fc214 Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Sun, 15 Apr 2012 23:36:17 +0200 Subject: [PATCH] Adding read-memory command support --- isp_commands.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++- isp_main.c | 2 +- 2 files changed, 208 insertions(+), 3 deletions(-) diff --git a/isp_commands.c b/isp_commands.c index 1892ace..f269da9 100644 --- a/isp_commands.c +++ b/isp_commands.c @@ -19,6 +19,11 @@ #include #include +#include /* for open, close */ +#include +#include +#include + #include "isp_utils.h" extern int trace_on; @@ -30,11 +35,14 @@ struct isp_command { }; -#define SERIAL_BUFSIZE 128 +/* Max should be 1270 for read memory, a little bit more for writes */ +#define SERIAL_BUFSIZE 1300 #define SYNCHRO_START "?" #define SYNCHRO "Synchronized\r\n" #define SYNCHRO_OK "OK\r\n" +#define DATA_BLOCK_OK "OK\r\n" +#define DATA_BLOCK_RESEND "RESEND\r\n" #define SYNCHRO_ECHO_OFF "A 0\r\n" #define ISP_ABORT "" @@ -45,6 +53,7 @@ struct isp_command { #define READ_BOOT_VERSION "K\r\n" + char* error_codes[] = { "CMD_SUCCESS", "INVALID_COMMAND", @@ -264,6 +273,202 @@ int isp_cmd_boot_version(int arg_count, char** args) return 0; } +int isp_cmd_read_memory(int arg_count, char** args) +{ + /* Serial communication */ + char buf[SERIAL_BUFSIZE]; + int ret = 0, len = 0; + /* Arguments */ + unsigned long int addr = 0, count = 0; + char* out_file_name = NULL; + int out_fd = -1; + /* Reply handling */ + unsigned int lines = 0, blocks = 0; + unsigned int total_bytes_received = 0; + unsigned int i = 0; + + /* Check read-memory arguments */ + if (arg_count != 3) { + printf("read-memory command needs address and count. Both must be multiple of 4.\n"); + return -12; + } + addr = strtoul(args[0], NULL, 0); + count = strtoul(args[1], NULL, 0); + if (trace_on) { + printf("read-memory command called for 0x%08lx (%lu) bytes at address 0x%08lx.\n", + count, count, addr); + } + if ((addr & 0x03) || (count & 0x03)) { + printf("Address and count must be multiple of 4 for read-memory command.\n"); + return -11; + } + out_file_name = args[2]; + + /* Create read-memory request */ + len = snprintf(buf, SERIAL_BUFSIZE, "R %lu %lu\r\n", addr, count); + if (len > SERIAL_BUFSIZE) { + len = SERIAL_BUFSIZE; /* This should not happen if SERIAL_BUFSIZE is 32 or more ... */ + } + + /* Send read-memory request */ + if (isp_serial_write(buf, len) != len) { + printf("Unable to send read-memory request.\n"); + return -10; + } + /* And receive and decode the answer */ + usleep( 2000 ); + /* First, check return code. This will also remove the first 3 caracters from the + * reply so we get only interresting caracters in the buffer. */ + len = isp_serial_read(buf, 3, 3); + if (len <= 0) { + printf("Error reading memory.\n"); + return -9; + } + ret = isp_ret_code(buf, NULL); + if (ret != 0) { + printf("Error when trying to read %lu bytes of memory at address 0x%08lx.\n", count, addr); + return -8; + } + + /* Now, find the number of lines and the length of the reply. + * See section 21.4.3 of LPC11xx user's manual (UM10398) */ +#define LINE_DATA_LENGTH 45 +#define LINES_PER_BLOCK 20 +#define MAX_DATA_BLOCK_SIZE (LINES_PER_BLOCK * LINE_DATA_LENGTH) /* 900 */ +#define MAX_BYTES_PER_LINE (((LINE_DATA_LENGTH / 3) * 4) + 1 + 2) /* 60 + "line length" + \r\n */ +#define FILE_CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP) + lines = (count / LINE_DATA_LENGTH); + if (count % LINE_DATA_LENGTH) { + lines += 1; + } + blocks = (lines / LINES_PER_BLOCK); + if (lines % LINES_PER_BLOCK) { + blocks += 1; + } + if (trace_on) { + printf("Reading %d block(s) (%d line(s)).\n", blocks, lines); + } + /* Open file for writing if output is not stdout */ + if (strncmp(out_file_name, "-", strlen(out_file_name)) == 0) { + out_fd = STDOUT_FILENO; + } else { + out_fd = open(out_file_name, (O_WRONLY | O_CREAT | O_TRUNC), FILE_CREATE_MODE); + if (out_fd <= 0) { + perror("Unable to open or create file for writing"); + printf("Tried to open \"%s\".\n", out_file_name); + return -7; + } + } + + ret = 0; + /* Receive and decode the data */ + for (i=0; i= MAX_DATA_BLOCK_SIZE) { + blocksize = (MAX_BYTES_PER_LINE * LINES_PER_BLOCK); + if (trace_on) { + printf("Reading block %d (%d line(s)).\n", i, LINES_PER_BLOCK); + } + } else { + unsigned int remain = count - total_bytes_received; + unsigned int nb_last_lines = (remain / LINE_DATA_LENGTH); + if (remain % LINE_DATA_LENGTH) { + nb_last_lines += 1; + } + /* 4 bytes transmitted for each 3 data bytes */ + blocksize = ((remain / 3) * 4); + if (remain % 3) { + blocksize += 4; + } + /* Add one byte per line for the starting "length character" and two bytes per + * line for the ending "\r\n" */ + blocksize += (3 * nb_last_lines); + if (trace_on) { + printf("Reading block %d of size %u (%d line(s)).\n", i, blocksize, nb_last_lines); + } + } + len = isp_serial_read(buf, SERIAL_BUFSIZE, blocksize); + if (len <= 0) { + printf("Error reading memory.\n"); + ret = -6; + break; + } + usleep( 1000 ); + /* Now read the checksum, maybe not yet received */ + len += isp_serial_read((buf + len), (SERIAL_BUFSIZE - len), ((len > (int)blocksize) ? 0 : 3)); + if (len < 0) { /* Length may be null, as may already have received everything */ + printf("Error reading memory (checksum part).\n"); + ret = -5; + break; + } + /* Decode. This must be done before sending acknowledge because we must + * compute the checksum */ + decoded_size = isp_uu_decode(data, buf, blocksize); + received_checksum = strtoul((buf + blocksize), NULL, 10); + for (j=0; j 3) { + printf("Block %d still wrong after 3 attempts, aborting.\n", i); + ret = -2; + break; + } + /* Back to previous block */ + i--; + /* Ask for resend */ + if (isp_serial_write(DATA_BLOCK_RESEND, strlen(DATA_BLOCK_RESEND)) != strlen(DATA_BLOCK_RESEND)) { + printf("Unable to send resend request.\n"); + ret = -1; + break; + } + } + } + /* Close file */ + if (out_fd != STDOUT_FILENO) { + close(out_fd); + } + + return ret; +} + /* FIXME : Temporary place-holder */ int isp_cmd_null(int arg_count, char** args) @@ -279,7 +484,7 @@ int isp_cmd_null(int arg_count, char** args) static struct isp_command isp_cmds_list[] = { {"unlock", 0, isp_cmd_unlock}, {"write-to-ram", 0, isp_cmd_null}, /* isp_cmd_write-to-ram} */ - {"read-memory", 0, isp_cmd_null}, /* isp_cmd_read-memory} */ + {"read-memory", 3, isp_cmd_read_memory}, {"prepare-for-write", 0, isp_cmd_null}, /* isp_cmd_prepare-for-write} */ {"copy-ram-to-flash", 0, isp_cmd_null}, /* isp_cmd_copy-ram-to-flash} */ {"go", 0, isp_cmd_null}, /* isp_cmd_go} */ diff --git a/isp_main.c b/isp_main.c index 0b9ae27..f9e4dd2 100644 --- a/isp_main.c +++ b/isp_main.c @@ -50,7 +50,7 @@ void help(char *prog_name) " is one of:\n" \ " \t unlock \n" \ " \t write-to-ram \n" \ - " \t read-memory \n" \ + " \t read-memory address count file : read 'count' byte(s) from 'address', store then in 'file'\n" \ " \t prepare-for-write \n" \ " \t copy-ram-to-flash \n" \ " \t go \n" \ -- 2.43.0