197 lines
4.6 KiB
C
197 lines
4.6 KiB
C
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
static int fd = -1;
|
|
|
|
void int_handler(int dummy) {
|
|
write(STDERR_FILENO, "sigint\n", 7);
|
|
|
|
if (fd != -1)
|
|
close(fd);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
set_attrs(int fd)
|
|
{
|
|
struct termios t;
|
|
int attr = tcgetattr(fd, &t);
|
|
assert (attr != -1);
|
|
|
|
cfsetospeed(&t, B115200);
|
|
cfsetispeed(&t, B115200);
|
|
|
|
t.c_cflag = (t.c_cflag & ~CSIZE) | CS8; // 8-bit chars
|
|
t.c_lflag = 0; // no signaling chars, no echo, no canonical processing
|
|
t.c_oflag = 0; // no remapping, no delays
|
|
t.c_cc[VMIN] = 1; // read doesn't block
|
|
t.c_cc[VTIME] = 0; // no timeout
|
|
|
|
// convert break to null byte, no CR to NL translation,
|
|
// no NL to CR translation, don't mark parity errors or breaks
|
|
// no input parity check, don't strip high bit off,
|
|
// no XON/XOFF software flow control
|
|
t.c_iflag &= ~(IGNBRK | BRKINT | ICRNL |
|
|
INLCR | PARMRK | INPCK | ISTRIP | IXOFF | IXON | IXANY);
|
|
|
|
t.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, enable reading
|
|
t.c_cflag &= ~(PARENB | PARODD); // shut off parity
|
|
t.c_cflag &= ~CSTOPB; // one stop bit
|
|
t.c_cflag |= CRTSCTS; // enable CTS/RTS
|
|
|
|
int ret = tcsetattr(fd, TCSANOW, &t);
|
|
assert (ret != -1);
|
|
}
|
|
|
|
ssize_t
|
|
write_block(int fd, char * buf, size_t len)
|
|
{
|
|
ssize_t wret, rret;
|
|
|
|
size_t out_len = 0;
|
|
|
|
char in_buf[len];
|
|
memset(in_buf, 0xea, len);
|
|
|
|
#define BLOCK_SIZE 8
|
|
|
|
for (unsigned int i = 0; i < (len / BLOCK_SIZE); i++) {
|
|
wret = write(fd, &buf[BLOCK_SIZE * i], BLOCK_SIZE);
|
|
assert (wret == BLOCK_SIZE);
|
|
int tret = tcdrain(fd);
|
|
assert (tret != -1);
|
|
|
|
//printf("%x\n", out_buf[BLOCK_SIZE * i] & 0xff, rret);
|
|
|
|
size_t block = 0;
|
|
while (block != BLOCK_SIZE) {
|
|
rret = read(fd, &in_buf[(BLOCK_SIZE * i) + block], BLOCK_SIZE - block);
|
|
assert (rret != -1);
|
|
block += rret;
|
|
}
|
|
//printf("%x %x %ld\n", out_buf[BLOCK_SIZE * i] & 0xff, in_buf[BLOCK_SIZE * i] & 0xff, rret);
|
|
assert (block == BLOCK_SIZE);
|
|
|
|
out_len += block;
|
|
|
|
write(STDERR_FILENO, ".", 1);
|
|
fsync(STDERR_FILENO);
|
|
}
|
|
|
|
size_t rem = len % BLOCK_SIZE;
|
|
if (rem) {
|
|
wret = write(fd, &buf[len - rem], rem);
|
|
assert (wret != -1);
|
|
assert ((size_t)wret == rem);
|
|
int tret = tcdrain(fd);
|
|
assert (tret != -1);
|
|
|
|
size_t block = 0;
|
|
while (block != rem) {
|
|
rret = read(fd, &in_buf[len - rem + block], rem - block);
|
|
assert (rret != -1);
|
|
block += rret;
|
|
}
|
|
//printf("%x %x %ld\n", buf[BLOCK_SIZE * i] & 0xff, in_buf[BLOCK_SIZE * i] & 0xff, rret);
|
|
assert (block == rem);
|
|
|
|
out_len += block;
|
|
|
|
write(STDERR_FILENO, ".", 1);
|
|
fsync(STDERR_FILENO);
|
|
}
|
|
|
|
write(STDERR_FILENO, "\n", 1);
|
|
|
|
//int cmp = memcmp(buf, in_buf, len);
|
|
for (unsigned int bx = 0; bx < len; bx++) {
|
|
if (buf[bx] != in_buf[bx]) {
|
|
fprintf(stderr, "buf[%d] != in_buf[%d]\n", bx, bx);
|
|
fprintf(stderr, "%02x != %02x\n", buf[bx], in_buf[bx]);
|
|
}
|
|
}
|
|
|
|
return out_len;
|
|
}
|
|
|
|
|
|
void
|
|
write_header(int fd, size_t len, size_t addr)
|
|
{
|
|
assert (addr <= 0xffff);
|
|
assert (len <= 255);
|
|
|
|
fprintf(stderr, "len %ld addr %lx\n", len, addr & 0xffff);
|
|
|
|
char out_buf[3] = {
|
|
len & 0xff,
|
|
(addr >> 0) & 0xff,
|
|
(addr >> 8) & 0xff,
|
|
};
|
|
ssize_t wret = write(fd, out_buf, 3);
|
|
assert (wret != -1);
|
|
|
|
size_t hdr_len = len == 0 ? 2 : 3;
|
|
char in_buf[3];
|
|
size_t offset = 0;
|
|
ssize_t rret;
|
|
while (offset != hdr_len) {
|
|
rret = read(fd, &in_buf[offset], hdr_len - offset);
|
|
assert (rret != -1);
|
|
offset += rret;
|
|
}
|
|
|
|
assert (offset == hdr_len);
|
|
int cmp = memcmp(in_buf, "LDR", hdr_len);
|
|
assert (cmp == 0);
|
|
}
|
|
|
|
static char read_buf[0x8000];
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
signal(SIGINT, int_handler);
|
|
|
|
int tfd = open("/dev/ttyUSB0", O_RDWR | O_SYNC | O_NOCTTY);
|
|
assert (tfd != -1);
|
|
|
|
set_attrs(tfd);
|
|
|
|
int tret = tcflush(tfd, TCIOFLUSH);
|
|
assert (tret != -1);
|
|
|
|
assert (argc > 1);
|
|
fprintf(stderr, "%s\n", argv[1]);
|
|
|
|
int ffd = open(argv[1], O_RDONLY);
|
|
ssize_t rret = read(ffd, read_buf, 0x8000);
|
|
assert (rret != -1 && rret > 0 && rret <= 0x8000);
|
|
|
|
size_t offset = 0;
|
|
size_t base_address = 0x200;
|
|
|
|
while (rret - offset > 0) {
|
|
size_t block_len = rret - offset >= 255 ? 255 : rret - offset;
|
|
write_header(tfd, block_len, base_address + offset);
|
|
ssize_t block_ret = write_block(tfd, &read_buf[offset], block_len);
|
|
assert (block_ret != -1);
|
|
assert ((size_t)block_ret == block_len);
|
|
offset += block_ret;
|
|
}
|
|
|
|
fprintf(stderr, "jump %lx\n", base_address & 0xffff);
|
|
write_header(tfd, 0, base_address);
|
|
|
|
close(fd);
|
|
}
|
|
|
|
// stty -F /dev/ttyUSB0 115200 -icrnl -imaxbel -opost -onlcr -isig -echo -icanon -ixon
|