changeset 9:fea204bc7674

fc-sertool compiles
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Wed, 01 May 2013 02:43:17 +0000
parents acaac9162574
children e2e80a09338e
files .hgignore loadtools/Makefile loadtools/romload.c loadtools/sercomm.c loadtools/sertool.c loadtools/srecreader.c
diffstat 6 files changed, 351 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Apr 30 21:35:14 2013 +0000
+++ b/.hgignore	Wed May 01 02:43:17 2013 +0000
@@ -5,6 +5,8 @@
 \.bin$
 \.srec$
 
+^loadtools/fc-sertool
+
 ^toolchain/binutils-2.21.1/
 ^toolchain/binutils-build/
 ^toolchain/gcc-4.5.4/
--- a/loadtools/Makefile	Tue Apr 30 21:35:14 2013 +0000
+++ b/loadtools/Makefile	Wed May 01 02:43:17 2013 +0000
@@ -1,8 +1,14 @@
 CC=	gcc
 CFLAGS=	-O2
-OBJS=	hexdecode.o sercomm.o srecreader.o ttypassthru.o
+PROGS=	fc-sertool
+
+SERTOOL_OBJS=	hexdecode.o romload.o sercomm.o sertool.o srecreader.o \
+		ttypassthru.o
 
-all:	${OBJS}
+all:	${PROGS}
+
+fc-sertool:	${SERTOOL_OBJS}
+	${CC} -o $@ ${SERTOOL_OBJS}
 
 clean:
-	rm -f *.o *.out *errs
+	rm -f *.o *.out *errs ${PROGS}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/romload.c	Wed May 01 02:43:17 2013 +0000
@@ -0,0 +1,269 @@
+/*
+ * This module implements the communication protocol for pushing our
+ * IRAM-loadable code to the Calypso ROM bootloader.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <termios.h>
+#include <unistd.h>
+#include "srecreader.h"
+
+extern int errno;
+
+extern char *target_ttydev;
+extern int target_fd;
+
+struct srecreader iramimage;
+
+static int beacon_interval = 13;	/* in milliseconds */
+
+static u_char beacon_cmd[2] = {'<', 'i'};
+
+static u_char param_cmd[11] = {'<', 'p',
+			0x00,	/* baud rate select code (115200) */
+			0x00,	/* DPLL setup: leave it off like on power-up, */
+				/* OsmocomBB does the same thing */
+			0x00, 0x04,	/* chip select timing (WS) settings */
+					/* our setting matches both OsmocomBB */
+					/* and what the ROM runs with */
+					/* before receiving this command */
+			0x22,	/* FFFF:F900 register config, low byte */
+				/* OsmocomBB sends 0x00 here, but I've chosen */
+				/* 0x22 to match the setting of this register */
+				/* used by the boot ROM before this command. */
+			0x00, 0x01, 0xD4, 0xC0	/* UART timeout */
+				/* I've chosen the same value as what the */
+				/* boot ROM runs with before getting this cmd */
+};
+
+static u_char write_cmd[10] = {'<', 'w', 0x01, 0x01, 0x00};
+static u_char cksum_cmd[3]  = {'<', 'c'};
+static u_char branch_cmd[6] = {'<', 'b'};
+
+#define	INTERMEDIATE_TIMEOUT	500	/* ms to wait for responses */
+#define	SERIAL_FLUSH_DELAY	200	/* also in ms */
+
+/*
+ * The following function should be called by command line option
+ * parsers upon encountering the -i option.
+ */
+set_beacon_interval(arg)
+	char *arg;
+{
+	int i;
+
+	i = atoi(arg);
+	if (i < 2 || i > 500) {
+		fprintf(stderr, "invalid -i argument specified\n");
+		exit(1);
+	}
+	beacon_interval = i;
+}
+
+static int
+expect_response(timeout)
+{
+	char buf[2];
+	fd_set fds;
+	struct timeval tv;
+	int pass, cc;
+
+	for (pass = 0; pass < 2; ) {
+		FD_ZERO(&fds);
+		FD_SET(target_fd, &fds);
+		tv.tv_sec = 0;
+		tv.tv_usec = timeout * 1000;
+		cc = select(target_fd+1, &fds, NULL, NULL, &tv);
+		if (cc < 0) {
+			if (errno == EINTR)
+				continue;
+			perror("select");
+			exit(1);
+		}
+		if (cc < 1)
+			return(-1);
+		cc = read(target_fd, buf + pass, 2 - pass);
+		if (cc <= 0) {
+			perror("read after successful select");
+			exit(1);
+		}
+		if (pass == 0 && buf[0] != '>')
+			continue;
+		pass += cc;
+	}
+	return(buf[1]);
+}
+
+static
+send_beacons()
+{
+	printf("Sending beacons to %s\n", target_ttydev);
+	do
+		write(target_fd, beacon_cmd, sizeof beacon_cmd);
+	while (expect_response(beacon_interval) != 'i');
+	return 0;
+}
+
+static uint32_t
+compute_block_cksum()
+{
+	uint32_t sum;
+	int i, llen;
+
+	sum = iramimage.datalen + 5;
+	llen = iramimage.datalen + 4;
+	for (i = 0; i < llen; i++)
+		sum = iramimage.record[i+1];
+	return sum;
+}
+
+perform_romload()
+{
+	int resp;
+	uint16_t image_cksum;
+	unsigned long rec_count;
+	static int zero = 0;
+
+	if (open_srec_file(&iramimage) < 0)
+		exit(1);
+	ioctl(target_fd, FIONBIO, &zero);
+	send_beacons();
+	printf("Got beacon response, attempting download\n");
+
+	usleep(SERIAL_FLUSH_DELAY * 1000);
+	tcflush(target_fd, TCIFLUSH);
+	write(target_fd, param_cmd, sizeof param_cmd);
+	resp = expect_response(INTERMEDIATE_TIMEOUT);
+	if (resp != 'p') {
+		if (resp < 0)
+			fprintf(stderr, "No response to <p command\n");
+		else if (isprint(resp))
+			fprintf(stderr,
+			"Got >%c in response to <p command; expected >p\n",
+				resp);
+		else
+			fprintf(stderr,
+			"Got > %02X in response to <p command; expected >p\n",
+				resp);
+		exit(1);
+	}
+	printf("<p command successful, switching to 115200 baud\n");
+	switch_baud_rate(B115200);
+	usleep(SERIAL_FLUSH_DELAY * 1000);
+	tcflush(target_fd, TCIFLUSH);
+
+	image_cksum = 0;
+	for (rec_count = 0; ; rec_count++) {
+		if (read_s_record(&iramimage) < 0)
+			exit(1);
+		switch (iramimage.record_type) {
+		case '0':
+			if (iramimage.lineno == 1)
+				continue;
+			fprintf(stderr,
+		"%s: S0 record found in line %d (expected in line 1 only)\n",
+				iramimage.filename, iramimage.lineno);
+			exit(1);
+		case '3':
+		case '7':
+			if (s3s7_get_addr_data(&iramimage) < 0)
+				exit(1);
+			break;
+		default:
+			fprintf(stderr,
+				"%s line %d: S%c record type not supported\n",
+				iramimage.filename, iramimage.lineno,
+				iramimage.record_type);
+			exit(1);
+		}
+		if (iramimage.record_type == '7')
+			break;
+		/* must be S3 */
+		if (iramimage.datalen < 1) {
+			fprintf(stderr,
+				"%s line %d: S3 record has zero data length\n",
+				iramimage.filename, iramimage.lineno);
+			exit(1);
+		}
+		/* form <w command */
+		if (!rec_count)
+			printf("Sending image payload\n");
+		write_cmd[5] = iramimage.datalen;
+		bcopy(iramimage.record + 1, write_cmd + 6, 4);
+		write(target_fd, write_cmd, sizeof write_cmd);
+		write(target_fd, iramimage.record + 5, iramimage.datalen);
+		/* update our checksum accumulator */
+		image_cksum += ~(compute_block_cksum() & 0xFF);
+		/* collect response */
+		resp = expect_response(INTERMEDIATE_TIMEOUT);
+		if (resp != 'w') {
+			fprintf(stderr, "Block #%lu: ", rec_count);
+			if (resp < 0)
+				fprintf(stderr, "No response to <w command\n");
+			else if (isprint(resp))
+				fprintf(stderr,
+			"Got >%c in response to <w command; expected >w\n",
+					resp);
+			else
+				fprintf(stderr,
+			"Got > %02X in response to <w command; expected >w\n",
+					resp);
+			exit(1);
+		}
+		/* on to the next record! */
+	}
+	/* got S7 */
+	fclose(iramimage.openfile);
+	if (!rec_count) {
+		fprintf(stderr,
+		"%s line %d: S7 without any preceding S3 data records\n",
+			iramimage.filename, iramimage.lineno);
+		exit(1);
+	}
+
+	/* send <c */
+	printf("Sending checksum\n");
+	cksum_cmd[2] = ~(image_cksum & 0xFF);
+	write(target_fd, cksum_cmd, sizeof cksum_cmd);
+	resp = expect_response(INTERMEDIATE_TIMEOUT);
+	if (resp != 'c') {
+		if (resp < 0)
+			fprintf(stderr, "No response to <c command\n");
+		else if (isprint(resp))
+			fprintf(stderr,
+			"Got >%c in response to <c command; expected >c\n",
+				resp);
+		else
+			fprintf(stderr,
+			"Got > %02X in response to <c command; expected >c\n",
+				resp);
+		exit(1);
+	}
+	printf("<c command successful, sending <b\n");
+
+	bcopy(iramimage.record + 1, branch_cmd + 2, 4);
+	write(target_fd, branch_cmd, sizeof branch_cmd);
+	resp = expect_response(INTERMEDIATE_TIMEOUT);
+	if (resp != 'b') {
+		if (resp < 0)
+			fprintf(stderr, "No response to <b command\n");
+		else if (isprint(resp))
+			fprintf(stderr,
+			"Got >%c in response to <b command; expected >b\n",
+				resp);
+		else
+			fprintf(stderr,
+			"Got > %02X in response to <b command; expected >b\n",
+				resp);
+		exit(1);
+	}
+	printf("<b command successful: downloaded image should now be running!\n");
+	return(0);
+}
--- a/loadtools/sercomm.c	Tue Apr 30 21:35:14 2013 +0000
+++ b/loadtools/sercomm.c	Wed May 01 02:43:17 2013 +0000
@@ -37,3 +37,13 @@
 	}
 	return 0;
 }
+
+switch_baud_rate(code)
+{
+	cfsetispeed(&target_termios, code);
+	cfsetospeed(&target_termios, code);
+	if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) {
+		perror("tcsetattr to switch baud rate");
+		exit(1);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/sertool.c	Wed May 01 02:43:17 2013 +0000
@@ -0,0 +1,45 @@
+/*
+ * This module contains the main() function for fc-sertool: the simplest
+ * of the FreeCalypso loading tools, which sends the user-specified
+ * IRAM SREC image to the boot ROM and then switches into serial tty
+ * pass-through.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "srecreader.h"
+
+extern char *target_ttydev;
+extern struct srecreader iramimage;
+
+main(argc, argv)
+	char **argv;
+{
+	extern char *optarg;
+	extern int optind;
+	int c;
+
+	while ((c = getopt(argc, argv, "i:")) != EOF)
+		switch (c) {
+		case 'i':
+			set_beacon_interval(optarg);
+			continue;
+		case '?':
+		default:
+usage:			fprintf(stderr,
+	"usage: fc-sertool [-i beacon-interval] ttyport iramimage.srec\n");
+			exit(1);
+		}
+	if (argc - optind != 2)
+		goto usage;
+	target_ttydev = argv[optind];
+	iramimage.filename = argv[optind+1];
+
+	open_target_serial();
+	perform_romload();
+	tty_passthru();
+	exit(0);
+}
--- a/loadtools/srecreader.c	Tue Apr 30 21:35:14 2013 +0000
+++ b/loadtools/srecreader.c	Wed May 01 02:43:17 2013 +0000
@@ -88,3 +88,19 @@
 		return(-1);
 	return srec_cksum(sr);
 }
+
+s3s7_get_addr_data(sr)
+	struct srecreader *sr;
+{
+	if (sr->record[0] < 5) {
+		fprintf(stderr, "%s line %d: S%c record is too short\n",
+			sr->filename, sr->lineno, sr->record_type);
+		return(-1);
+	}
+	sr->datalen = sr->record[0] - 5;
+	sr->addr = ((uint32_t)sr->record[1] << 24) |
+		   ((uint32_t)sr->record[2] << 16) |
+		   ((uint32_t)sr->record[3] << 8) |
+		    (uint32_t)sr->record[4];
+	return(0);
+}