#include #include #include #include #include #include #include static void help() { const char *msg = "Usage: zup [options] command...\n" "Send commands to a computer running zbootloader. If no commands are\n" "provided jump into REPL instead.\n" "\n" "Options:\n" " -b, --baud=BAUD use BAUD as baud rate for serial port\n" " -v, --verbose \n" " -V, --version \n" " -H, --human-readable \n" " -r, --raw \n" " -R, --repl ignore commands and go into REPL instead\n" " -p, --port=FILE use FILE for serial comunication\n" " -h, --help display this text and exit\n" "\n" "Available commands:\n" " r:BANK:ADDR:LEN:FILE read LEN bytes from BANK and ADDR into FILE\n" " w:BANK:ADDR:FILE write FILE into BANK and ADDR\n" " b:ADDR exit zbootloader and boot from ADDR\n" "\n" "Report bugs to: thomas@thomaslabs.org\n" "Home page: "; puts(msg); exit(EXIT_SUCCESS); } static void version() { const char *fmt = "zup %s\n" "Copyright (C) 2023 Thomas Albers Raviola\n\n"; printf(fmt, VERSION); exit(EXIT_SUCCESS); } static speed_t parse_baud(const char *str) { struct baud_pair { const char *b; speed_t c; }; // Conversion table for baud rates const struct baud_pair baud_rates[] = { {"50", B50}, {"75", B75}, {"110", B110}, {"134", B134}, {"150", B150}, {"200", B200}, {"300", B300}, {"600", B600}, {"1200", B1200}, {"1800", B1800}, {"2400", B2400}, {"4800", B4800}, {"9600", B9600}, {"19200", B19200}, {"38400", B38400}, {"57600", B57600}, {"115200", B115200}, {"230400", B230400}, {"460800", B460800}, {"500000", B500000}, {"576000", B576000}, {"921600", B921600}, {"1000000", B1000000}, {"1152000", B1152000}, {"1500000", B1500000}, {"2000000", B2000000} }; for (int i = 0; i < LEN(baud_rates); i++) { if (!strcmp(baud_rates[i].b, str)) return baud_rates[i].c; } return 0; } static int parse_options(int argc, char *const argv[]) { const char *sopts = "b:p:hHVRrv"; const struct option lopts[] = { { "baud", required_argument, 0, 'b'}, { "verbose", no_argument, 0, 'v'}, { "version", no_argument, 0, 'V'}, { "raw", no_argument, 0, 'r'}, { "repl", no_argument, 0, 'R'}, { "port", required_argument, 0, 'p'}, { "human-readable", no_argument, 0, 'H'}, { "help", no_argument, 0, 'h'}, { 0, 0, 0, 0 } }; int c; int i = 0; while ((c = getopt_long(argc, argv, sopts, lopts, &i)) != -1) { switch (c) { case 'b': if (!(param.baud = parse_baud(optarg))) { fprintf(stderr, "Error: Invalid baud rate '%s'\n", optarg); exit(EXIT_FAILURE); } break; case 'v': param.verbose = 1; break; case 'p': strncpy(param.port, optarg, LEN(param.port)); break; case 'R': param.repl = 1; break; case 'H': param.human_readable = 1; break; case 'r': param.human_readable = 0; break; case 'V': version(); break; case 'h': case '?': help(); break; default: break; } } return optind; } void print_error(int error) { int i = -error - 1; const char *msgs[] = { "ERR_TIMEOUT", "ERR_READ", "ERR_WRITE", "ERR_NACK", "ERR_ARGS" }; if (0 <= i && i < LEN(msgs)) fprintf(stderr, "%s\n", msgs[i]); else fprintf(stderr, "Unknown error. Code %d\n", error); } void hexdump(size_t start_address, size_t len, const uint8_t *buf) { long offset = start_address - (start_address & ~0xF); printf(" "); for (int i = 0; i < 16; ++i) printf(" %01X%01X", i, i); puts("\n------------------------------------------------------" "|-----------------|"); for (long i = 0; i < (len + 15) / 16; ++i) { printf("%04X:", (start_address & ~0xF) + 16 * i); for (long j = 0; j < 16; ++j) { long k = 16 * i + j - offset; if (k < 0 || k >= len) printf(" "); else printf(" %02X", buf[k]); } printf(" | "); for (long j = 0; j < min(16, len - 16 * i); ++j) { long k = 16 * i + j - offset; if (k < 0 || k >= len) { putchar(' '); } else { int c = buf[16 * i + j - offset]; putchar(isprint(c) ? c : '.'); } } putchar('|'); putchar('\n'); } } struct param param = { .port = "/dev/ttyS1", .baud = B9600, .verbose = 0, .human_readable = 0, .repl = 0 }; // TODO: Support stdin/stdout int main(int argc, char *argv[]) { int suc = EXIT_SUCCESS; // Init defaults int ind = parse_options(argc, argv); int fd = open_tty(param.port, param.baud); if (ind == argc || param.repl) { repl(fd); } else { argc -= ind; argv = &argv[ind]; int err = 0; for (int i = 0; i < argc && !err; ++i) err = run_line(fd, argv[i], ":"); if (err) suc = EXIT_FAILURE; } close(fd); exit(EXIT_SUCCESS); }