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