X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fsball.c;h=a92e56e1e05e913b47a2dee38f94b3e3e2dcc0ee;hb=70fa99bf4e211d2ff99de790f525977b94c33be7;hp=9dce2ae1c58636c0adf7388b1f52931eb4174657;hpb=9f32047b6512fb261f5b57f62571b658ba6e3330;p=sball diff --git a/src/sball.c b/src/sball.c index 9dce2ae..a92e56e 100644 --- a/src/sball.c +++ b/src/sball.c @@ -1,3 +1,10 @@ +/* Serial spaceball and space-mouse example driver code for UNIX systems. + * Tested with Spaceball 4000FLX and Magellan SpaceMouse on GNU/Linux, FreeBSD, + * SGI/IRIX, and SunOS (Solaris/Illumos). + * + * Author: John Tsiombikas + * No copyright, public domain. + */ #include #include #include @@ -11,6 +18,18 @@ #include #include +#if defined(__i386__) || defined(__ia64__) || defined(WIN32) || \ + (defined(__alpha__) || defined(__alpha)) || \ + defined(__arm__) || \ + (defined(__mips__) && defined(__MIPSEL__)) || \ + defined(__SYMBIAN32__) || \ + defined(__x86_64__) || \ + defined(__LITTLE_ENDIAN__) +#define SBALL_LITTLE_ENDIAN +#else +#define SBALL_BIG_ENDIAN +#endif + #define INP_BUF_SZ 256 enum { @@ -27,7 +46,7 @@ struct sball { int len; short mot[6]; - unsigned int keystate; + unsigned int keystate, keymask; struct termios saved_term; int saved_mstat; @@ -64,13 +83,11 @@ struct sball *sball_open(const char *dev) return 0; } - if(!(sb = malloc(sizeof *sb))) { + if(!(sb = calloc(1, sizeof *sb))) { fprintf(stderr, "sball_open: failed to allocate sball object\n"); goto err; } sb->fd = fd; - sb->flags = 0; - sb->len = 0; stty_save(sb); @@ -85,10 +102,14 @@ struct sball *sball_open(const char *dev) printf("Spaceball detected: %s\n", buf); sb->nbuttons = guess_num_buttons(buf); + sb->keymask = 0xffff >> (16 - sb->nbuttons); printf("%d buttons\n", sb->nbuttons); - /* set binary mode and enable automatic data packet sending */ - write(fd, "\rCB\rMSSV\r", 9); + /* set binary mode and enable automatic data packet sending. also request + * a key event to find out as soon as possible if this is a 4000flx with + * 12 buttons + */ + write(fd, "\rCB\rMSSV\rk\r", 11); sb->parse = sball_parsepkt; return sb; @@ -105,6 +126,7 @@ struct sball *sball_open(const char *dev) printf("Magellan SpaceMouse detected:\n%s\n", buf); sb->nbuttons = guess_num_buttons(buf); + sb->keymask = 0xffff >> (16 - sb->nbuttons); printf("%d buttons\n", sb->nbuttons); /* set 3D mode, not-dominant-axis, pass through motion and button packets */ @@ -169,7 +191,13 @@ int sball_num_buttons(struct sball *sb) return sb->nbuttons; } -/* Labtec spaceball: 9600 8n1 XON/XOFF */ +/* Labtec spaceball: 9600 8n1 XON/XOFF + * Can't use canonical mode to assemble input into lines for the spaceball, + * because binary data received for motion events can include newlines which + * would be eaten up by the line discipline. Therefore we'll rely on VTIME=1 to + * hopefully get more than 1 byte at a time. Alternatively we could request + * printable reports, but I don't feel like implementing that. + */ static int stty_sball(struct sball *sb) { int mstat; @@ -177,17 +205,12 @@ static int stty_sball(struct sball *sb) term = sb->saved_term; term.c_oflag = 0; - term.c_lflag = ICANON; + term.c_lflag = 0; term.c_cc[VMIN] = 0; - term.c_cc[VTIME] = 0; - term.c_cc[VEOF] = 0; - term.c_cc[VEOL] = '\r'; - term.c_cc[VEOL2] = 0; - term.c_cc[VERASE] = 0; - term.c_cc[VKILL] = 0; + term.c_cc[VTIME] = 1; term.c_cflag = CLOCAL | CREAD | CS8 | HUPCL; - term.c_iflag = IGNBRK | IGNPAR; + term.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF; cfsetispeed(&term, B9600); cfsetospeed(&term, B9600); @@ -203,7 +226,10 @@ static int stty_sball(struct sball *sb) return 0; } -/* Logicad magellan spacemouse: 9600 8n2 CTS/RTS */ +/* Logicad magellan spacemouse: 9600 8n2 CTS/RTS + * Since the magellan devices don't seem to send any newlines, we can rely on + * canonical mode to feed us nice whole lines at a time. + */ static int stty_mag(struct sball *sb) { int mstat; @@ -220,7 +246,12 @@ static int stty_mag(struct sball *sb) term.c_cc[VERASE] = 0; term.c_cc[VKILL] = 0; - term.c_cflag = CLOCAL | CREAD | CS8 | CSTOPB | HUPCL | CRTSCTS; + term.c_cflag = CLOCAL | CREAD | CS8 | CSTOPB | HUPCL; +#ifdef CCTS_OFLOW + term.c_cflag |= CCTS_OFLOW; +#elif defined(CRTSCTS) + term.c_cflag |= CRTSCTS; +#endif term.c_iflag = IGNBRK | IGNPAR; cfsetispeed(&term, B9600); @@ -290,24 +321,22 @@ static int mag_parsepkt(struct sball *sb, int id, char *data, int len) return -1; } for(i=0; i<6; i++) { -#ifdef SBALL_BIG_ENDIAN - sb->mot[i] = ((((int)data[3] & 0xf) << 12) | (((int)data[2] & 0xf) << 8) | - (((int)data[1] & 0xf) << 4) | (data[0] & 0xf)) - 0x8000; -#else sb->mot[i] = ((((int)data[0] & 0xf) << 12) | (((int)data[1] & 0xf) << 8) | (((int)data[2] & 0xf) << 4) | (data[3] & 0xf)) - 0x8000; -#endif data += 4; } print_state(sb); break; case 'k': - if(len != 3) { + if(len < 3) { fprintf(stderr, "magellan: invalid keyboard pakcet, expected 3 bytes, got: %d\n", len); return -1; } sb->keystate = (data[0] & 0xf) | ((data[1] & 0xf) << 4) | (((unsigned int)data[2] & 0xf) << 8); + if(len > 3) { + sb->keystate |= ((unsigned int)data[3] & 0xf) << 12; + } print_state(sb); break; @@ -366,16 +395,15 @@ static int sball_parsepkt(struct sball *sb, int id, char *data, int len) } #ifndef SBALL_BIG_ENDIAN + rd = data; for(i=0; i<6; i++) { - data += 2; - c = data[0]; - data[0] = data[1]; - data[1] = c; - sb->mot[i] = *(short*)data; + rd += 2; + c = rd[0]; + rd[0] = rd[1]; + rd[1] = c; } -#else - memcpy(sb->mot, data + 2, 12); #endif + memcpy(sb->mot, data + 2, 12); print_state(sb); break; @@ -391,8 +419,8 @@ static int sball_parsepkt(struct sball *sb, int id, char *data, int len) * data[0] bits 0-2 -> buttons 4,5,6 * data[0] bit 4 is (2003 pick) -> button 7 */ - sb->keystate = (data[1] & 0xf) | ((data[1] >> 4) & 3) | ((data[0] & 7) << 4) | - ((data[0] & 0x10) >> 1); + sb->keystate = ((data[1] & 0xf) | ((data[1] >> 4) & 3) | ((data[0] & 7) << 4) | + ((data[0] & 0x10) << 3)) & sb->keymask; print_state(sb); break; @@ -402,7 +430,12 @@ static int sball_parsepkt(struct sball *sb, int id, char *data, int len) return -1; } /* spaceball 4000 key packet */ - sb->flags |= SB4000; + if(!(sb->flags & SB4000)) { + printf("Switching to spaceball 4000flx/5000flx-a mode (12 buttons) \n"); + sb->flags |= SB4000; + sb->nbuttons = 12; /* might have guessed 8 before */ + sb->keymask = 0xfff; + } /* update orientation flag (actually don't bother) */ /* if(data[0] & 0x20) { @@ -423,7 +456,7 @@ static int sball_parsepkt(struct sball *sb, int id, char *data, int len) case 'E': fprintf(stderr, "sball: error:"); for(i=0; idevice >= 0) { + if(td->device != dev) { + dev = td->device; + sb.keymask = dev == BTEST_SB3003C ? 3 : 0xffff; + parse = (dev < BTEST_SMCLASSIC) ? sball_parsepkt : mag_parsepkt; + printf("\n\nTesting button packets for: %s", btest_models[dev]); + } + + strcpy(pkt, td->pkt + 1); + sb.flags = dev == BTEST_SB4000FLX ? SB4000 : 0; + + printf("\n %s: ", td->label); + parse(&sb, td->pkt[0], pkt, strlen(pkt) - 1); + td++; + } + putchar('\n'); +}