+/*
+ * Tool for USB communication with Mega Everdrive
+ * Copyright (c) 2013,2014 notaz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
#define _BSD_SOURCE
#include <stdio.h>
#include <string.h>
static int setup(int fd)
{
- speed_t ispeed, ospeed;
struct termios tty;
int ret;
}
#define send_cmd(fd, cmd) \
- write_to_cart(fd, cmd, sizeof(cmd) - 1)
+ write_to_cart(fd, cmd, strlen(cmd))
static int read_check_byte(int fd, char expect)
{
}
#define send_cmd_check_k(fd, cmd) \
- write_with_check(fd, cmd, sizeof(cmd) - 1, 'k')
+ write_with_check(fd, cmd, strlen(cmd), 'k')
-int main(int argc, char *argv[])
+static int send_file(int fd, const char *fname, const char *cmd)
{
- const char *portname = "/dev/ttyUSB0";
char buf[0x10000];
+ int retval = -1;
+ FILE *f = NULL;
+ size_t blocksz;
size_t size;
int blocks;
- FILE *f;
int ret;
- int fd;
int i;
- fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
- if (fd < 0) {
- perror("open");
- return 1;
+ f = fopen(fname, "rb");
+ if (f == NULL)
+ {
+ fprintf(stderr, "fopen %s: ", fname);
+ return -1;
}
- setup(fd);
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ if (size > 0xf00000) {
+ fprintf(stderr, "size too large: %zd\n", size);
+ goto out;
+ }
- send_cmd_check_k(fd, " *T");
+ if (cmd[1] == 'f')
+ blocksz = 1024;
+ else
+ blocksz = sizeof(buf);
- if (argv[1] != NULL)
- {
- f = fopen(argv[1], "rb");
- if (f == NULL)
- {
- perror("fopen");
- return 1;
- }
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- fseek(f, 0, SEEK_SET);
- if (size > 0xf00000) {
- fprintf(stderr, "size too large: %zd\n", size);
- return 1;
+ blocks = (size + blocksz - 1) / blocksz;
+
+ send_cmd(fd, cmd);
+ ret = write_with_check(fd, &blocks, 1, 'k');
+ if (ret)
+ return ret;
+
+ // at this point, 'd' will arrive even if we don't
+ // write any more data, what's the point of that?
+ // probably a timeout?
+
+ for (i = 0; i < blocks; i++) {
+ ret = fread(buf, 1, blocksz, f);
+ if (i != blocks - 1 && ret != blocksz) {
+ fprintf(stderr, "failed to read block %d/%d\n",
+ i, blocks);
}
+ if (ret < blocksz)
+ memset(buf + ret, 0, blocksz - ret);
+
+ write_to_cart(fd, buf, blocksz);
+ }
- blocks = (size + 0xffff) >> 16;
- send_cmd(fd, "*g");
- write_with_check(fd, &blocks, 1, 'k');
+ ret = read_check_byte(fd, 'd');
+ if (ret)
+ goto out;
- // at this point, 'd' will arrive even if we don't
- // write any more data, what's the point of that?
+ retval = 0;
+out:
+ if (f != NULL)
+ fclose(f);
- for (i = 0; i < blocks; i++) {
- ret = fread(buf, 1, sizeof(buf), f);
- if (i != blocks - 1 && ret != sizeof(buf)) {
- fprintf(stderr, "failed to read block %d/%d\n",
- i, blocks);
- }
- if (ret < sizeof(buf))
- memset(buf + ret, 0, sizeof(buf) - ret);
+ return retval;
+}
- write_to_cart(fd, buf, sizeof(buf));
- }
+static void usage(const char *argv0)
+{
+ printf("usage:\n"
+ "%s [-d <ttydevice>] [-f <file>] command(s)\n"
+ "known commands for ED OS:\n"
+ " *g - upload game\n"
+ " *w - upload and start OS\n"
+ " *o - upload and start OS\n"
+ " *f - upload (and start?) FPGA firmware\n"
+ " *s - start last ROM (same as pressing start in menu)\n"
+ " *r<x> - run SDRAM contents as mapper x:\n"
+ " s - sms, m - md, o - OS app, c - cd BIOS, M - md10m\n"
+ "upload commands must be followed by -f <file>\n"
+ , argv0);
+ exit(1);
+}
+
+static void invarg(int argc, char *argv[], int arg)
+{
+ if (arg < argc)
+ fprintf(stderr, "invalid arg %d: \"%s\"\n", arg, argv[arg]);
+ else
+ fprintf(stderr, "missing required argument %d\n", arg);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *portname = "/dev/ttyUSB0";
+ const char *pending_cmd = NULL;
+ int ret = -1;
+ int arg = 1;
+ int fd;
+
+ if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+ usage(argv[0]);
- ret = read_check_byte(fd, 'd');
- if (ret)
- return 1;
+ if (!strcmp(argv[arg], "-d")) {
+ arg++;
+ if (argv[arg] != NULL)
+ portname = argv[arg];
+ else
+ invarg(argc, argv, arg);
+ arg++;
+ }
- send_cmd_check_k(fd, "*rm");
+ fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
+ if (fd < 0) {
+ fprintf(stderr, "open %s: ", portname);
+ perror("");
+ return 1;
}
- printf("all ok\n");
+ setup(fd);
- return 0;
+ send_cmd_check_k(fd, " *T");
+
+ for (; arg < argc; arg++) {
+ if (!strcmp(argv[arg], "-f")) {
+ arg++;
+ if (argv[arg] == NULL)
+ invarg(argc, argv, argc);
+ if (pending_cmd == NULL)
+ // assume game upload
+ pending_cmd = "*g";
+
+ ret = send_file(fd, argv[arg], pending_cmd);
+ if (ret)
+ return ret;
+
+ pending_cmd = NULL;
+ continue;
+ }
+ if (argv[arg + 1] && !strcmp(argv[arg + 1], "-f")) {
+ /* we'll avoid sending command if there are
+ * problems with specified file */
+ pending_cmd = argv[arg];
+ continue;
+ }
+
+ ret = send_cmd_check_k(fd, argv[arg]);
+ }
+
+ return ret;
}