changeset 0:e1a1a181c0d7

initial import
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Thu, 16 Dec 2010 20:30:11 +0900
parents
children 05cc06e88a57
files Makefile cdcnv.c rcctl.c
diffstat 3 files changed, 480 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Thu Dec 16 20:30:11 2010 +0900
@@ -0,0 +1,13 @@
+# $Id: Makefile,v 1.1 2002/12/21 01:13:27 tosy Exp $
+
+TARGET = rcctl
+SRCS = rcctl.c cdcnv.c
+CC = gcc
+CCOPT = -O -lusb -Wall
+
+all:
+	$(CC) $(CCOPT) -o $(TARGET) $(SRCS)
+
+debug:
+	$(CC) $(CCOPT) -DVERBOSE -DDEBUG -o $(TARGET) $(SRCS)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cdcnv.c	Thu Dec 16 20:30:11 2010 +0900
@@ -0,0 +1,260 @@
+/* cdcnv.c ---------------------------------------------
+$Id: cdcnv.c,v 1.1 2002/12/21 01:13:27 tosy Exp $
+
+  (以前の履歴は rcctl.c 参照)
+  v0.30  97.12.13  コード変換部(cdcnv.c)分離
+  v0.31  98.03.07  Mac21対応
+  v0.31a 98.03.11  Syncom対応(要rc_send修正)
+  v0.31b 98.03.15  ALISA3(L)対応
+  v0.32  98.11.29  鉄人,Σ,NET7000対応
+  v0.40  02.12.15  B-kara,HyperJOY対応,Σバグ修正
+------------------------------------------------------*/
+
+#include <string.h>
+#if defined(__FreeBSD__)||defined(linux)
+#define stricmp(s, c) strcasecmp(s, c)
+#endif
+
+const char *mks = "XUGJHBPDSNKMALZTCI";
+#define M_X2 0	/* X2000 */
+#define M_UK 1	/* U-kara */
+#define M_GI 2	/* GIGA */
+#define M_JO 3	/* JOYSOUND */
+#define M_HJ 4	/* HyperJOY */
+#define M_BT 5	/* BeMax'S(T) */
+#define M_PR 6	/* Prologue21 */
+#define M_DA 7	/* DAM */
+#define M_SY 8	/* Syncom/孫悟空 */
+#define M_N7 9	/* NET7000 */
+#define M_BK 10 /* B-kara */
+#define M_MA 11	/* Mac21 */
+#define M_A3 12	/* ALISA3(A) */
+#define M_AL 13	/* ALISA3(L) */
+#define M_AZ 14	/* ALISA3(Z) */
+#define M_TS 15	/* 東映システム */
+#define M_SI 16	/* Σシステム */
+#define M_TJ 17	/* カラオケの鉄人 */
+
+#define K_SE 3
+#define K_KU 4
+#define K_KD 5
+#define K_SP 6
+#define K_ST 7
+#define K_CL 8
+#define K_NM 9
+
+int cvt[][21] = {
+  /* cd,  IDL,  IDH,   SE,   KU,   KD,   SP,   ST,   CL, */
+  /*  0,    1,    2,    3,    4,    5,    6,    7,    8,    9,    A,    B*/
+  {0x30, 0x2e, 0xd1, 0x17, 0x02, 0x03, 0x0c, 0x1c, 0x0d,         /* X2000 */
+   0x13, 0x10, 0x14, 0x18, 0x11, 0x15, 0x19, 0x12, 0x16, 0x1a,   -1,   -1 },
+  {0x30, 0x98, 0x67, 0x0c, 0x13, 0x12, 0x0f, 0x0e, 0x0d,     /* U-kara/-2 */
+   0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,   -1,   -1 },
+  {0x10, 0x84, 0x10,   -1, 0x04, 0x05, 0x0f, 0x01,   -1,          /* GIGA */
+   0xf0, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0,   -1,   -1 },
+  {0x40, 0x81, 0x16, 0x1f, 0x54, 0x0b, 0x1d, 0x5c, 0x1c,      /* JOYSOUND */
+   0x00, 0x07, 0x0a, 0x58, 0x03, 0x06, 0x50, 0x01, 0x0e, 0x5d,   -1,   -1 },
+  {0x20, 0x81, 0x16, 0x1f, 0x54, 0x0b, 0x1d, 0x5c, 0x1c,      /* HyperJOY */
+   0x00, 0x07, 0x0a, 0x58, 0x03, 0x06, 0x50, 0x01, 0x0e, 0x5d,   -1,   -1 },
+  {0x20, 0xac, 0x53, 0x9d, 0xcc, 0xca, 0x96, 0xdc, 0x9a,   /* BeMax'S (T) */
+   0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,   -1,   -1 },
+  {0x10, 0x81, 0xb0, 0x33, 0xd3, 0xb3, 0x93, 0x13,   -1,    /* Prologue21 */
+   0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, 0x01, 0x09,   -1,   -1 },
+  {0x10, 0xd1, 0x2d, 0x09, 0x04, 0x05, 0x00, 0x01, 0x07,           /* DAM */
+   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b },
+  {0x60, 0xc3, 0xc3, 0x05, 0x2c, 0x2d, 0x04, 0xc7, 0x02,        /* Syncom */
+   0x0f, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,   -1,   -1 },
+  {0x30, 0x84, 0x05, 0x0f, 0x0e, 0x0c, 0x07,   -1, 0x1e,       /* NET7000 */
+   0x1c, 0x10, 0x11, 0x12, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1a,   -1,   -1 },
+  {0x10, 0x2e, 0xd1, 0x4c, 0x35, 0x33, 0x4f, 0x4e, 0x4d,        /* B-kara */
+   0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b },
+  {0x30, 0x80, 0x00, 0x03, 0x18, 0x14, 0x1e,   -1, 0x07,         /* Mac21 */
+   0x00, 0x0c, 0x0d, 0x0e, 0x08, 0x09, 0x0a, 0x04, 0x05, 0x06, 0x01, 0x02 },
+  {0x30, 0x87, 0x56, 0x12, 0x43, 0x47, 0x11,   -1, 0x42,        /* ALISA3 */
+   0x0d, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f },
+  {0x30, 0x87, 0x56, 0x12, 0x43, 0x47, 0x11,   -1, 0x42,        /* ALISA3 */
+   0x0d, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f },
+  {0x30, 0x87, 0x56, 0x12, 0x43, 0x47, 0x11,   -1, 0x42,        /* ALISA3 */
+   0x0d, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f },
+  {0x30, 0x00, 0xff, 0x41, 0x08, 0x09, 0x4c, 0x45, 0x44,      /* TOEI sys */
+   0x13, 0x0f, 0x4f, 0x4e, 0x07, 0x47, 0x46, 0x03, 0x43, 0x42, 0x53, 0x52 },
+  {0x10, 0x55, 0xaa, 0x3e, 0x08, 0x09, 0x5c,   -1,   -1,     /* Σ System */
+   0x13, 0x0f, 0x4f, 0x4e, 0x07, 0x47, 0x46, 0x03, 0x43, 0x42, 0x53, 0x52 },
+  {0x40, 0xae, 0x51, 0xdc, 0x03, 0x02, 0x96,   -1, 0xdd,          /* 鉄人 */
+   0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0xda, 0xdb }
+  };
+
+int tsc[] = {0x00, 0x04, 0x0c, 0x10, 0x01, 0x05, 0x0d, 0x11};
+int tjc[] = {0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xde, 0xd0, 0xd1, 0xd2, 0xd3};
+
+char *cverrstr[] = {
+  "Invalid maker code.",
+  "Invalid music number.",
+  "Invalid function code."
+};
+
+int cdcnv(int buf[], char *mak, char *cod)
+{
+  int maker, i, c, n, *q;
+
+  if ((maker = (int)strchr(mks, *mak & 0xdf)) == NULL)
+    return -1;
+  maker -= (int)mks;
+
+  q = buf;
+
+  *q++ = 0x80;	/* wake-up code */
+  *q++ = cvt[maker][0];
+  *q++ = cvt[maker][1];
+  *q++ = cvt[maker][2];
+
+  /* 統合機種等でのメーカー名指定 */
+  if ((c = *++mak) != 0) {
+    if ((maker == M_A3)&&('0' <= c)&&(c <= '4'))
+      cvt[maker][K_SE] = 0x12 + (c - '0');
+    else if ((maker == M_AZ)&&('1' <= c)&&(c <= '4'))
+      *q++ = 0x13 + (c - '1');
+    else if ((maker == M_AL)&&('0' <= c)&&(c <= '9')) {
+      *q++ = cvt[maker][K_NM + (c - '0')];
+      *q++ = 0x10;
+    }
+    else if ((maker == M_TS)&&('1' <= c)&&(c <= '8'))
+      *q++ = tsc[c - '1'];
+    else if ((maker == M_TJ)&&('0' <= c)&&(c <= '9'))
+      *q++ = tjc[c - '1'];
+    else if ((maker == M_UK)&&('2' == c)) {
+      buf[1] = 0x70;
+      *q++ = 0xf0;
+    }
+  }
+  if (maker == M_BK)
+    *q++ = 0xf0;
+
+  if (('0' <= *cod)&&(*cod <= '9')) {
+    if (maker == M_DA)
+      *q++ = 0x08;
+    else if (maker == M_MA)
+      *q++ = 0x10;	/* Req.1 */
+    else if (maker == M_SI) {
+      /* [1-9A-F] -> '01','02',...,'15' , NULL -> '00' */
+      if (*mak == 0) {
+        *q++ = cvt[maker][K_NM + 0];
+        *q++ = cvt[maker][K_NM + 0];
+      }
+      else {
+        if (mak[1] != 0)
+	  *q++ = cvt[maker][K_NM + (*mak++ - '0')];
+	else
+	  *q++ = cvt[maker][K_NM + ((*mak >= 'A')? 1: 0)];
+	*q++ = cvt[maker][K_NM + ((*mak % 0x41) & 0x0f)];
+      }
+    }
+
+    /* 曲コード変換 */
+    while((c = *cod++) != '\0') {
+      if (('0' <= c)&&(c <= '9'))
+        *q = cvt[maker][c - '0' + K_NM];
+      else if ((c == 'A')||(c == 'a'))
+        *q = cvt[maker][10 + K_NM];
+      else if ((c == 'B')||(c == 'b'))
+        *q = cvt[maker][11 + K_NM];
+      else if (c == '-') {
+	if (maker == M_TJ)
+	  *q = cvt[maker][K_SE];
+	else
+	  continue;
+      }
+      else
+        *q = -1;
+      if (*q++ == -1)
+	return -2;
+    }
+
+    /* 送信直前処理 */
+    switch(maker) {
+    case M_X2:
+      /* X2000: 曲コードの末尾 2 桁の直前にも SET を送信 */
+      q -= 2;
+      q[3] = cvt[maker][K_SE];
+      q[2] = q[1];
+      q[1] = q[0];
+      q[0] = cvt[maker][K_SE];
+      q += 4;
+      break;
+
+    case M_GI:
+      /* GIGA: 曲コードが 6 桁以下の場合は最後に'0'を埋める */
+      while(q < &buf[10])
+        *q++ = cvt[maker][K_NM];
+      break;
+
+    case M_PR:
+      /* Prologue21: */
+      for( i=0; i<3; i++ ) {
+        buf[10-i] = 0;
+        if (q > &buf[4])
+          buf[10-i] = *--q << 4;
+        if (q > &buf[4])
+          buf[10-i] |= *--q;
+      }
+      q = &buf[11];
+      *q++ = 0x33;
+      buf[4] = buf[8];
+      buf[5] = buf[9];
+      buf[6] = buf[10];
+      buf[7] = buf[11];
+      break;  /* q=&buf[8] にしないとバグのような… */
+
+    case M_SI:
+      /* Σシステム: コード長 10 バイト(<Maker[2]>,<Code[7]>,<SET>)固定 */
+    case M_DA:
+      /* DAM: コード長 9 バイト(0x08,<Code[7]>,<SET>)固定 */
+    case M_BK:
+      /* B-kara: コード長 9 バイト(0xf0,<Code[7]>,<SET>)固定 */
+      n = (maker == M_SI)? 12: 11; /* 数字の最終桁を buf[n] とした値 */
+      for( i=0; i<7; i++ ) {
+        c = *(q-1);
+	if ((i == 1)&&((c == cvt[maker][K_NM+10])||(c == cvt[maker][K_NM+11])))
+	  /* 曲コード中の'A','B'以降の桁数が1桁なら'0'を挿入 */
+	  buf[n-i] = cvt[maker][K_NM + 0];
+        else if ((i == 2)&&(c!=cvt[maker][K_NM+10])&&(c!=cvt[maker][K_NM+11]))
+	  /* 曲コードの末尾 3 文字めが'A','B'でなければ'-'を設定 */
+          buf[n-i] = (maker == M_BK)? 0x3d: ((maker == M_SI)? 0x51: 0x3c);
+        else if (q > &buf[n-6])
+          buf[n-i] = *--q;
+        else
+	  /* 桁数の足らない部分には'0'を設定 */
+          buf[n-i] = cvt[maker][K_NM + 0];
+      }
+      q = &buf[n+1];
+    default:
+      *q++ = cvt[maker][K_SE];
+      break;
+    }
+  }
+  /* 制御コードの処理 */
+  else {
+    *q = -1;
+    if (!stricmp(cod, "SE"))
+      *q = cvt[maker][K_SE];
+    else if (!stricmp(cod, "KU"))
+      *q = cvt[maker][K_KU];
+    else if (!stricmp(cod, "KD"))
+      *q = cvt[maker][K_KD];
+    else if (!stricmp(cod, "SP"))
+      *q = cvt[maker][K_SP];
+    else if (!stricmp(cod, "ST"))
+      *q = cvt[maker][K_ST];
+    else if (!stricmp(cod, "CL"))
+      *q = cvt[maker][K_CL];
+    if (*q == -1)
+      return -3;
+    q++;
+  }
+
+  if ((maker == M_BK)||((maker == M_UK)&&('2' == *mak)))
+    *q++ = 0xf7;
+
+  buf[1] |= q-buf-2;	/* 実送信バイト数(PIC 制御用)を埋め込み */
+  return q-buf;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rcctl.c	Thu Dec 16 20:30:11 2010 +0900
@@ -0,0 +1,207 @@
+/* rcctl.c ---------------------------------------------
+$Id: rcctl.c,v 1.1 2002/12/21 01:13:28 tosy Exp $
+
+  v0.10  97.08.15  初期版(コミケット52)
+  v0.11  97.08.27  通信タイミング修正
+  v0.12  97.09.12  U-kara-2サポート
+  v0.12a 97.09.15  返り値設定
+  v0.12b 97.09.20  Bug fix (JOY:[SP])
+  v0.20  97.10.01  FreeBSD版
+  v0.20a 97.10.18  Bug fix (X2k:[SP],[ST])
+  v0.21  97.12.10  ALISA-3シーケンス修正
+  v0.30  97.12.13  コード変換部(cdcnv.c)分離
+  v0.40  02.12.16  USB版対応
+  【cdcnv.c の履歴も参照のこと】
+------------------------------------------------------*/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <termios.h>
+#include <unistd.h>
+#include <libusb.h>
+#include <sys/ioctl.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+/* #define VERBOSE */
+/* #define NOCTSCHK */
+
+#ifndef SDEV
+#define SDEV "/dev/cuaa0"
+#endif
+
+#ifndef UDEV
+#define UDEV "/dev/uhid0"
+#endif
+
+#ifndef S_VERS
+#define S_VERS "0.40"
+#endif
+
+int fd;
+
+int cdcnv(int buf[], char *mak, char *cod);
+extern char *cverrstr[];
+
+int init_sio(void)
+{
+#ifndef NOCTSCHK
+  int tcnt = 0;
+#endif
+  struct termios tios;
+  int md;
+
+  if ((fd = open(SDEV, O_RDWR)) == -1) {
+    fprintf(stderr, "Cannot open %s.\n", SDEV);
+    return 255;
+  }
+
+  tcgetattr(fd, &tios);
+  tios.c_iflag = 0;
+  tios.c_oflag = 0;
+  tios.c_cflag = B9600|CS8|CLOCAL;
+  tios.c_lflag = 0;
+/*
+  cfmakeraw(&tios);
+  cfsetspeed(&tios, B9600);
+*/
+  tcsetattr(fd, TCSANOW, &tios);
+  tcflush(fd, TCOFLUSH);
+
+  md = TIOCM_LE|TIOCM_DTR|TIOCM_RTS;
+  ioctl(fd, TIOCMBIS, &md);
+
+  /* wait for CTS: 充電待ち */
+#ifndef NOCTSCHK
+  for(;;) {
+    ioctl(fd, TIOCMGET, &md);
+    if (md & TIOCM_CTS)
+      break;
+    if (tcnt == 0) {
+      fprintf(stderr, "Waiting....");
+    }
+    if (tcnt++ >= 30) {
+      fprintf(stderr, "Device timeout.\n");
+      close(fd);
+      return 1;
+    }
+    sleep(1);
+  }
+#endif /* NOCTSCHK */
+
+  md = TIOCM_RTS;
+  ioctl(fd, TIOCMBIC, &md);
+  usleep(10000);	/* 10ms */
+  ioctl(fd, TIOCMBIS, &md);
+  usleep(50000);	/* 50ms */
+
+  return 0;
+}
+
+/* CTS が 0.5 秒以上連続して ON になるまで待つ */
+void charge(void)
+{
+#ifndef NOCTSCHK
+  int i, md;
+
+  for( i=0; i<50; i++ ) {
+    usleep(10000);	/* 10ms */
+    ioctl(fd, TIOCMGET, &md);
+    if (!(md & TIOCM_CTS))
+      i = 0;
+  }
+#endif /* NOCTSCHK */
+}
+
+int init_usb(void)
+{
+  report_desc_t rd;
+  hid_data_t hd;
+  hid_item_t shi;
+
+  hid_init(NULL);
+
+  if((fd = open(UDEV, O_RDWR)) < 0) {
+    fprintf(stderr, "Cannot open %s.\n", UDEV);
+    return 1;
+  }
+
+  /* read header */
+  if ((rd = hid_get_report_desc(fd)) == 0) {
+    fprintf(stderr, "Failed on USB_GET_REPORT_DESC.\n");
+    return 1;
+  }
+
+  /* parse */
+  hd = hid_start_parse(rd, 1<<hid_output);
+  while ( hid_get_item(hd, &shi) ) {
+    if(shi.kind == hid_output)
+      break;
+  }
+  hid_end_parse(hd);
+
+  /* prepare buffers */
+  if (hid_report_size(rd, hid_output, 0) != 8) {
+    fprintf(stderr, "%s is not 'OKCon/USB'?\n", UDEV);
+    return 1;
+  };
+
+  hid_dispose_report_desc(rd);
+
+  return 0;
+}
+
+int main(int ac, char *av[])
+{
+  int i, u, buf[16];
+  u_char sbuf[8];
+
+  if (ac < 3) {
+    printf("'Oke-Con' controller, version " S_VERS ".\n");
+    printf("Copyright (C) 1997-2002 by Tosy / W341IG.\n");
+    printf("Usage: rcctl <maker> <code>\n");
+    return 255;
+  }
+
+  if ((u = cdcnv(buf, av[1], av[2])) < 0) {
+    fprintf(stderr, "%s: %s\n", av[0], cverrstr[~u]);
+    return 1;
+  }
+
+#ifdef VERBOSE
+  printf("Initializing....");
+#endif
+  if (init_usb())
+  /* if (init_sio()) */
+    return 255;
+#ifdef VERBOSE
+  printf(" done.\n");
+#endif
+
+#ifdef VERBOSE
+/*  printf("maker %d (%c).\n", maker, mks[maker]); */
+  for(i=0; i<u; i++ ) {
+    printf("%02x ", buf[i]);
+  }
+  printf("\n");
+#endif
+
+  for(i=1; i<u; i++ ) {
+    sbuf[(i-1)%8] = buf[i] & 0x00ff;
+#ifdef VERBOSE
+    printf("%02x ", sbuf[(i-1)%8]);
+#endif
+    if ((i == 8)||(i == (u-1))) {
+      write(fd, sbuf, 8);
+#ifdef VERBOSE
+      printf(" --- got %d chars.\n", read(fd, sbuf, 8));
+#else
+      read(fd, sbuf, 8);
+#endif
+    }
+  }
+
+  /* charge(); */
+  close(fd);
+  return 0;
+}