sport: serial IO abstraction layer.

This commit is contained in:
Daniel Beer 2011-07-27 11:26:02 +12:00
parent eee0bc0352
commit b8dd765a5b
9 changed files with 257 additions and 248 deletions

View File

@ -65,7 +65,7 @@ mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \
fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.o \
cmddb.o stdcmd.o prog.o flash_bsl.o list.o simio.o simio_tracer.o \
simio_timer.o simio_wdt.o simio_hwmult.o simio_gpio.o aliasdb.o \
gdb_proto.o gdbc.o
gdb_proto.o gdbc.o sport.o
$(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
.c.o:

40
bsl.c
View File

@ -22,23 +22,18 @@
#include <string.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include "bsl.h"
#include "util.h"
#include "output.h"
#include "fet_error.h"
#if defined(__APPLE__) || defined(__OpenBSD__)
#define B460800 460800
#endif
#include "sport.h"
struct bsl_device {
struct device base;
int serial_fd;
sport_t serial_fd;
uint8_t reply_buf[256];
int reply_len;
};
@ -51,7 +46,7 @@ static int bsl_ack(struct bsl_device *dev)
{
uint8_t reply;
if (read_with_timeout(dev->serial_fd, &reply, 1) < 0) {
if (sport_read(dev->serial_fd, &reply, 1) < 0) {
printc_err("bsl: failed to receive reply\n");
return -1;
}
@ -74,13 +69,13 @@ static int bsl_sync(struct bsl_device *dev)
static const uint8_t c = DATA_HDR;
int tries = 2;
if (tcflush(dev->serial_fd, TCIFLUSH) < 0) {
if (sport_flush(dev->serial_fd) < 0) {
pr_error("bsl: tcflush");
return -1;
}
while (tries--)
if (!(write_all(dev->serial_fd, &c, 1) || bsl_ack(dev)))
if (!(sport_write_all(dev->serial_fd, &c, 1) || bsl_ack(dev)))
return 0;
printc_err("bsl: sync failed\n");
@ -122,7 +117,7 @@ static int send_command(struct bsl_device *dev,
pktbuf[pktlen + 4] = cklow;
pktbuf[pktlen + 5] = ckhigh;
return write_all(dev->serial_fd, pktbuf, pktlen + 6);
return sport_write_all(dev->serial_fd, pktbuf, pktlen + 6);
}
static int verify_checksum(struct bsl_device *dev)
@ -150,7 +145,7 @@ static int fetch_reply(struct bsl_device *dev)
dev->reply_len = 0;
for (;;) {
int r = read_with_timeout(dev->serial_fd,
int r = sport_read(dev->serial_fd,
dev->reply_buf + dev->reply_len,
sizeof(dev->reply_buf) -
dev->reply_len);
@ -208,7 +203,7 @@ static void bsl_destroy(device_t dev_base)
struct bsl_device *dev = (struct bsl_device *)dev_base;
bsl_xfer(dev, CMD_RESET, 0, NULL, 0);
close(dev->serial_fd);
sport_close(dev->serial_fd);
free(dev);
}
@ -326,11 +321,9 @@ static int bsl_erase(device_t dev_base, device_erase_type_t type,
static int enter_via_fet(struct bsl_device *dev)
{
uint8_t buf[16];
uint8_t *data = buf;
int len = 8;
/* Enter bootloader command */
if (write_all(dev->serial_fd,
if (sport_write_all(dev->serial_fd,
(uint8_t *)"\x7e\x24\x01\x9d\x5a\x7e", 6)) {
printc_err("bsl: couldn't write bootloader transition "
"command\n");
@ -338,19 +331,12 @@ static int enter_via_fet(struct bsl_device *dev)
}
/* Wait for reply */
while (len) {
int r = read_with_timeout(dev->serial_fd, data, len);
if (r < 0) {
if (sport_read_all(dev->serial_fd, buf, 8) < 0) {
printc_err("bsl: couldn't read bootloader "
"transition acknowledgement\n");
return -1;
}
data += r;
len -= r;
}
/* Check that it's what we expect */
if (memcmp(buf, "\x06\x00\x24\x00\x00\x00\x61\x01", 8)) {
printc_err("bsl: bootloader start returned error "
@ -380,8 +366,8 @@ static device_t bsl_open(const struct device_args *args)
dev->base.type = &device_bsl;
dev->serial_fd = open_serial(args->path, B460800);
if (dev->serial_fd < 0) {
dev->serial_fd = sport_open(args->path, B460800, 0);
if (SPORT_ISERR(dev->serial_fd)) {
printc_err("bsl: can't open %s: %s\n",
args->path, strerror(errno));
free(dev);
@ -412,7 +398,7 @@ static device_t bsl_open(const struct device_args *args)
return (device_t)dev;
fail:
close(dev->serial_fd);
sport_close(dev->serial_fd);
free(dev);
return NULL;
}

View File

@ -22,29 +22,24 @@
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include "flash_bsl.h"
#include "util.h"
#include "output.h"
#include "fet_error.h"
#include "sport.h"
struct flash_bsl_device {
struct device base;
int serial_fd;
sport_t serial_fd;
int long_password;
};
#define MAX_PACKET 256
/* adapted from TI's published BSL source code */
#define CRC_INIT 0xffff
static uint16_t crc_ccitt(const uint8_t *data, int len) {
@ -66,21 +61,24 @@ static void crc_selftest(void) {
uint16_t crc_expected = 0x5590;
uint16_t crc_actual = crc_ccitt((uint8_t *)"\x52\x02", 2);
if (crc_expected != crc_actual) {
printc_err("flash_bsl: CRC malfunction (expected 0x%04x got 0x%04x)\n",
printc_err("flash_bsl: CRC malfunction "
"(expected 0x%04x got 0x%04x)\n",
crc_expected, crc_actual);
}
crc_expected = 0x121d;
crc_actual = crc_ccitt((uint8_t *)"\x3a\x04\x01", 3);
if (crc_expected != crc_actual) {
printc_err("flash_bsl: CRC malfunction (expected 0x%04x got 0x%04x)\n",
printc_err("flash_bsl: CRC malfunction "
"(expected 0x%04x got 0x%04x)\n",
crc_expected, crc_actual);
}
crc_expected = 0x528b;
crc_actual = crc_ccitt((uint8_t *)"\x1a", 1);
if (crc_expected != crc_actual) {
printc_err("flash_bsl: CRC malfunction (expected 0x%04x got 0x%04x)\n",
printc_err("flash_bsl: CRC malfunction "
"(expected 0x%04x got 0x%04x)\n",
crc_expected, crc_actual);
}
@ -112,7 +110,8 @@ static int flash_bsl_send(struct flash_bsl_device *dev,
crc = crc_ccitt(data, len);
if (len > MAX_PACKET) {
printc_err("flash_bsl: attempted to transmit long packet (len=%d)\n", len);
printc_err("flash_bsl: attempted to transmit "
"long packet (len=%d)\n", len);
return -1;
}
@ -123,12 +122,12 @@ static int flash_bsl_send(struct flash_bsl_device *dev,
cmd_buf[len + 3] = (crc & 0xff);
cmd_buf[len + 4] = (crc >> 8) & 0xff;
if (write_all(dev->serial_fd, cmd_buf, len + 5) < 0) {
if (sport_write_all(dev->serial_fd, cmd_buf, len + 5) < 0) {
printc_err("flash_bsl: serial write failed\n");
return -1;
}
if (read_all_with_timeout(dev->serial_fd, &response, 1) < 0) {
if (sport_read_all(dev->serial_fd, &response, 1) < 0) {
if (errno == ETIMEDOUT) {
printc_err("flash_bsl: serial read timed out\n");
} else {
@ -140,16 +139,19 @@ static int flash_bsl_send(struct flash_bsl_device *dev,
if (response != 0) {
switch (response) {
case 0x51:
printc_err("flash_bsl: BSL reports incorrect packet header\n");
printc_err("flash_bsl: BSL reports incorrect "
"packet header\n");
break;
case 0x52:
printc_err("flash_bsl: BSL reports checksum incorrect\n");
printc_err("flash_bsl: BSL reports checksum "
"incorrect\n");
break;
case 0x53:
printc_err("flash_bsl: BSL got zero-size packet\n");
break;
case 0x54:
printc_err("flash_bsl: BSL receive buffer overflowed\n");
printc_err("flash_bsl: BSL receive buffer "
"overflowed\n");
break;
case 0x55:
printc_err("flash_bsl: (known-)unknown error\n");
@ -175,7 +177,7 @@ static int flash_bsl_recv(struct flash_bsl_device *dev,
uint16_t recv_len;
uint16_t crc_value;
if (read_all_with_timeout(dev->serial_fd, header, 3) < 0) {
if (sport_read_all(dev->serial_fd, header, 3) < 0) {
if (errno == ETIMEDOUT) {
printc_err("flash_bsl: response timed out\n");
return -1;
@ -204,13 +206,13 @@ static int flash_bsl_recv(struct flash_bsl_device *dev,
return -1;
}
if (read_all_with_timeout(dev->serial_fd, recv_buf, recv_len) < 0) {
if (sport_read_all(dev->serial_fd, recv_buf, recv_len) < 0) {
perror("receive message");
printc_err("flash_bsl: error receiving message\n");
return -1;
}
if (read_all_with_timeout(dev->serial_fd, crc_bytes, 2) < 0) {
if (sport_read_all(dev->serial_fd, crc_bytes, 2) < 0) {
perror("receive message CRC");
printc_err("flash_bsl: error receiving message CRC\n");
return -1;
@ -547,51 +549,40 @@ static void entry_delay(void)
usleep(1000);
}
static int set_serial_bits(int fd, int bits)
{
if (ioctl(fd, TIOCMSET, &bits) >= 0) {
return 0;
} else {
return -1;
}
}
static int enter_via_dtr_rts(struct flash_bsl_device *dev)
{
/*
* Implement the sequence shown on page 8 of TI document SLAU319A,
* via serial-port control lines.
*/
int fd = dev->serial_fd;
sport_t fd = dev->serial_fd;
/* drive RST# line low */
if (set_serial_bits(fd, TIOCM_RTS | TIOCM_DTR) != 0) {
if (sport_set_modem(fd, TIOCM_RTS | TIOCM_DTR) != 0) {
return -1;
}
entry_delay( );
/* drive TEST line high then low again */
if (set_serial_bits(fd, TIOCM_DTR) != 0) {
if (sport_set_modem(fd, TIOCM_DTR) != 0) {
return -1;
}
entry_delay( );
if (set_serial_bits(fd, TIOCM_RTS | TIOCM_DTR) != 0) {
if (sport_set_modem(fd, TIOCM_RTS | TIOCM_DTR) != 0) {
return -1;
}
entry_delay( );
/* drive TEST line high followed by RST# line */
if (set_serial_bits(fd, TIOCM_DTR) != 0) {
if (sport_set_modem(fd, TIOCM_DTR) != 0) {
return -1;
}
entry_delay( );
if (set_serial_bits(fd, 0) != 0) {
if (sport_set_modem(fd, 0) != 0) {
return -1;
}
entry_delay( );
if (set_serial_bits(fd, TIOCM_RTS) != 0) {
if (sport_set_modem(fd, TIOCM_RTS) != 0) {
return -1;
}
entry_delay( );
@ -603,16 +594,16 @@ static int enter_via_dtr_rts(struct flash_bsl_device *dev)
static void exit_via_dtr_rts(struct flash_bsl_device *dev)
{
int fd = dev->serial_fd;
sport_t fd = dev->serial_fd;
/* RST# and TEST LOW */
set_serial_bits(fd, TIOCM_RTS | TIOCM_DTR);
sport_set_modem(fd, TIOCM_RTS | TIOCM_DTR);
/* wait a brief period */
entry_delay( );
/* RST# HIGH */
set_serial_bits(fd, TIOCM_DTR);
sport_set_modem(fd, TIOCM_DTR);
}
static void flash_bsl_destroy(device_t dev_base)
@ -621,7 +612,7 @@ static void flash_bsl_destroy(device_t dev_base)
exit_via_dtr_rts(dev);
close(dev->serial_fd);
sport_close(dev->serial_fd);
free(dev);
}
@ -648,8 +639,8 @@ static device_t flash_bsl_open(const struct device_args *args)
memset(dev, 0, sizeof(*dev));
dev->base.type = &device_flash_bsl;
dev->serial_fd = open_serial_even_parity(args->path, B9600);
if (dev->serial_fd < 0) {
dev->serial_fd = sport_open(args->path, B9600, SPORT_EVEN_PARITY);
if (SPORT_ISERR(dev->serial_fd)) {
printc_err("flash_bsl: can't open %s: %s\n",
args->path, strerror(errno));
free(dev);
@ -678,8 +669,8 @@ static device_t flash_bsl_open(const struct device_args *args)
}
if (flash_bsl_recv(dev, tx_bsl_version_response,
sizeof(tx_bsl_version_response)) < sizeof(tx_bsl_version_response)) {
sizeof(tx_bsl_version_response)) <
sizeof(tx_bsl_version_response)) {
printc_err("flash_bsl: BSL responded with invalid version");
goto fail;
}
@ -690,7 +681,7 @@ static device_t flash_bsl_open(const struct device_args *args)
return (device_t)dev;
fail:
close(dev->serial_fd);
sport_close(dev->serial_fd);
free(dev);
return NULL;
}

3
gdbc.c
View File

@ -278,8 +278,7 @@ static int gdbc_ctl(device_t dev_base, device_ctl_t op)
case DEVICE_CTL_HALT:
if (dev->is_running) {
if (write_all(dev->gdb.sock,
(const uint8_t *)"\003", 1) < 0) {
if (send(dev->gdb.sock, "\003", 1, 0) < 1) {
pr_error("gdbc: write");
return -1;
}

125
sport.c Normal file
View File

@ -0,0 +1,125 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009, 2010 Daniel Beer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "sport.h"
sport_t sport_open(const char *device, int rate, int flags)
{
int fd = open(device, O_RDWR | O_NOCTTY);
struct termios attr;
if (fd < 0)
return -1;
tcgetattr(fd, &attr);
cfmakeraw(&attr);
cfsetispeed(&attr, rate);
cfsetospeed(&attr, rate);
if (flags & SPORT_EVEN_PARITY)
attr.c_cflag |= PARENB;
if (tcsetattr(fd, TCSAFLUSH, &attr) < 0) {
close(fd);
return -1;
}
return fd;
}
void sport_close(sport_t s)
{
close(s);
}
int sport_flush(sport_t s)
{
return tcflush(s, TCIFLUSH);
}
int sport_set_modem(sport_t s, int bits)
{
return ioctl(s, TIOCMSET, &bits);
}
int sport_read(sport_t s, uint8_t *data, int len)
{
int r;
do {
struct timeval tv = {
.tv_sec = 5,
.tv_usec = 0
};
fd_set set;
FD_ZERO(&set);
FD_SET(s, &set);
r = select(s + 1, &set, NULL, NULL, &tv);
if (r > 0)
r = read(s, data, len);
if (!r)
errno = ETIMEDOUT;
if (r <= 0 && errno != EINTR)
return -1;
} while (r <= 0);
return r;
}
int sport_write(sport_t s, const uint8_t *data, int len)
{
return write(s, data, len);
}
int sport_read_all(sport_t s, uint8_t *data, int len)
{
while (len) {
int r = sport_read(s, data, len);
if (r <= 0)
return -1;
data += r;
len -= r;
}
return 0;
}
int sport_write_all(sport_t s, const uint8_t *data, int len)
{
while (len) {
int r = sport_write(s, data, len);
if (r <= 0)
return -1;
data += r;
len -= r;
}
return 0;
}

58
sport.h Normal file
View File

@ -0,0 +1,58 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009, 2010 Daniel Beer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SPORT_H_
#define SPORT_H_
#include <stdint.h>
#include <termios.h>
#include <sys/ioctl.h>
#ifndef B460800
#define B460800 460800
#endif
#ifndef B500000
#define B500000 500000
#endif
typedef int sport_t;
#define SPORT_ISERR(x) ((x) < 0)
/* Various utility functions for IO */
#define SPORT_EVEN_PARITY 0x01
sport_t sport_open(const char *device, int rate, int flags);
void sport_close(sport_t s);
int sport_flush(sport_t s);
int sport_set_modem(sport_t s, int bits);
/* Read/write a serial port. These functions return the number of
* bytes transferred, or -1 on error.
*/
int sport_read(sport_t s, uint8_t *data, int len);
int sport_write(sport_t s, const uint8_t *data, int len);
/* Same as above, but requires that all data be transferred. */
int sport_read_all(sport_t s, uint8_t *data, int len);
int sport_write_all(sport_t s, const uint8_t *data, int len);
#endif

35
uif.c
View File

@ -23,30 +23,21 @@
#include <assert.h>
#include <stdint.h>
#include <unistd.h>
#include <termios.h>
#if defined(__linux__)
#include <linux/serial.h>
#endif
#include <sys/ioctl.h>
#include <fcntl.h>
#include "uif.h"
#include "util.h"
#include "output.h"
#include "sport.h"
#ifndef B460800
#define B460800 460800
#endif
#ifndef B500000
#define B500000 500000
#if defined(__linux__)
#include <linux/serial.h>
#include <fcntl.h>
#endif
struct uif_transport {
struct transport base;
int serial_fd;
sport_t serial_fd;
};
static int serial_send(transport_t tr_base, const uint8_t *data, int len)
@ -57,7 +48,7 @@ static int serial_send(transport_t tr_base, const uint8_t *data, int len)
debug_hexdump("Serial transfer out:", data, len);
#endif
if (write_all(tr->serial_fd, data, len) < 0) {
if (sport_write_all(tr->serial_fd, data, len) < 0) {
pr_error("uif: write error");
return -1;
}
@ -70,7 +61,7 @@ static int serial_recv(transport_t tr_base, uint8_t *data, int max_len)
struct uif_transport *tr = (struct uif_transport *)tr_base;
int r;
r = read_with_timeout(tr->serial_fd, data, max_len);
r = sport_read(tr->serial_fd, data, max_len);
if (r < 0) {
pr_error("uif: read error");
return -1;
@ -86,7 +77,7 @@ static void serial_destroy(transport_t tr_base)
{
struct uif_transport *tr = (struct uif_transport *)tr_base;
close(tr->serial_fd);
sport_close(tr->serial_fd);
free(tr);
}
@ -108,7 +99,8 @@ static int open_olimex_iso(const char *device)
serial_info.flags = ASYNC_SPD_CUST;
serial_info.custom_divisor = 120;
if (ioctl(fd, TIOCSSERIAL, &serial_info) < 0) {
printc_err("open_olimex_iso: can't do ioctl TIOCSSERIAL: %s\n",
printc_err("open_olimex_iso: can't do "
"ioctl TIOCSSERIAL: %s\n",
strerror(errno));
return -1;
}
@ -136,12 +128,12 @@ transport_t uif_open(const char *device, uif_type_t type)
switch (type) {
case UIF_TYPE_FET:
printc("Trying to open UIF on %s...\n", device);
tr->serial_fd = open_serial(device, B460800);
tr->serial_fd = sport_open(device, B460800, 0);
break;
case UIF_TYPE_OLIMEX:
printc("Trying to open Olimex on %s...\n", device);
tr->serial_fd = open_serial(device, B500000);
tr->serial_fd = sport_open(device, B500000, 0);
break;
case UIF_TYPE_OLIMEX_ISO:
@ -149,7 +141,8 @@ transport_t uif_open(const char *device, uif_type_t type)
printc("Trying to open Olimex (ISO) on %s...\n", device);
tr->serial_fd = open_olimex_iso(device);
#else
printc_err("uif_open: ioctl TIOCSSERIAL not supported on this platform\n");
printc_err("uif_open: ioctl TIOCSSERIAL not supported "
"on this platform\n");
#endif
break;
}

136
util.c
View File

@ -21,9 +21,6 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
@ -63,139 +60,6 @@ int ctrlc_check(void)
return ctrlc_flag;
}
int read_with_timeout(int fd, uint8_t *data, int max_len)
{
int r;
do {
struct timeval tv = {
.tv_sec = 5,
.tv_usec = 0
};
fd_set set;
FD_ZERO(&set);
FD_SET(fd, &set);
r = select(fd + 1, &set, NULL, NULL, &tv);
if (r > 0)
r = read(fd, data, max_len);
if (!r)
errno = ETIMEDOUT;
if (r <= 0 && errno != EINTR)
return -1;
} while (r <= 0);
return r;
}
/*
* read_all_with_timeout
* read all requested data, or die trying.
*
* Arguments:
* fd: file descriptor from which to read
* data: buffer where data will be put
* len: total size of data to read
*
* Return Value:
* Zero on success. -1 on failure.
*/
int read_all_with_timeout(int fd, uint8_t *data, int len)
{
int r, n_read;
/* loop until all required data has been read (or we time out) */
while (len > 0) {
struct timeval tv = {
.tv_sec = 5,
.tv_usec = 0
};
/* wait (with timeout) for data to become available */
fd_set set;
FD_ZERO(&set);
FD_SET(fd, &set);
r = select(fd + 1, &set, NULL, NULL, &tv);
if (r > 0) {
/* select( ) succeeded */
n_read = read(fd, data, len);
if (n_read <= 0) {
/* read failed */
return -1;
} else {
data += n_read;
len -= n_read;
}
} else if (!r) {
/* select( ) succeeded but timed out */
errno = ETIMEDOUT;
return -1;
} else if (errno != EINTR) {
/* select( ) failed */
return -1;
}
};
return 0;
}
int write_all(int fd, const uint8_t *data, int len)
{
while (len) {
int result = write(fd, data, len);
if (result < 0) {
if (errno == EINTR)
continue;
return -1;
}
data += result;
len -= result;
}
return 0;
}
static int open_serial_and_set_cflags(const char *device,
int rate, tcflag_t set)
{
int fd = open(device, O_RDWR | O_NOCTTY);
struct termios attr;
if (fd < 0)
return -1;
tcgetattr(fd, &attr);
cfmakeraw(&attr);
cfsetispeed(&attr, rate);
cfsetospeed(&attr, rate);
attr.c_cflag |= set;
if (tcsetattr(fd, TCSAFLUSH, &attr) < 0)
return -1;
return fd;
}
int open_serial(const char *device, int rate)
{
return open_serial_and_set_cflags(device, rate, 0);
}
int open_serial_even_parity(const char *device, int rate) {
return open_serial_and_set_cflags(device, rate, PARENB);
}
char *get_arg(char **text)
{
char *start;

7
util.h
View File

@ -31,13 +31,6 @@
/* This type fits an MSP430X register value */
typedef uint32_t address_t;
/* Various utility functions for IO */
int open_serial(const char *device, int rate);
int open_serial_even_parity(const char *device, int rate);
int read_with_timeout(int fd, uint8_t *data, int len);
int read_all_with_timeout(int fd, uint8_t *data, int len);
int write_all(int fd, const uint8_t *data, int len);
/* Check and catch ^C from the user */
void ctrlc_init(void);
void ctrlc_reset(void);