Browse Source

cic interface, cli for real this time...

ikari 13 years ago
parent
commit
d4b7d9630b
4 changed files with 566 additions and 0 deletions
  1. 73 0
      src/cic.c
  2. 19 0
      src/cic.h
  3. 440 0
      src/cli.c
  4. 34 0
      src/cli.h

+ 73 - 0
src/cic.c

@@ -0,0 +1,73 @@
+#include <arm/NXP/LPC17xx/LPC17xx.h>
+#include "bits.h"
+#include "config.h"
+#include "uart.h"
+#include "cic.h"
+
+char *cicstatenames[3] = { "CIC_OK", "CIC_FAIL", "CIC_PAIR" };
+
+void print_cic_state() {
+  printf("CIC state: %s\n", get_cic_statename(get_cic_state()));
+}
+
+inline char *get_cic_statename(enum cicstates state) {
+  return cicstatenames[state];
+}
+
+enum cicstates get_cic_state() {
+  uint32_t count;
+  uint32_t togglecount = 0;
+  uint8_t state, state_old;
+ 
+  state_old = BITBAND(SNES_CIC_STATUS_REG->FIOPIN, SNES_CIC_STATUS_BIT);
+  for(count=0; count<1000; count++) {
+    state = BITBAND(SNES_CIC_STATUS_REG->FIOPIN, SNES_CIC_STATUS_BIT);
+    if(state != state_old) {
+      togglecount++;
+    }
+    state_old = state;
+  }
+  if(togglecount > 20) {
+    printf("%ld\n", togglecount);
+    return CIC_PAIR;
+  }
+  if(state) {
+    return CIC_OK;
+  }
+  return CIC_FAIL;
+}
+
+void cic_init(int allow_pairmode) {
+  BITBAND(SNES_CIC_PAIR_REG->FIODIR, SNES_CIC_PAIR_BIT) = 1;
+  if(allow_pairmode) {
+    BITBAND(SNES_CIC_PAIR_REG->FIOCLR, SNES_CIC_PAIR_BIT) = 1;
+  } else {
+    BITBAND(SNES_CIC_PAIR_REG->FIOSET, SNES_CIC_PAIR_BIT) = 1;
+  }
+}
+
+/* prepare GPIOs for pair mode + set initial modes */
+void cic_pair(int init_vmode, int init_d4) {
+  cic_videomode(init_vmode);
+  cic_d4(init_d4);
+
+  BITBAND(SNES_CIC_D0_REG->FIODIR, SNES_CIC_D0_BIT) = 1;
+  BITBAND(SNES_CIC_D1_REG->FIODIR, SNES_CIC_D1_BIT) = 1;
+}
+
+void cic_videomode(int value) {
+  if(value) {
+    BITBAND(SNES_CIC_D0_REG->FIOSET, SNES_CIC_D0_BIT) = 1;
+  } else {
+    BITBAND(SNES_CIC_D0_REG->FIOCLR, SNES_CIC_D0_BIT) = 1;
+  }
+}
+
+void cic_d4(int value) {
+  if(value) {
+    BITBAND(SNES_CIC_D1_REG->FIOSET, SNES_CIC_D1_BIT) = 1;
+  } else {
+    BITBAND(SNES_CIC_D1_REG->FIOCLR, SNES_CIC_D1_BIT) = 1;
+  }
+}
+

+ 19 - 0
src/cic.h

@@ -0,0 +1,19 @@
+#ifndef _CIC_H
+#define _CIC_H
+
+#include <arm/NXP/LPC17xx/LPC17xx.h>
+#include "bits.h"
+
+enum cicstates { CIC_OK = 0, CIC_FAIL, CIC_PAIR };
+enum cic_region { CIC_NTSC = 0, CIC_PAL };
+
+void print_cic_state(void);
+char *get_cic_statename(enum cicstates state);
+enum cicstates get_cic_state(void);
+void cic_init(int allow_pairmode);
+
+void cic_pair(int init_vmode, int init_d4);
+void cic_videomode(int value);
+void cic_d4(int value);
+
+#endif

+ 440 - 0
src/cli.c

@@ -0,0 +1,440 @@
+/* tapplay - TAP file playback for sd2iec hardware
+   Copyright (C) 2009  Ingo Korb <ingo@akana.de>
+
+   Inspiration and low-level SD/MMC access based on code from MMC2IEC
+     by Lars Pontoppidan et al., see sdcard.c|h and config.h.
+
+   FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License only.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+   cli.c: The command line interface
+
+*/
+
+#include <arm/NXP/LPC17xx/LPC17xx.h>
+#include <arm/bits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "config.h"
+#include "diskio.h"
+#include "ff.h"
+#include "timer.h"
+#include "uart.h"
+#include "fileops.h"
+#include "memory.h"
+#include "snes.h"
+#include "fpga.h"
+#include "cic.h"
+
+#include "cli.h"
+
+#define MAX_LINE 250
+
+/* Variables */
+static char cmdbuffer[MAX_LINE+1];
+static char *curchar;
+
+/* Word lists */
+static char command_words[] =
+  "cd\0reset\0dir\0ls\0test\0resume\0loadrom\0loadraw\0put\0d4\0vmode\0";
+enum { CMD_CD = 0, CMD_RESET, CMD_DIR, CMD_LS, CMD_TEST, CMD_RESUME, CMD_LOADROM, CMD_LOADRAW, CMD_PUT, CMD_D4, CMD_VMODE };
+
+/* ------------------------------------------------------------------------- */
+/*   Parse functions                                                         */
+/* ------------------------------------------------------------------------- */
+
+/* Skip spaces at curchar */
+static uint8_t skip_spaces(void) {
+  uint8_t res = (*curchar == ' ' || *curchar == 0);
+
+  while (*curchar == ' ')
+    curchar++;
+
+  return res;
+}
+
+/* Parse the string in curchar for an integer with bounds [lower,upper] */
+static int32_t parse_unsigned(uint32_t lower, uint32_t upper) {
+  char *end;
+  uint32_t result;
+
+  if (strlen(curchar) == 1 && *curchar == '?') {
+    printf("Number between %ld[0x%lx] and %ld[0x%lx] expected\n",lower,lower,upper,upper);
+    return -2;
+  }
+
+  result = strtoul(curchar, &end, 10);
+  if ((*end != ' ' && *end != 0) || errno != 0) {
+    printf("Invalid numeric argument\n");
+    return -1;
+  }
+
+  curchar = end;
+  skip_spaces();
+
+  if (result < lower || result > upper) {
+    printf("Numeric argument out of range (%ld..%ld)\n",lower,upper);
+    return -1;
+  }
+
+  return result;
+}
+/* Parse the string starting with curchar for a word in wordlist */
+static int8_t parse_wordlist(char *wordlist) {
+  uint8_t i, matched;
+  char *cur, *ptr;
+  char c;
+
+  i = 0;
+  ptr = wordlist;
+
+  // Command list on "?"
+  if (strlen(curchar) == 1 && *curchar == '?') {
+    printf("Commands available: \n ");
+    while (1) {
+      c = *ptr++;
+      if (c == 0) {
+        if (*ptr == 0) {
+          printf("\n");
+          return -2;
+        } else {
+          printf("\n ");
+        }
+      } else
+        uart_putc(c);
+    }
+  }
+
+  while (1) {
+    cur = curchar;
+    matched = 1;
+    c = *ptr;
+    do {
+      // If current word list character is \0: No match found
+      if (c == 0) {
+        printf("Unknown word: %s\n",curchar);
+        return -1;
+      }
+
+      if (tolower(c) != tolower(*cur)) {
+        // Check for end-of-word
+        if (cur != curchar && (*cur == ' ' || *cur == 0)) {
+          // Partial match found, return that
+          break;
+        } else {
+          matched = 0;
+          break;
+        }
+      }
+      ptr++;
+      cur++;
+      c = *ptr;
+    } while (c != 0);
+    
+    if (matched) {
+      char *tmp = curchar;
+
+      curchar = cur;
+      // Return match only if whitespace or end-of-string follows
+      // (avoids mismatching partial words)
+      if (skip_spaces()) {
+        return i;
+      } else {
+        printf("Unknown word: %s\n(use ? for help)\n",tmp);
+        return -1;
+      }
+    } else {
+      // Try next word in list
+      i++;
+      while (*ptr++ != 0) ;
+    }
+  }
+}
+
+/* Read a line from serial, uses cmdbuffer as storage */
+static char *getline(char *prompt) {
+  int i=0;
+  char c;
+
+  printf("\n%s",prompt);
+  memset(cmdbuffer,0,sizeof(cmdbuffer));
+
+  while (1) {
+    c = uart_getc();
+    if (c == 13)
+      break;
+
+    if (c == 27 || c == 3) {
+      printf("\\\n%s",prompt);
+      i = 0;
+      memset(cmdbuffer,0,sizeof(cmdbuffer));
+      continue;
+    }
+
+    if (c == 127 || c == 8) {
+      if (i > 0) {
+        i--;
+        uart_putc(8);   // backspace
+        uart_putc(' '); // erase character
+        uart_putc(8);   // backspace
+      } else
+        continue;
+    } else {
+      if (i < sizeof(cmdbuffer)-1) {
+        cmdbuffer[i++] = c;
+        uart_putc(c);
+      }
+    }
+  }
+  cmdbuffer[i] = 0;
+  return cmdbuffer;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/*   Command functions                                                       */
+/* ------------------------------------------------------------------------- */
+
+/* Reset */
+static void cmd_reset(void) {
+  /* force watchdog reset */
+  LPC_WDT->WDTC = 256; // minimal timeout
+  LPC_WDT->WDCLKSEL = BV(31); // internal RC, lock register
+  LPC_WDT->WDMOD = BV(0) | BV(1); // enable watchdog and reset-by-watchdog
+  LPC_WDT->WDFEED = 0xaa;
+  LPC_WDT->WDFEED = 0x55; // initial feed to really enable WDT
+}
+
+/* Show the contents of the current directory */
+static void cmd_show_directory(void) {
+  FRESULT res;
+  DIR dh;
+  FILINFO finfo;
+  uint8_t *name;
+
+  f_getcwd((TCHAR*)file_lfn, 255);
+
+  res = f_opendir(&dh, (TCHAR*)file_lfn);
+  if (res != FR_OK) {
+    printf("f_opendir failed, result %d\n",res);
+    return;
+  }
+
+  finfo.lfname = (TCHAR*)file_lfn;
+  finfo.lfsize = 255;
+
+  do {
+    /* Read the next entry */
+    res = f_readdir(&dh, &finfo);
+    if (res != FR_OK) {
+      printf("f_readdir failed, result %d\n",res);
+      return;
+    }
+
+    /* Abort if none was found */
+    if (!finfo.fname[0])
+      break;
+
+    /* Skip volume labels */
+    if (finfo.fattrib & AM_VOL)
+      continue;
+
+    /* Select between LFN and 8.3 name */
+    if (finfo.lfname[0])
+      name = (uint8_t*)finfo.lfname;
+    else {
+      name = (uint8_t*)finfo.fname;
+      strlwr((char *)name);
+    }
+
+#if 0
+    if (finfo.fattrib & AM_DIR) {
+      printf("DIR ");
+    } else {
+      printf("    ");
+    }
+#endif
+
+    printf("%s",name);
+
+    /* Directory indicator (Unix-style) */
+    if (finfo.fattrib & AM_DIR)
+      uart_putc('/');
+
+    printf("\n");
+  } while (finfo.fname[0]);
+}
+
+
+static void cmd_loadrom(void) {
+  uint32_t address = 0;
+  snes_reset(1);
+  set_mcu_ovr(1);
+  load_rom((uint8_t*)curchar, address);
+  set_mcu_ovr(0);
+  snes_reset(0);
+}
+
+static void cmd_d4(void) {
+  int32_t hz;
+
+  if(get_cic_state() != CIC_PAIR) {
+    printf("not in pair mode\n");
+  } else {
+    hz = parse_unsigned(50,60);
+    if(hz==50) {
+      cic_d4(CIC_PAL);
+    } else {
+      cic_d4(CIC_NTSC);
+    }
+    printf("ok\n");
+  }
+}
+
+static void cmd_vmode(void) {
+  int32_t hz;
+  if(get_cic_state() != CIC_PAIR) {
+    printf("not in pair mode\n");
+  } else {
+    hz = parse_unsigned(50,60);
+    if(hz==50) {
+      cic_videomode(CIC_PAL);
+    } else {
+      cic_videomode(CIC_NTSC);
+    }
+    printf("ok\n");
+  }
+}
+
+#if 0
+  uint8_t *buf = malloc(256);
+
+  if (buf == NULL) {
+    printf("buffer allocation failed!\n");
+    return;
+  }
+
+  for (int i=0;i<256;i++) {
+    buf[i] = i2c_read_register(0xa0, i);
+  }
+
+  uart_trace(buf, 0, 256);
+  free(buf);
+#endif
+
+/* ------------------------------------------------------------------------- */
+/*   CLI interface functions                                                 */
+/* ------------------------------------------------------------------------- */
+
+void cli_init(void) {
+}
+
+void cli_entrycheck() {
+  if(uart_gotc() && uart_getc() == 27) {
+    printf("*** BREAK\n");
+    cli_loop();
+  }
+}
+
+void cli_loop(void) {
+  while (1) {
+    curchar = getline(">");
+    printf("\n");
+
+    /* Process medium changes before executing the command */
+    if (disk_state != DISK_OK && disk_state != DISK_REMOVED) {
+      FRESULT res;
+
+      printf("Medium changed... ");
+      res = f_mount(0,&fatfs);
+      if (res != FR_OK) {
+        printf("Failed to mount new medium, result %d\n",res);
+      } else {
+        printf("Ok\n");
+      }
+
+    }
+
+    /* Remove whitespace */
+    while (*curchar == ' ') curchar++;
+    while (strlen(curchar) > 0 && curchar[strlen(curchar)-1] == ' ')
+      curchar[strlen(curchar)-1] = 0;
+
+    /* Ignore empty lines */
+    if (strlen(curchar) == 0)
+      continue;
+
+    /* Parse command */
+    int8_t command = parse_wordlist(command_words);
+    if (command < 0)
+      continue;
+
+
+    FRESULT res;
+    switch (command) {
+    case CMD_CD:
+#if _FS_RPATH
+      if (strlen(curchar) == 0) {
+        f_getcwd((TCHAR*)file_lfn, 255);
+        printf("%s\n",file_lfn);
+        break;
+      }
+
+      res = f_chdir((const TCHAR *)curchar);
+      if (res != FR_OK) {
+        printf("chdir %s failed with result %d\n",curchar,res);
+      } else {
+        printf("Ok.\n");
+      }
+#else
+      printf("cd not supported.\n");
+      res;
+#endif
+    break;
+    case CMD_RESET:
+      cmd_reset();
+      break;
+
+    case CMD_DIR:
+    case CMD_LS:
+      cmd_show_directory();
+      break;
+
+    case CMD_RESUME:
+      return;
+      break;
+
+    case CMD_LOADROM:
+      cmd_loadrom();
+      break;
+
+    case CMD_D4:
+      cmd_d4();
+      break;
+
+    case CMD_VMODE:
+      cmd_vmode();
+      break;
+
+    }
+  }
+}

+ 34 - 0
src/cli.h

@@ -0,0 +1,34 @@
+/* tapplay - TAP file playback for sd2iec hardware
+   Copyright (C) 2009  Ingo Korb <ingo@akana.de>
+
+   Inspiration and low-level SD/MMC access based on code from MMC2IEC
+     by Lars Pontoppidan et al., see sdcard.c|h and config.h.
+
+   FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License only.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+   cli.h: Definitions for cli.c
+
+*/
+
+#ifndef CLI_H
+#define CLI_H
+
+void cli_init(void);
+void cli_loop(void);
+void cli_entrycheck(void);
+
+#endif