initial support for 2 players
[teensytas.git] / host / main.c
index 9cc492c..b5a65b1 100644 (file)
@@ -455,33 +455,33 @@ struct gmv_tas {
   uint8_t data[0][3];
 };
 
-static uint8_t *import_gmv(FILE *f, long size, int *byte_count, FILE *logf)
+static int import_gmv(FILE *f, long size,
+  uint8_t *out[2], int out_byte_count[2], FILE *logf)
 {
   struct gmv_tas *gmv;
   int frame_count;
   int count = 0;
   uint16_t val;
-  uint8_t *out;
   int ret;
   int i;
 
-  *byte_count = 0;
+  out_byte_count[0] = out_byte_count[1] = 0;
 
   if (size < (long)sizeof(*gmv)) {
     fprintf(stderr, "bad gmv size: %ld\n", size);
-    return NULL;
+    return -1;
   }
 
   gmv = malloc(size);
   if (gmv == NULL) {
     fprintf(stderr, "OOM?\n");
-    return NULL;
+    return -1;
   }
   ret = fread(gmv, 1, size, f);
   if (ret != size) {
     fprintf(stderr, "fread %d/%ld: ", ret, size);
     perror("");
-    return NULL;
+    return -1;
   }
 
   frame_count = (size - sizeof(*gmv)) / sizeof(gmv->data[0]);
@@ -489,25 +489,25 @@ static uint8_t *import_gmv(FILE *f, long size, int *byte_count, FILE *logf)
   /* check the GMV.. */
   if (frame_count <= 0 || size != sizeof(*gmv) + frame_count * 3) {
     fprintf(stderr, "broken gmv? frames=%d\n", frame_count);
-    return NULL;
+    return -1;
   }
 
   if (strncmp(gmv->sig, "Gens Movie TEST", 15) != 0) {
     fprintf(stderr, "bad GMV sig\n");
-    return NULL;
+    return -1;
   }
   if (gmv->ctrl1 != '3') {
     fprintf(stderr, "unhandled controlled config: '%c'\n", gmv->ctrl1);
-    //return NULL;
+    //return -1;
   }
   if (gmv->ver >= 'A') {
     if (gmv->flags & 0x40) {
       fprintf(stderr, "unhandled flag: movie requires a savestate\n");
-      return NULL;
+      return -1;
     }
     if (gmv->flags & 0x20) {
       fprintf(stderr, "unhandled flag: 3-player movie\n");
-      return NULL;
+      return -1;
     }
     if (gmv->flags & ~0x80) {
       //fprintf(stderr, "unhandled flag(s): %04x\n", gmv->flags);
@@ -519,15 +519,15 @@ static uint8_t *import_gmv(FILE *f, long size, int *byte_count, FILE *logf)
   printf("%d frames, %u rerecords\n",
          frame_count, gmv->rerecord_count);
 
-  out = malloc(frame_count * MAX_INPUT_BYTES);
-  if (out == NULL) {
+  out[0] = malloc(frame_count * MAX_INPUT_BYTES);
+  if (out[0] == NULL) {
     fprintf(stderr, "OOM?\n");
-    return NULL;
+    return -1;
   }
 
   for (i = 0; i < frame_count; i++) {
     val = gmv->data[i][0] | ((gmv->data[i][2] & 0x0f) << 8);
-    count += tas_data_to_teensy(val, out + count, logf);
+    count += tas_data_to_teensy(val, out[0] + count, logf);
 
     if (gmv->data[i][1] != 0xff || gmv->data[i][2] != 0xff)
     {
@@ -536,8 +536,8 @@ static uint8_t *import_gmv(FILE *f, long size, int *byte_count, FILE *logf)
     }
   }
 
-  *byte_count = count;
-  return out;
+  out_byte_count[0] = count;
+  return 0;
 }
 
 static int do_bkm_char(char c, char expect, uint16_t *val, int bit)
@@ -554,18 +554,21 @@ static int do_bkm_char(char c, char expect, uint16_t *val, int bit)
   return 1;
 }
 
-static uint8_t *import_bkm(FILE *f, int *byte_count, FILE *logf)
+static int import_bkm(FILE *f, uint8_t *out[2], int out_byte_count[2],
+  FILE *logf)
 {
-  uint8_t *out = NULL;
-  uint16_t val;
+  int teensy_bytes = 0;
+  int have_pl2 = 0;
+  int have_xyz = 0;
   int frames = 0;
   int count = 0;
   int alloc = 0;
   int line = 0;
   char buf[256];
   const char *r;
+  uint16_t val;
   char *p;
-  int i;
+  int pl, i;
 
   while ((p = fgets(buf, sizeof(buf), f)) != NULL)
   {
@@ -581,53 +584,78 @@ static uint8_t *import_bkm(FILE *f, int *byte_count, FILE *logf)
 
     if (count >= alloc - MAX_INPUT_BYTES) {
       alloc = alloc * 2 + 64;
-      out = realloc(out, alloc * sizeof(out[0]));
-      if (out == NULL) {
-        fprintf(stderr, "OOM?\n");
-        return NULL;
+      for (pl = 0; pl < 2; pl++) {
+        out[pl] = realloc(out[pl], alloc * sizeof(out[0][0]));
+        if (out[pl] == NULL) {
+          fprintf(stderr, "OOM?\n");
+          return -1;
+        }
       }
     }
 
-    val = 0xfff;
-
     if (strncmp(p, "|.|", 3) != 0)
       goto unhandled_line;
     p += 3;
 
-    const char ref[] = "UDLRABCS";
-    for (r = ref, i = 0; *r != 0; p++, r++, i++) {
-      if (do_bkm_char(*p, *r, &val, i))
+    for (pl = 0; pl < 2; pl++) {
+      static const char ref[] = "UDLRABCSXYZM";
+
+      val = 0xfff;
+      for (r = ref, i = 0; *r != 0; p++, r++, i++) {
+        if (do_bkm_char(*p, *r, &val, i))
+          goto unhandled_line;
+      }
+
+      if (*p++ != '|')
         goto unhandled_line;
+
+      teensy_bytes = tas_data_to_teensy(val, out[pl] + count, logf);
+
+      if ((val & 0xf00) != 0xf00)
+        have_xyz = 1;
+      if (pl == 1)
+        have_pl2 |= (val != 0xfff);
     }
+    count += teensy_bytes;
 
-    if (strcmp(p, "....|............||") != 0)
+    if (strcmp(p, "|") != 0)
       goto unhandled_line;
 
-    count += tas_data_to_teensy(val, out + count, logf);
     frames++;
     continue;
 
 unhandled_line:
     fprintf(stderr, "unhandled bkm line %d: '%s'\n", line, buf);
-    return NULL;
+    return -1;
   }
 
-  printf("loaded bkm, %d frames, %d bytes\n", frames, count);
-  *byte_count = count;
-  return out;
+  printf("loaded bkm, %d players, %d frames, %d bytes, have_xyz=%d\n",
+    have_pl2 ? 2 : 1, frames, count, have_xyz);
+  out_byte_count[0] = count;
+  if (have_pl2)
+    out_byte_count[1] = count;
+  else {
+    free(out[1]);
+    out[1] = NULL;
+  }
+
+  return 0;
 }
 
-static uint8_t *import_raw(FILE *f, int *byte_count, FILE *logf)
+static int import_raw(FILE *f, uint8_t *out[2], int out_byte_count[2],
+  FILE *logf)
 {
-  uint8_t *out = NULL, val;
   int count = 0;
   int alloc = 0;
   int line = 0;
   int first = 1;
   char buf[256];
+  uint8_t val;
   char *p;
   int i;
 
+  out_byte_count[0] = out_byte_count[1] = 0;
+
   while ((p = fgets(buf, sizeof(buf), f)) != NULL)
   {
     line++;
@@ -655,27 +683,27 @@ static uint8_t *import_raw(FILE *f, int *byte_count, FILE *logf)
 
     if (count >= alloc) {
       alloc = alloc * 2 + 64;
-      out = realloc(out, alloc * sizeof(out[0]));
-      if (out == NULL) {
+      out[0] = realloc(out[0], alloc * sizeof(out[0][0]));
+      if (out[0] == NULL) {
         fprintf(stderr, "OOM?\n");
-        return NULL;
+        return -1;
       }
     }
 
     if (logf)
       fwrite(&val, 1, 1, logf);
 
-    out[count++] = val & 0x3f;
+    out[0][count++] = val & 0x3f;
     continue;
 
 bad:
     fprintf(stderr, "bad raw line %d: '%s'\n", line, buf);
-    return NULL;
+    return -1;
   }
 
   printf("loaded raw, %d bytes\n", count);
-  *byte_count = count;
-  return out;
+  out_byte_count[0] = count;
+  return 0;
 }
 
 static int write_bkm_frame(FILE *f, const uint8_t *data)
@@ -746,12 +774,11 @@ int main(int argc, char *argv[])
   const char *tasfn = NULL;
   const char *outfn = NULL;
   const char *logfn = NULL;
-  uint8_t *tas_data = NULL;
-  int tas_data_size = 0;
-  int bytes_sent = 0;
+  uint8_t *tas_data[2] = { NULL, NULL };
+  int tas_data_size[2] = { 0, 0 };
+  int bytes_sent[2] = { 0, 0 };
   int use_vsync = 0; // frame increment on vsync
   int no_start_seq = 0;
-  int tas_skip = 0;
   int enable_sent = 0;
   int abort_sent = 0;
   int frame_count = 0;
@@ -858,11 +885,11 @@ int main(int argc, char *argv[])
       ext++;
 
     if (strcasecmp(ext, "gmv") == 0)
-      tas_data = import_gmv(f, size, &tas_data_size, logf);
+      ret = import_gmv(f, size, tas_data, tas_data_size, logf);
     else if (strcasecmp(ext, "bkm") == 0)
-      tas_data = import_bkm(f, &tas_data_size, logf);
+      ret = import_bkm(f, tas_data, tas_data_size, logf);
     else if (strcasecmp(ext, "txt") == 0)
-      tas_data = import_raw(f, &tas_data_size, logf);
+      ret = import_raw(f, tas_data, tas_data_size, logf);
     else {
       fprintf(stderr, "unknown movie type: '%s'\n", ext);
       return 1;
@@ -874,10 +901,14 @@ int main(int argc, char *argv[])
       logf = NULL;
     }
 
-    if (tas_data == NULL) {
+    if (ret != 0 || tas_data[0] == NULL || tas_data_size[0] <= 0) {
       fprintf(stderr, "failed fo parse %s\n", tasfn);
       return 1;
     }
+    if (tas_data_size[1] != 0 && tas_data[1] == NULL) {
+      fprintf(stderr, "missing tas_data[1]\n");
+      return 1;
+    }
   }
 
   if (outfn != NULL) {
@@ -913,7 +944,8 @@ int main(int argc, char *argv[])
       wait_device = 0;
       pending_urbs = 0;
       enable_sent = 0;
-      bytes_sent = 0;
+      bytes_sent[0] = 0;
+      bytes_sent[1] = 0;
 
       /* we wait first, then send commands, but if teensy
        * is started already, it won't send anything */
@@ -1016,21 +1048,25 @@ int main(int argc, char *argv[])
       }
       else if (reaped_urb == &urb[URB_DATA_IN])
       {
+        int p;
+
         /* some request from teensy */
         switch (pkt_in.type) {
         case PKT_STREAM_REQ:
-          printf("req: %d/%d/%d\n", pkt_in.req.frame * 2,
-            bytes_sent, tas_data_size);
+          p = pkt_in.req.is_p2 ? 1 : 0;
+          printf("req%d: %d/%d/%d\n", pkt_in.req.is_p2,
+            pkt_in.req.frame * 2, bytes_sent[p], tas_data_size[p]);
 
           pkt_out.size = 0;
-          if (bytes_sent < tas_data_size) {
-            pkt_out.type = PKT_STREAM_DATA_TO;
+          if (bytes_sent[p] < tas_data_size[p]) {
+            pkt_out.type = p ? PKT_STREAM_DATA_TO_P2
+                             : PKT_STREAM_DATA_TO_P1;
 
-            i = tas_data_size - bytes_sent;
+            i = tas_data_size[p] - bytes_sent[p];
             if (i > sizeof(pkt_out.data))
               i = sizeof(pkt_out.data);
-            memcpy(pkt_out.data, tas_data + bytes_sent, i);
-            bytes_sent += i;
+            memcpy(pkt_out.data, tas_data[p] + bytes_sent[p], i);
+            bytes_sent[p] += i;
             pkt_out.size = i;
           }
           else {
@@ -1086,13 +1122,18 @@ int main(int argc, char *argv[])
       // can't do that yet
       continue;
 
-    if ((tas_data != NULL || outf != NULL) && !enable_sent) {
+    if ((tas_data[0] != NULL || outf != NULL) && !enable_sent) {
       memset(&pkt_out, 0, sizeof(pkt_out));
       pkt_out.type = PKT_STREAM_ENABLE;
-      pkt_out.enable.stream_to = (tas_data != NULL);
+      pkt_out.enable.stream_to = (tas_data[0] != NULL);
       pkt_out.enable.stream_from = (outf != NULL);
-      pkt_out.enable.use_readinc = !use_vsync;
       pkt_out.enable.no_start_seq = no_start_seq;
+      if (use_vsync)
+        pkt_out.enable.inc_mode = INC_MODE_VSYNC;
+      else if (tas_data_size[1] != 0)
+        pkt_out.enable.inc_mode = INC_MODE_SHARED_PL2;
+      else
+        pkt_out.enable.inc_mode = INC_MODE_SHARED_PL1;
 
       ret = submit_urb(dev.fd, &urb[URB_DATA_OUT], dev.ifaces[0].ep_out,
                        &pkt_out, sizeof(pkt_out));
@@ -1102,10 +1143,11 @@ int main(int argc, char *argv[])
       }
       pending_urbs |= 1 << URB_DATA_OUT;
       enable_sent = 1;
-      bytes_sent = 0;
+      bytes_sent[0] = 0;
+      bytes_sent[1] = 0;
       continue;
     }
-    if (tas_data == NULL && fixed_input_changed) {
+    if (tas_data[0] == NULL && fixed_input_changed) {
       memset(&pkt_out, 0, sizeof(pkt_out));
       pkt_out.type = PKT_FIXED_STATE;
       memcpy(pkt_out.data, fixed_input_state, sizeof(fixed_input_state));