summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Daniel <cd@maintech.de>2011-12-27 00:09:21 +0100
committerChristian Daniel <cd@maintech.de>2011-12-27 00:09:21 +0100
commita59a982503a2c4565afbf4442e05a1fb4fe01127 (patch)
tree5098717319097be7e3ee1e65d79a1de3d72c07e8
parent79c3f63c78d1cc86d890f9863d8510fa66777916 (diff)
add initial version of flasher tool
-rw-r--r--utils/rum-ba/Makefile87
-rw-r--r--utils/rum-ba/src/main.c86
-rw-r--r--utils/rum-ba/src/osmosdr.c104
-rw-r--r--utils/rum-ba/src/osmosdr.h12
-rw-r--r--utils/rum-ba/src/sam3u.c308
-rw-r--r--utils/rum-ba/src/sam3u.h19
-rw-r--r--utils/rum-ba/src/serial.c175
-rw-r--r--utils/rum-ba/src/serial.h14
-rw-r--r--utils/rum-ba/src/utils.c49
-rw-r--r--utils/rum-ba/src/utils.h9
10 files changed, 863 insertions, 0 deletions
diff --git a/utils/rum-ba/Makefile b/utils/rum-ba/Makefile
new file mode 100644
index 0000000..a7da2ae
--- /dev/null
+++ b/utils/rum-ba/Makefile
@@ -0,0 +1,87 @@
+# binary file name
+TARGET=sdr-samba
+
+# CROSS_COMPILE=
+QUIET=@
+
+# N = build release version
+# y = optimize but include debugger info
+# Y = build debug version
+DEBUG=N
+
+C_SOURCES=\
+ src/main.c \
+ src/osmosdr.c \
+ src/sam3u.c \
+ src/serial.c \
+ src/utils.c
+
+# general compiler flags
+CFLAGS=-Wall
+LDFLAGS=-Wl,-Map=$(FULLTARGET).map
+LIBS=-lrt
+
+##############################################################################
+
+SUBDIRS=$(sort $(dir $(C_SOURCES)))
+
+DEPDIR=deps
+OBJDIR=objs
+BINDIR=bin
+DEPDIRS=$(addprefix $(DEPDIR)/,$(SUBDIRS))
+OBJDIRS=$(addprefix $(OBJDIR)/,$(SUBDIRS))
+
+CC=$(CROSS_COMPILE)gcc
+LD=$(CROSS_COMPILE)gcc
+
+COBJS=$(C_SOURCES:%.c=%.o)
+DEPS=$(C_SOURCES:%.c=%.dep)
+FULLDEPS=$(addprefix $(DEPDIR)/,$(DEPS))
+FULLCOBJS=$(addprefix $(OBJDIR)/,$(COBJS))
+FULLTARGET=$(addprefix $(BINDIR)/,$(TARGET))
+
+ifeq ($(DEBUG),Y)
+ # debug version
+ CFLAGS+=-O0 -g3
+ LDFLAGS+=-g3
+else ifeq ($(DEBUG),y)
+ # optimized version with debugger info
+ CFLAGS+=-O2 -g3 -Werror -ffunction-sections -fdata-sections
+ LDFLAGS+=-g3 -Wl,--gc-sections
+else
+ # release version
+ CFLAGS+=-O2 -s -Werror -ffunction-sections -fdata-sections
+ LDFLAGS+=-s -Wl,--gc-sections
+endif
+
+.PHONY: all build clean distclean
+
+all: build
+
+build: $(FULLTARGET)
+
+-include $(FULLDEPS)
+
+$(FULLTARGET): $(DEPDIRS) $(OBJDIRS) $(BINDIR) $(FULLCOBJS)
+ @echo LD \ $(TARGET)
+ $(QUIET)$(LD) $(LDFLAGS) -o $(FULLTARGET) -Wl,--start-group $(FULLCOBJS) $(LIBS) -Wl,--end-group
+ $(QUIET)ln -sf $(FULLTARGET) $(TARGET)
+
+$(FULLCOBJS):
+ @echo C\ \ \ $(patsubst $(OBJDIR)/%,%,$(patsubst %.o,%.c, $@))
+ $(QUIET)$(CC) $(CFLAGS) $(CFLAGS_$(subst /,_,$(patsubst %.o,%,$@))) -MD -MP -MF $(patsubst %.o,$(DEPDIR)/%.dep,$(patsubst $(OBJDIR)/%,%,$@)) -c $(patsubst $(OBJDIR)/%,%,$(patsubst %.o,%.c, $@)) -o $@
+
+$(DEPDIRS):
+ $(QUIET)mkdir -p $@
+
+$(OBJDIRS):
+ $(QUIET)mkdir -p $@
+
+$(BINDIR):
+ $(QUIET)mkdir -p $@
+
+clean:
+ $(QUIET)echo CLEAN
+ $(QUIET)rm -Rf $(DEPDIR) $(OBJDIR) $(BINDIR) $(TARGET) $(TARGET).map *~ *.s *.ss
+
+distclean: clean
diff --git a/utils/rum-ba/src/main.c b/utils/rum-ba/src/main.c
new file mode 100644
index 0000000..6e68443
--- /dev/null
+++ b/utils/rum-ba/src/main.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "serial.h"
+#include "osmosdr.h"
+#include "utils.h"
+
+static int printSyntax()
+{
+ fprintf(stderr, "Error: Invalid command line!\n\n"
+ "syntax: sdr-samba /dev/ttyACM0 command\n"
+ "valid commands are:\n"
+ " - detect: detect OsmoSDR and print unique ID\n"
+ " - blink: blink LEDs on board\n"
+ " - ramload image.bin: load image.bin into SRAM and start it\n"
+ " - flash image.bin: write image.bin to FLASH\n");
+
+ return EXIT_FAILURE;
+}
+
+int main(int argc, char* argv[])
+{
+ int fd;
+ int res = -1;
+ void* bin;
+ size_t binSize;
+
+ if(argc < 3)
+ return printSyntax();
+
+ if(strcmp(argv[2], "detect") == 0) {
+ if(argc != 3)
+ return printSyntax();
+ if((fd = serialOpen(argv[1])) < 0)
+ return EXIT_FAILURE;
+ res = 0;
+ if(res >= 0)
+ res = osmoSDRDetect(fd);
+ if(res >= 0)
+ res = osmoSDRPrintUID(fd, 0);
+ if(res >= 0)
+ res = osmoSDRPrintUID(fd, 1);
+ serialClose(fd);
+ } else if(strcmp(argv[2], "blink") == 0) {
+ if(argc != 3)
+ return printSyntax();
+ if((fd = serialOpen(argv[1])) < 0)
+ return EXIT_FAILURE;
+ res = 0;
+ if(res >= 0)
+ res = osmoSDRDetect(fd);
+ if(res >= 0)
+ res = osmoSDRBlink(fd);
+ serialClose(fd);
+ } else if(strcmp(argv[2], "ramload") == 0) {
+ if(argc != 4)
+ return printSyntax();
+ if((bin = loadFile(argv[3], &binSize)) == NULL)
+ return EXIT_FAILURE;
+ if((fd = serialOpen(argv[1])) < 0)
+ return EXIT_FAILURE;
+ res = 0;
+ if(res >= 0)
+ res = osmoSDRDetect(fd);
+ if(res >= 0)
+ res = osmoSDRRamLoad(fd, bin, binSize);
+ serialClose(fd);
+ } else if(strcmp(argv[2], "flash") == 0) {
+ if(argc != 4)
+ return printSyntax();
+ if((bin = loadFile(argv[3], &binSize)) == NULL)
+ return EXIT_FAILURE;
+ if((fd = serialOpen(argv[1])) < 0)
+ return EXIT_FAILURE;
+ res = 0;
+ if(res >= 0)
+ res = osmoSDRDetect(fd);
+ if(res >= 0)
+ res = osmoSDRFlash(fd, bin, binSize);
+ serialClose(fd);
+ } else {
+ return printSyntax();
+ }
+
+ return (res < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/utils/rum-ba/src/osmosdr.c b/utils/rum-ba/src/osmosdr.c
new file mode 100644
index 0000000..b792138
--- /dev/null
+++ b/utils/rum-ba/src/osmosdr.c
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <unistd.h>
+#include "osmosdr.h"
+#include "sam3u.h"
+
+int osmoSDRDetect(int fd)
+{
+ uint32_t chipID;
+
+ if(sam3uDetect(fd, &chipID) < 0)
+ return -1;
+
+ if((chipID & 0xffffffe0) == 0x28000960) {
+ printf("Chip ID: 0x%08x -- ok\n", chipID);
+ } else {
+ printf("Chip ID: 0x%08x -- ERROR\n", chipID);
+ return -1;
+ }
+
+ return 0;
+}
+
+int osmoSDRPrintUID(int fd, int bank)
+{
+ uint8_t uniqueID[16];
+ int i;
+
+ if(sam3uReadUniqueID(fd, bank, uniqueID) < 0) {
+ fprintf(stderr, "could not read unique ID\n");
+ return -1;
+ }
+
+ printf("UID%d : ", bank);
+ for(i = 0; i < 16; i++)
+ printf("%02x", uniqueID[i]);
+ printf("\n");
+
+ return 0;
+}
+
+int osmoSDRBlink(int fd)
+{
+ int i;
+
+ if(sam3uWrite32(fd, 0x400e0e00 + 0x44, 1 << 19) < 0)
+ return -1;
+ if(sam3uWrite32(fd, 0x400e0e00 + 0x60, 1 << 19) < 0)
+ return -1;
+ if(sam3uWrite32(fd, 0x400e0e00 + 0x54, 1 << 19) < 0)
+ return -1;
+ if(sam3uWrite32(fd, 0x400e0e00 + 0x10, 1 << 19) < 0)
+ return -1;
+ if(sam3uWrite32(fd, 0x400e0e00 + 0x00, 1 << 19) < 0)
+ return -1;
+
+ for(i = 0; i < 10; i++) {
+ printf("on."); fflush(stdout);
+ if(sam3uWrite32(fd, 0x400e0e00 + 0x34, 1 << 19) < 0)
+ return -1;
+ usleep(250 * 1000);
+ printf("off."); fflush(stdout);
+ if(sam3uWrite32(fd, 0x400e0e00 + 0x30, 1 << 19) < 0)
+ return -1;
+ usleep(250 * 1000);
+ }
+
+ printf(" -- ok\n");
+ return 0;
+}
+
+int osmoSDRRamLoad(int fd, void* bin, size_t binSize)
+{
+ size_t ofs;
+ uint32_t tmp;
+
+ printf("Uploading %zu bytes @ 0x20001000", binSize);
+
+ for(ofs = 0; ofs < binSize; ofs += 4) {
+ if(sam3uWrite32(fd, 0x20001000 + ofs, ((uint32_t*)bin)[ofs / 4]) < 0)
+ return -1;
+ }
+
+ for(ofs = 0; ofs < binSize; ofs += 4) {
+ if(sam3uRead32(fd, 0x20001000 + ofs, &tmp) < 0)
+ return -1;
+ if(tmp != ((uint32_t*)bin)[ofs / 4]) {
+ printf(" -- RAM verify failed\n");
+ return -1;
+ }
+ }
+ printf(" -- ok\n");
+
+ printf("Starting @ 0x%08x\n", ((uint32_t*)bin)[1]);
+
+ if(sam3uRun(fd, ((uint32_t*)bin)[1]) < 0)
+ return -1;
+
+ return 0;
+}
+
+int osmoSDRFlash(int fd, void* bin, size_t binSize)
+{
+ return sam3uFlash(fd, 0, bin, binSize);
+}
diff --git a/utils/rum-ba/src/osmosdr.h b/utils/rum-ba/src/osmosdr.h
new file mode 100644
index 0000000..5ed3a51
--- /dev/null
+++ b/utils/rum-ba/src/osmosdr.h
@@ -0,0 +1,12 @@
+#ifndef INCLUDE_OSMOSDR_H
+#define INCLUDE_OSMOSDR_H
+
+#include <stdint.h>
+
+int osmoSDRDetect(int fd);
+int osmoSDRPrintUID(int fd, int bank);
+int osmoSDRBlink(int fd);
+int osmoSDRRamLoad(int fd, void* bin, size_t binSize);
+int osmoSDRFlash(int fd, void* bin, size_t binSize);
+
+#endif // INCLUDE_OSMOSDR_H
diff --git a/utils/rum-ba/src/sam3u.c b/utils/rum-ba/src/sam3u.c
new file mode 100644
index 0000000..ab6a2c3
--- /dev/null
+++ b/utils/rum-ba/src/sam3u.c
@@ -0,0 +1,308 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "sam3u.h"
+#include "serial.h"
+
+int sam3uRead32(int fd, uint32_t address, uint32_t* value)
+{
+ char str[32];
+ sprintf(str, "w%08X,4#", address);
+ if(serialPutS(fd, str) < 0)
+ return -1;
+ if(serialExpect(fd, "\n\r0x", 100) < 0)
+ return -1;
+ if(serialGetS(fd, str, 8, 100) < 0)
+ return -1;
+ str[8] = '\0';
+ errno = 0;
+ *value = strtoll(str, NULL, 16);
+ if(errno != 0) {
+ fprintf(stderr, "number conversion failed: %s", strerror(errno));
+ return -1;
+ }
+ if(serialExpect(fd, "\n\r>", 100) < 0)
+ return -1;
+ return 0;
+}
+
+int sam3uRead16(int fd, uint32_t address, uint16_t* value)
+{
+ char str[32];
+ sprintf(str, "h%08X,2#", address);
+ if(serialPutS(fd, str) < 0)
+ return -1;
+ if(serialExpect(fd, "\n\r0x", 100) < 0)
+ return -1;
+ if(serialGetS(fd, str, 4, 100) < 0)
+ return -1;
+ str[4] = '\0';
+ errno = 0;
+ *value = strtol(str, NULL, 16);
+ if(errno != 0) {
+ fprintf(stderr, "number conversion failed: %s", strerror(errno));
+ return -1;
+ }
+ if(serialExpect(fd, "\n\r>", 100) < 0)
+ return -1;
+ return 0;
+}
+
+int sam3uRead8(int fd, uint32_t address, uint8_t* value)
+{
+ char str[32];
+ sprintf(str, "o%08X,1#", address);
+ if(serialPutS(fd, str) < 0)
+ return -1;
+ if(serialExpect(fd, "\n\r0x", 100) < 0)
+ return -1;
+ if(serialGetS(fd, str, 2, 100) < 0)
+ return -1;
+ str[2] = '\0';
+ errno = 0;
+ *value = strtol(str, NULL, 16);
+ if(errno != 0) {
+ fprintf(stderr, "number conversion failed: %s", strerror(errno));
+ return -1;
+ }
+ if(serialExpect(fd, "\n\r>", 100) < 0)
+ return -1;
+ return 0;
+}
+
+int sam3uWrite32(int fd, uint32_t address, uint32_t value)
+{
+ char str[32];
+ sprintf(str, "W%08X,%08X#", address, value);
+ if(serialPutS(fd, str) < 0)
+ return -1;
+ if(serialExpect(fd, "\n\r>", 100) < 0)
+ return -1;
+ return 0;
+}
+
+int sam3uWrite16(int fd, uint32_t address, uint16_t value)
+{
+ char str[32];
+ sprintf(str, "H%08X,%04X#", address, value);
+ if(serialPutS(fd, str) < 0)
+ return -1;
+ if(serialExpect(fd, "\n\r>", 100) < 0)
+ return -1;
+ return 0;
+}
+
+int sam3uWrite8(int fd, uint32_t address, uint8_t value)
+{
+ char str[32];
+ sprintf(str, "O%08X,%02X#", address, value);
+ if(serialPutS(fd, str) < 0)
+ return -1;
+ if(serialExpect(fd, "\n\r>", 100) < 0)
+ return -1;
+ return 0;
+}
+
+int sam3uRun(int fd, uint32_t address)
+{
+ char str[32];
+ sprintf(str, "G%08X#", address);
+ if(serialPutS(fd, str) < 0)
+ return -1;
+ return 0;
+}
+
+int sam3uDetect(int fd, uint32_t* chipID)
+{
+ char c;
+
+ while(serialGetC(fd, &c, 100) >= 0) ;
+
+ if(serialPutS(fd, "T#") < 0)
+ return -1;
+
+ if(serialExpect(fd, "\n\r\n\r>", 100) < 0) {
+ fprintf(stderr, "did not receive expected answer\n");
+ return -1;
+ }
+
+ return sam3uRead32(fd, 0x400e0740, chipID);
+}
+
+int sam3uReadUniqueID(int fd, int bank, uint8_t* uniqueID)
+{
+ uint32_t regBase;
+ uint32_t flashBase;
+ uint32_t fsr;
+ int i;
+
+ switch(bank) {
+ case 0:
+ regBase = 0x400e0800;
+ flashBase = 0x80000;
+ break;
+ case 1:
+ regBase = 0x400e0a00;
+ flashBase = 0x100000;
+ break;
+ default:
+ fprintf(stderr, "illegal flash bank");
+ return -1;
+ }
+
+ if(sam3uWrite32(fd, regBase + 0x04, 0x5a00000e) < 0)
+ return -1;
+
+ do {
+ if(sam3uRead32(fd, regBase + 0x08, &fsr) < 0)
+ return -1;
+ } while((fsr & 1) != 0);
+
+ for(i = 0; i < 16; i++) {
+ if(sam3uRead8(fd, flashBase + i, uniqueID + i) < 0)
+ return -1;
+ }
+
+ if(sam3uWrite32(fd, regBase + 0x04, 0x5a00000f) < 0)
+ return -1;
+
+ do {
+ if(sam3uRead32(fd, regBase + 0x08, &fsr) < 0)
+ return -1;
+ } while((fsr & 1) == 0);
+
+ return 0;
+}
+
+int sam3uFlash(int fd, int bank, void* bin, size_t binSize)
+{
+ uint32_t regBase;
+ uint32_t flashBase;
+ uint32_t fsr;
+ uint32_t flID;
+ uint32_t flSize;
+ uint32_t flPageSize;
+ uint32_t flNbPlane;
+ uint8_t buf[8192];
+ uint32_t ofs;
+ uint32_t todo;
+ uint32_t len;
+ uint32_t idx;
+
+ switch(bank) {
+ case 0:
+ regBase = 0x400e0800;
+ flashBase = 0x80000;
+ break;
+ case 1:
+ regBase = 0x400e0a00;
+ flashBase = 0x100000;
+ break;
+ default:
+ fprintf(stderr, "illegal flash bank");
+ return -1;
+ }
+
+ printf("reading flash descriptor");
+
+ if(sam3uWrite32(fd, regBase + 0x04, 0x5a000000) < 0)
+ goto error;
+
+ do {
+ if(sam3uRead32(fd, regBase + 0x08, &fsr) < 0)
+ goto error;
+ } while((fsr & 1) == 0);
+
+
+ if(sam3uRead32(fd, regBase + 0x0c, &flID) < 0)
+ goto error;
+ if(sam3uRead32(fd, regBase + 0x0c, &flSize) < 0)
+ goto error;
+ if(sam3uRead32(fd, regBase + 0x0c, &flPageSize) < 0)
+ goto error;
+ if(sam3uRead32(fd, regBase + 0x0c, &flNbPlane) < 0)
+ goto error;
+
+ printf(" -- ok\n");
+ printf("Flash ID: 0x%08x\n", flID);
+ printf("Flash size: %d Bytes\n", flSize);
+ printf("Page size: %d Bytes\n", flPageSize);
+ printf("Number of planes: %d\n", flNbPlane);
+
+#if 1
+ printf("erasing flash"); fflush(stdout);
+
+ if(sam3uWrite32(fd, regBase + 0x04, 0x5a000005) < 0)
+ goto error;
+
+ do {
+ if(sam3uRead32(fd, regBase + 0x08, &fsr) < 0)
+ goto error;
+ } while((fsr & 1) == 0);
+
+ printf(" -- ok\n");
+#endif
+
+ ofs = 0;
+ for(todo = binSize; todo > 0; todo -= len) {
+ printf("flashing @ 0x%08x", ofs); fflush(stdout);
+ len = todo;
+ if(len > flPageSize)
+ len = flPageSize;
+ memset(buf, 0xff, sizeof(buf));
+ memcpy(buf, ((uint8_t*)bin) + ofs, len);
+ for(idx = 0; idx < flPageSize / 4; idx++) {
+ if(sam3uWrite32(fd, flashBase + ofs + (idx * 4), ((uint32_t*)buf)[idx]) < 0)
+ goto error;
+ }
+
+ if(sam3uWrite32(fd, regBase + 0x04, 0x5a000000 | ((ofs / flPageSize) << 8) | 0x03) < 0)
+ goto error;
+
+ do {
+ if(sam3uRead32(fd, regBase + 0x08, &fsr) < 0)
+ goto error;
+ } while((fsr & 1) == 0);
+
+ printf(" -- ok\n");
+
+ ofs += flPageSize;
+ }
+
+ ofs = 0;
+ for(todo = binSize; todo > 0; todo -= len) {
+ printf("verifying @ 0x%08x", ofs); fflush(stdout);
+ len = todo;
+ if(len > flPageSize)
+ len = flPageSize;
+
+ for(idx = 0; idx < flPageSize / 4; idx++) {
+ if(sam3uRead32(fd, flashBase + ofs + (idx * 4), ((uint32_t*)buf) + idx) < 0)
+ goto error;
+ }
+
+ if(memcmp(buf, ((uint8_t*)bin) + ofs, len) == 0)
+ printf(" -- ok\n");
+ else printf(" -- ERROR\n");
+
+ ofs += flPageSize;
+ }
+
+ printf("disabling SAM-BA"); fflush(stdout);
+ if(sam3uWrite32(fd, regBase + 0x04, 0x5a000000 | (1 << 8) | 0x0b) < 0)
+ goto error;
+
+ do {
+ if(sam3uRead32(fd, regBase + 0x08, &fsr) < 0)
+ goto error;
+ } while((fsr & 1) == 0);
+
+ printf(" -- ok\n");
+
+ return 0;
+
+error:
+ printf(" -- ERROR\n");
+ return -1;
+}
diff --git a/utils/rum-ba/src/sam3u.h b/utils/rum-ba/src/sam3u.h
new file mode 100644
index 0000000..190cd40
--- /dev/null
+++ b/utils/rum-ba/src/sam3u.h
@@ -0,0 +1,19 @@
+#ifndef INCLUDE_SAM3U_H
+#define INCLUDE_SAM3U_H
+
+#include <stdint.h>
+
+int sam3uRead32(int fd, uint32_t address, uint32_t* value);
+int sam3uRead16(int fd, uint32_t address, uint16_t* value);
+int sam3uRead8(int fd, uint32_t address, uint8_t* value);
+
+int sam3uWrite32(int fd, uint32_t address, uint32_t value);
+int sam3uWrite16(int fd, uint32_t address, uint16_t value);
+int sam3uWrite8(int fd, uint32_t address, uint8_t value);
+
+int sam3uRun(int fd, uint32_t address);
+int sam3uDetect(int fd, uint32_t* chipID);
+int sam3uReadUniqueID(int fd, int bank, uint8_t* uniqueID);
+int sam3uFlash(int fd, int bank, void* bin, size_t binSize);
+
+#endif // INCLUDE_SAM3U_H
diff --git a/utils/rum-ba/src/serial.c b/utils/rum-ba/src/serial.c
new file mode 100644
index 0000000..545a35a
--- /dev/null
+++ b/utils/rum-ba/src/serial.c
@@ -0,0 +1,175 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <poll.h>
+#include "serial.h"
+#include "utils.h"
+
+int serialOpen(const char* device)
+{
+ int fd = -1;
+ struct termios tios;
+
+ if((fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY)) < 0) {
+ fprintf(stderr, "could not open %s: %s\n", device, strerror(errno));
+ goto failed;
+ }
+ bzero(&tios, sizeof(tios));
+ tios.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
+ tios.c_iflag = IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = ICANON;
+ tios.c_cc[VMIN] = 1;
+ cfmakeraw(&tios);
+ if(tcflush(fd, TCIOFLUSH) < 0) {
+ fprintf(stderr, "tcflush() failed: %s\n", strerror(errno));
+ goto failed;
+ }
+ if(tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+ fprintf(stderr, "tcsetattr() failed: %s\n", strerror(errno));
+ goto failed;
+ }
+ if(tcflush(fd, TCIOFLUSH) < 0) {
+ fprintf(stderr, "tcflush() failed: %s\n", strerror(errno));
+ goto failed;
+ }
+
+ return fd;
+
+failed:
+ if(fd >= 0)
+ close(fd);
+ return -1;
+}
+
+void serialClose(int fd)
+{
+ if(fd >= 0)
+ close(fd);
+}
+
+int serialPutC(int fd, char c)
+{
+ if(write(fd, &c, sizeof(char)) != sizeof(char)) {
+ if(errno == EAGAIN) {
+ struct pollfd pollfd;
+ int res;
+ pollfd.fd = fd;
+ pollfd.events = POLLOUT;
+ pollfd.revents = 0;
+ do {
+ res = poll(&pollfd, 1, 250);
+ } while((res < 0) && (errno == EINTR));
+ if(res > 0) {
+ if(write(fd, &c, sizeof(char)) != sizeof(char)) {
+ fprintf(stderr, "write failed: %s\n", strerror(errno));
+ return -1;
+ } else {
+ return 0;
+ }
+ } else if(res == 0) {
+ fprintf(stderr, "write failed: %s\n", strerror(errno));
+ return -1;
+ } else {
+ fprintf(stderr, "poll failed: %s\n", strerror(errno));
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "write failed: %s\n", strerror(errno));
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+}
+
+int serialPutS(int fd, const char* str)
+{
+ while(*str != '\0') {
+ if(serialPutC(fd, *str++) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int serialGetC(int fd, char* c, int timeout)
+{
+ struct pollfd pollfd;
+ int res;
+
+ pollfd.fd = fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+
+ do {
+ res = poll(&pollfd, 1, timeout);
+ } while((res < 0) && (errno == EINTR));
+
+ if(res > 0) {
+ if(read(fd, c, sizeof(char)) != sizeof(char)) {
+ fprintf(stderr, "read failed: %s\n", strerror(errno));
+ return -1;
+ } else {
+ return 0;
+ }
+ } else if(res == 0) {
+ // timeout
+ return -1;
+ }
+
+ fprintf(stderr, "poll failed: %s\n", strerror(errno));
+ return -1;
+}
+
+int serialGetS(int fd, char* str, int len, int timeout)
+{
+ int todo = len;
+ uint64_t endTime = getTickCount() + timeout;
+
+ while(todo > 0) {
+ uint64_t now = getTickCount();
+
+ if(now < endTime) {
+ char c;
+ if(serialGetC(fd, &c, endTime - now) < 0)
+ return -1;
+ //printf("[%02x]", c);
+ *str++ = c;
+ todo--;
+ } else {
+ break;
+ }
+ }
+
+ return (todo > 0) ? -1 : 0;
+}
+
+int serialExpect(int fd, const char* str, int timeout)
+{
+ int todo = strlen(str);
+ uint64_t endTime = getTickCount() + timeout;
+
+ while(todo > 0) {
+ uint64_t now = getTickCount();
+
+ if(now < endTime) {
+ char c;
+ if(serialGetC(fd, &c, endTime - now) < 0)
+ return -1;
+ //printf("[%02x]", c);
+ if(c == *str++) {
+ todo--;
+ continue;
+ } else {
+ return -1;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return (todo > 0) ? -1 : 0;
+}
diff --git a/utils/rum-ba/src/serial.h b/utils/rum-ba/src/serial.h
new file mode 100644
index 0000000..6f70c4e
--- /dev/null
+++ b/utils/rum-ba/src/serial.h
@@ -0,0 +1,14 @@
+#ifndef INCLUDE_SERIAL_H
+#define INCLUDE_SERIAL_H
+
+#include <stdint.h>
+
+int serialOpen(const char* device);
+void serialClose(int fd);
+int serialPutC(int fd, char c);
+int serialPutS(int fd, const char* str);
+int serialGetC(int fd, char* c, int timeout);
+int serialGetS(int fd, char* str, int len, int timeout);
+int serialExpect(int fd, const char* str, int timeout);
+
+#endif // INCLUDE_SERIAL_H
diff --git a/utils/rum-ba/src/utils.c b/utils/rum-ba/src/utils.c
new file mode 100644
index 0000000..4d1e54c
--- /dev/null
+++ b/utils/rum-ba/src/utils.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/stat.h>
+#include "utils.h"
+
+uint64_t getTickCount()
+{
+ struct timespec t;
+
+ if(clock_gettime(CLOCK_MONOTONIC, &t) != 0)
+ return 0;
+ return (((uint64_t)t.tv_sec) * 1000) + (((uint64_t)t.tv_nsec) / 1000000);
+}
+
+void* loadFile(const char* filename, size_t* size)
+{
+ void* result = NULL;
+ struct stat statbuf;
+ FILE* f = NULL;
+
+ if(stat(filename, &statbuf) < 0) {
+ fprintf(stderr, "could not stat() file %s: %s\n", filename, strerror(errno));
+ goto failed;
+ }
+
+ if((result = calloc(1, statbuf.st_size)) == NULL) {
+ fprintf(stderr, "failed to allocate %zu bytes of memory\n", (size_t)statbuf.st_size);
+ goto failed;
+ }
+ if((f = fopen(filename, "rb")) == NULL) {
+ fprintf(stderr, "failed to open %s: %s\n", filename, strerror(errno));
+ goto failed;
+ }
+ if(fread(result, 1, statbuf.st_size, f) != statbuf.st_size) {
+ fprintf(stderr, "could not read all bytes: %s\n", strerror(errno));
+ goto failed;
+ }
+
+ fclose(f);
+ *size = (size_t)statbuf.st_size;
+ return result;
+
+failed:
+ if(f != NULL)
+ fclose(f);
+ return NULL;
+}
diff --git a/utils/rum-ba/src/utils.h b/utils/rum-ba/src/utils.h
new file mode 100644
index 0000000..a990dd6
--- /dev/null
+++ b/utils/rum-ba/src/utils.h
@@ -0,0 +1,9 @@
+#ifndef INCLUDE_UTILS_H
+#define INCLUDE_UTILS_H
+
+#include <stdint.h>
+
+uint64_t getTickCount();
+void* loadFile(const char* filename, size_t* size);
+
+#endif // INCLUDE_UTILS_H