initial version of flash_bsl driver

This driver allows mspdebug to talk to the bootloader on a flash MSP430
via a serial port. DTR and RTS lines are used to control the TEST and
RST# pins on the MSP430, respectively. Currently, read and program are
supported. However, read is fairly useless because the driver currently
does not support any password other than the default. Thus it must
mass-erase the chip to gain access.

Read that again. USING THIS DRIVER WILL MASS ERASE YOUR CHIP IMMEDIATELY,
WITHOUT YOU ASKING FOR IT.
This commit is contained in:
Andrew Armenia 2010-09-17 10:04:33 -04:00 committed by Daniel Beer
parent ecccfb5a64
commit 89520c052e
6 changed files with 806 additions and 2 deletions

View File

@ -1,5 +1,6 @@
# MSPDebug - debugging tool for the eZ430
# Copyright (C) 2009, 2010 Daniel Beer
# Copyright (C) 2010 Andrew Armenia
#
# 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
@ -58,7 +59,7 @@ mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \
util.o bsl.o sim.o symmap.o gdb.o btree.o rtools.o sym.o devcmd.o \
reader.o vector.o output_util.o expr.o fet_error.o binfile.o \
fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.o \
cmddb.o stdcmd.o prog.o
cmddb.o stdcmd.o prog.o flash_bsl.o
$(CC) $(LDFLAGS) $(MACPORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
.c.o:

683
flash_bsl.c Normal file
View File

@ -0,0 +1,683 @@
/* MSPDebug - debugging tool for the eZ430
* Copyright (C) 2009, 2010 Daniel Beer
* Copyright (C) 2010 Andrew Armenia
*
* 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 <stdio.h>
#include <stdlib.h>
#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"
struct flash_bsl_device {
struct device base;
int 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) {
uint16_t crc = CRC_INIT;
uint16_t temp;
int i;
for (i = 0; i < len; ++i) {
temp = ((crc >> 8) ^ data[i]) & 0xff;
temp ^= (temp >> 4);
crc = (crc << 8) ^ (temp << 12) ^ (temp << 5) ^ temp;
}
return crc;
}
static void crc_selftest(void) {
/* These test vectors are from page 30 of TI doc SLAU319A */
uint16_t crc_expected = 0x5590, crc_actual = crc_ccitt("\x52\x02", 2);
if (crc_expected != crc_actual) {
printc_err("flash_bsl: CRC malfunction (expected 0x%04x got 0x%04x)\n",
crc_expected, crc_actual);
}
crc_expected = 0x121d;
crc_actual = crc_ccitt("\x3a\x04\x01", 3);
if (crc_expected != crc_actual) {
printc_err("flash_bsl: CRC malfunction (expected 0x%04x got 0x%04x)\n",
crc_expected, crc_actual);
}
crc_expected = 0x528b;
crc_actual = crc_ccitt("\x1a", 1);
if (crc_expected != crc_actual) {
printc_err("flash_bsl: CRC malfunction (expected 0x%04x got 0x%04x)\n",
crc_expected, crc_actual);
}
}
#define RX_DATA_BLOCK 0x10
#define RX_DATA_BLOCK_FAST 0x1b
#define RX_PASSWORD 0x11
#define ERASE_SEGMENT 0x12
#define UNLOCK_LOCK_INFO 0x13
#define MASS_ERASE 0x15
#define CRC_CHECK 0x16
#define LOAD_PC 0x17
#define TX_DATA_BLOCK 0x18
#define TX_BSL_VERSION 0x19
#define TX_BUFFER_SIZE 0x1a
static int flash_bsl_send(struct flash_bsl_device *dev, const uint8_t *data, int len)
{
uint16_t crc;
uint8_t cmd_buf[MAX_PACKET + 5];
uint8_t response;
debug_hexdump("flash_bsl: sending", data, len);
crc = crc_ccitt(data, len);
if (len > MAX_PACKET) {
printc_err("flash_bsl: attempted to transmit long packet (len=%d)\n", len);
return -1;
}
cmd_buf[0] = 0x80;
cmd_buf[1] = (len & 0xff);
cmd_buf[2] = (len >> 8) & 0xff;
memcpy(cmd_buf + 3, data, len);
cmd_buf[len + 3] = (crc & 0xff);
cmd_buf[len + 4] = (crc >> 8) & 0xff;
if (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 (errno == ETIMEDOUT) {
printc_err("flash_bsl: serial read timed out\n");
} else {
printc_err("flash_bsl: serial read failed\n");
}
return -1;
}
if (response != 0) {
switch (response) {
case 0x51:
printc_err("flash_bsl: BSL reports incorrect packet header\n");
break;
case 0x52:
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");
break;
case 0x55:
printc_err("flash_bsl: (known-)unknown error\n");
break;
case 0x56:
printc_err("flash_bsl: unknown baud rate\n");
break;
default:
printc_err("flash_bsl: unknown unknown error\n");
break;
}
return -1;
}
return 0;
}
static int flash_bsl_recv(struct flash_bsl_device *dev,
uint8_t *recv_buf, int buf_len)
{
uint8_t header[3];
uint8_t crc_bytes[2];
uint16_t recv_len;
uint16_t crc_value;
if (read_all_with_timeout(dev->serial_fd, header, 3) < 0) {
if (errno == ETIMEDOUT) {
printc_err("flash_bsl: response timed out\n");
return -1;
} else {
perror("read response header");
printc_err("flash_bsl: read response failed\n");
return -1;
}
}
if (header[0] != 0x80) {
printc_err("flash_bsl: incorrect response header received\n");
return -1;
}
recv_len = header[2];
recv_len <<= 8;
recv_len |= header[1];
printc_err("flash_bsl: incoming message length %d\n", recv_len);
if (recv_len > buf_len) {
printc_err("flash_bsl: insufficient buffer to receive data\n");
return -1;
}
if (read_all_with_timeout(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) {
perror("receive message CRC");
printc_err("flash_bsl: error receiving message CRC\n");
return -1;
}
crc_value = crc_bytes[1];
crc_value <<= 8;
crc_value |= crc_bytes[0];
if (crc_ccitt(recv_buf, recv_len) != crc_value) {
printc_err("flash_bsl: received message with bad CRC\n");
return -1;
}
debug_hexdump("received message", recv_buf, recv_len);
usleep(10000);
return recv_len;
}
static void flash_bsl_perror(uint8_t code) {
switch (code) {
case 0x00:
printc_err("flash_bsl: success\n");
break;
case 0x01:
printc_err("flash_bsl: FLASH verify failed\n");
break;
case 0x02:
printc_err("flash_bsl: FLASH operation failed\n");
break;
case 0x03:
printc_err("flash_bsl: voltage not constant during program\n");
break;
case 0x04:
printc_err("flash_bsl: BSL is locked\n");
break;
case 0x05:
printc_err("flash_bsl: incorrect password\n");
break;
case 0x06:
printc_err("flash_bsl: attempted byte write to FLASH\n");
break;
case 0x07:
printc_err("flash_bsl: unrecognized command\n");
break;
case 0x08:
printc_err("flash_bsl: command was too long\n");
break;
default:
printc_err("flash_bsl: unknown status message\n");
break;
}
}
#define MAX_BLOCK 256
static int flash_bsl_readmem(device_t dev_base,
address_t addr, uint8_t *mem, address_t len)
{
struct flash_bsl_device *dev = (struct flash_bsl_device *)dev_base;
uint8_t recv_buf[MAX_BLOCK*2];
uint8_t send_buf[64];
uint16_t read_size;
int ret;
if (addr > 0xfffff || addr + len > 0xfffff) {
printc_err("flash_bsl: read exceeds possible range\n");
return -1;
}
while (len > 0) {
if (len > MAX_BLOCK) {
read_size = MAX_BLOCK;
} else {
read_size = len;
}
/* build command */
send_buf[0] = TX_DATA_BLOCK; /* command: transmit data block */
send_buf[1] = addr & 0xff;
send_buf[2] = (addr >> 8) & 0xff;
send_buf[3] = (addr >> 16) & 0xff;
send_buf[4] = read_size & 0xff;
send_buf[5] = (read_size >> 8) & 0xff;
if (flash_bsl_send(dev, send_buf, 6) < 0) {
printc_err("flash_bsl readmem: send failed\n");
return -1;
}
ret = flash_bsl_recv(dev, recv_buf, read_size + 1);
if (ret < 0) {
printc_err("flash_bsl readmem: receive failed\n");
return -1;
} else if (ret < read_size) {
printc_err("flash_bsl readmem: warning: not all requested data received\n");
}
if (recv_buf[0] == 0x3a) {
memcpy(mem, recv_buf + 1, ret - 1);
len -= ret - 1;
mem += ret - 1;
} else if (recv_buf[0] == 0x3b) {
flash_bsl_perror(recv_buf[1]);
} else {
printc_err("flash_bsl readmem: invalid response\n");
return -1;
}
}
return 0;
}
static int flash_bsl_erase(struct flash_bsl_device *dev)
{
const uint8_t mass_erase_cmd[] = { MASS_ERASE };
uint8_t response_buffer[16];
int ret;
if (flash_bsl_send(dev, mass_erase_cmd, sizeof(mass_erase_cmd)) < 0) {
printc_err("flash_bsl_erase: failed to send erase command\n");
return -1;
}
ret = flash_bsl_recv(dev, response_buffer, sizeof(response_buffer));
if (ret < 2) {
printc_err("flash_bsl_erase: no response\n");
return -1;
}
if (response_buffer[0] != 0x3b) {
printc_err("flash_bsl_erase: incorrect response\n");
return -1;
}
if (response_buffer[1] != 0) {
flash_bsl_perror(response_buffer[1]);
printc_err("flash_bsl_erase: erase failed\n");
return -1;
} else {
printc_err("flash_bsl_erase: success\n");
}
return 0;
}
static int flash_bsl_unlock(struct flash_bsl_device *dev)
{
/*
* after erase, the password will be 0xff * (16 or 32)
* (an empty interrupt vector table)
*/
uint8_t rx_password_cmd[33] = "\x11"
"\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff";
uint8_t response_buffer[16];
int ret;
/* mass erase (this might wipe Information Memory on some devices */
if (flash_bsl_erase(dev) < 0) {
printc_err("flash_bsl_unlock: warning: erase failed\n");
}
/* send password (which is now erased FLASH) */
if (dev->long_password) {
printc_err("flash_bsl_unlock: using long password?\n");
}
if (flash_bsl_send(dev, rx_password_cmd, dev->long_password ? 33 : 17) < 0) {
printc_err("flash_bsl_unlock: send password failed\n");
return -1;
}
ret = flash_bsl_recv(dev, response_buffer, sizeof(response_buffer));
if (ret < 2) {
printc_err("flash_bsl_unlock: error receiving password response\n");
return -1;
}
if (response_buffer[0] != 0x3b) {
printc_err("flash_bsl_unlock: received invalid password response\n");
return -1;
}
if (response_buffer[1] != 0x00) {
flash_bsl_perror(response_buffer[1]);
printc_err("flash_bsl_unlock: password error\n");
return -1;
}
return 0;
}
static int flash_bsl_ctl(device_t dev_base, device_ctl_t type)
{
struct flash_bsl_device *dev = (struct flash_bsl_device *)dev_base;
switch (type) {
case DEVICE_CTL_ERASE:
return flash_bsl_erase(dev);
case DEVICE_CTL_HALT:
/* Ignore halt requests */
return 0;
case DEVICE_CTL_RESET:
/* Ignore reset requests */
return 0;
default:
printc_err("bsl: CPU control is not possible\n");
}
return -1;
}
static device_status_t flash_bsl_poll(device_t dev_base)
{
return DEVICE_STATUS_HALTED;
}
static int flash_bsl_getregs(device_t dev_base, address_t *regs)
{
printc_err("flash_bsl: register fetch is not implemented\n");
return -1;
}
static int flash_bsl_setregs(device_t dev_base, const address_t *regs)
{
printc_err("flash_bsl: register store is not implemented\n");
return -1;
}
static int flash_bsl_writemem(device_t dev_base,
address_t addr, const uint8_t *mem, address_t len)
{
struct flash_bsl_device *dev = (struct flash_bsl_device *)dev_base;
uint8_t send_buf[2*MAX_BLOCK];
uint8_t recv_buf[16];
uint16_t write_size;
int n_recv;
if (addr > 0xfffff || addr + len > 0xfffff) {
printc_err("flash_bsl: write exceeds possible range\n");
return -1;
}
while (len > 0) {
/* compute size of this write operation */
if (len > MAX_BLOCK) {
write_size = MAX_BLOCK;
} else {
write_size = len;
}
/* build write command */
/* command */
send_buf[0] = RX_DATA_BLOCK;
/* address */
send_buf[1] = addr & 0xff;
send_buf[2] = (addr >> 8) & 0xff;
send_buf[3] = (addr >> 16) & 0xff;
/* data */
memcpy(&send_buf[4], mem, write_size);
mem += write_size;
len -= write_size;
/* send command */
if (flash_bsl_send(dev, send_buf, write_size + 4) < 0) {
printc_err("flash_bsl: send failed\n");
return -1;
}
/* receive and check response */
n_recv = flash_bsl_recv(dev, recv_buf, sizeof(recv_buf));
if (n_recv < 0) {
printc_err("flash_bsl write: error occurred receiving response\n");
return -1;
} else if (n_recv < 2) {
printc_err("flash_bsl write: response too short\n");
return -1;
} else if (recv_buf[0] != 0x3b) {
printc_err("flash_bsl write: invalid response received\n");
return -1;
} else if (recv_buf[1] != 0x00) {
printc_err("flash_bsl write: BSL reported write error: ");
flash_bsl_perror(recv_buf[1]);
return -1;
}
/* else success! */
}
return 0;
}
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;
/* drive RST# line low */
if (set_serial_bits(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) {
return -1;
}
entry_delay( );
if (set_serial_bits(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) {
return -1;
}
entry_delay( );
if (set_serial_bits(fd, 0) != 0) {
return -1;
}
entry_delay( );
if (set_serial_bits(fd, TIOCM_RTS) != 0) {
return -1;
}
entry_delay( );
/* BSL should now be running! */
return 0;
}
static void exit_via_dtr_rts(struct flash_bsl_device *dev)
{
int fd = dev->serial_fd;
/* RST# and TEST LOW */
set_serial_bits(fd, TIOCM_RTS | TIOCM_DTR);
/* wait a brief period */
entry_delay( );
/* RST# HIGH */
set_serial_bits(fd, TIOCM_DTR);
}
static void flash_bsl_destroy(device_t dev_base)
{
struct flash_bsl_device *dev = (struct flash_bsl_device *)dev_base;
exit_via_dtr_rts(dev);
close(dev->serial_fd);
free(dev);
}
device_t flash_bsl_open(const char *device, int long_password)
{
struct flash_bsl_device *dev = malloc(sizeof(*dev));
uint8_t tx_bsl_version_command[] = { TX_BSL_VERSION };
uint8_t tx_bsl_version_response[5];
if (!dev) {
pr_error("flash_bsl: can't allocate memory");
return NULL;
}
crc_selftest( );
memset(dev, 0, sizeof(*dev));
dev->base.destroy = flash_bsl_destroy;
dev->base.readmem = flash_bsl_readmem;
dev->base.writemem = flash_bsl_writemem;
dev->base.getregs = flash_bsl_getregs;
dev->base.setregs = flash_bsl_setregs;
dev->base.ctl = flash_bsl_ctl;
dev->base.poll = flash_bsl_poll;
dev->serial_fd = open_serial_even_parity(device, B9600);
if (dev->serial_fd < 0) {
printc_err("flash_bsl: can't open %s: %s\n",
device, strerror(errno));
free(dev);
return NULL;
}
dev->long_password = long_password;
/* enter bootloader */
if (enter_via_dtr_rts(dev) < 0) {
goto fail;
}
usleep(500000);
/* unlock device (erase then send password) */
if (flash_bsl_unlock(dev) < 0) {
goto fail;
}
if (flash_bsl_send(dev, tx_bsl_version_command, sizeof(tx_bsl_version_command)) < 0) {
printc_err("flash_bsl: failed to read BSL version");
goto fail;
}
if (flash_bsl_recv(dev, 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;
}
debug_hexdump("BSL version", tx_bsl_version_response,
sizeof(tx_bsl_version_response));
#if 0
/* Show chip info */
if (bsl_xfer(dev, CMD_TX_DATA, 0xff0, NULL, 0x10) < 0) {
printc_err("bsl: failed to read chip info\n");
goto fail;
}
if (dev->reply_len < 0x16) {
printc_err("bsl: missing chip info\n");
goto fail;
}
printc_dbg("Device ID: 0x%02x%02x\n",
dev->reply_buf[4], dev->reply_buf[5]);
printc_dbg("BSL version is %x.%02x\n", dev->reply_buf[14],
dev->reply_buf[15]);
#endif
return (device_t)dev;
fail:
close(dev->serial_fd);
free(dev);
return NULL;
}

28
flash_bsl.h Normal file
View File

@ -0,0 +1,28 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009, 2010 Daniel Beer
* Copyright (C) 2010 Andrew Armenia
*
* 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 FLASH_BSL_H_
#define FLASH_BSL_H_
#include "device.h"
/* MSP430 Flash bootloader implementation. */
device_t flash_bsl_open(const char *devpath, int long_password);
#endif

23
main.c
View File

@ -44,6 +44,7 @@
#include "fet.h"
#include "vector.h"
#include "fet_db.h"
#include "flash_bsl.h"
#include "uif.h"
#include "olimex.h"
@ -127,6 +128,7 @@ struct cmdline_args {
int no_reset;
int no_rc;
int vcc_mv;
int long_password;
};
struct driver {
@ -218,6 +220,17 @@ static device_t driver_open_uif_bsl(const struct cmdline_args *args)
return bsl_open(args->serial_device);
}
static device_t driver_open_flash_bsl(const struct cmdline_args *args)
{
if (!args->serial_device) {
printc_err("This driver does not support USB access. "
"Specify a tty device using -d.\n");
return NULL;
}
return flash_bsl_open(args->serial_device, args->long_password);
}
static const struct driver driver_table[] = {
{
.name = "rf2500",
@ -243,6 +256,11 @@ static const struct driver driver_table[] = {
.name = "uif-bsl",
.help = "TI FET430UIF bootloader.",
.func = driver_open_uif_bsl
},
{
.name = "flash-bsl",
.help = "TI generic FLASH bootloader via RS-232",
.func = driver_open_flash_bsl
}
};
@ -360,6 +378,7 @@ static int parse_cmdline_args(int argc, char **argv,
{"usb-list", 0, 0, 'I'},
{"version", 0, 0, 'V'},
{"no-reset", 0, 0, 'R'},
{"long-password", 0, 0, 'P'},
{NULL, 0, 0, 0}
};
@ -422,6 +441,10 @@ static int parse_cmdline_args(int argc, char **argv,
args->no_reset = 1;
break;
case 'P':
args->long_password = 1;
break;
case '?':
printc_err("Try --help for usage information.\n");
return -1;

69
util.c
View File

@ -91,6 +91,61 @@ int read_with_timeout(int fd, uint8_t *data, int max_len)
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) {
@ -109,7 +164,7 @@ int write_all(int fd, const uint8_t *data, int len)
return 0;
}
int open_serial(const char *device, int rate)
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;
@ -121,13 +176,25 @@ int open_serial(const char *device, int rate)
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;

2
util.h
View File

@ -33,7 +33,9 @@ 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 */