mega-usb: allow sending any commands
authornotaz <notasas@gmail.com>
Fri, 19 Sep 2014 00:51:15 +0000 (03:51 +0300)
committernotaz <notasas@gmail.com>
Fri, 19 Sep 2014 21:40:16 +0000 (00:40 +0300)
mega-usb/Makefile
mega-usb/mega-usb.c

index 5c7aec3..8d5879e 100644 (file)
@@ -1,4 +1,7 @@
-CFLAGS += -Wall -ggdb -O2
+CFLAGS += -Wall -ggdb
+ifndef DEBUG
+CFLAGS += -O2
+endif
 
 all: mega-usb
 
index 7217080..affa5c2 100644 (file)
@@ -1,3 +1,28 @@
+/*
+ * 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>
@@ -11,7 +36,6 @@
 
 static int setup(int fd)
 {
-       speed_t ispeed, ospeed;
        struct termios tty;
        int ret;
 
@@ -72,7 +96,7 @@ static int read_from_cart(int fd, void *data, size_t size)
 }
 
 #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)
 {
@@ -115,72 +139,156 @@ static int write_with_check(int fd, const void *data, size_t size, char chk)
 }
 
 #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;
 }