merged the new serial device code, and deleted libsball and the old

inactive magellan code.
pull/26/merge
John Tsiombikas 2020-11-10 01:01:25 +02:00
rodzic 26c840da63
commit 486645527f
15 zmienionych plików z 620 dodań i 2033 usunięć

Wyświetl plik

@ -1,5 +1,5 @@
src = $(sort $(wildcard src/*.c) $(wildcard src/serial/*.c) $(wildcard src/magellan/*.c))
hdr = $(wildcard src/*.h) $(wildcard src/serial/*.h) $(wildcard src/magellan/*.h)
src = $(sort $(wildcard src/*.c))
hdr = $(wildcard src/*.h)
obj = $(src:.c=.o)
dep = $(obj:.o=.d)
bin = spacenavd

Wyświetl plik

@ -1,6 +1,6 @@
/*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2007-2020 John Tsiombikas <nuclear@member.fsf.org>
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
@ -15,40 +15,648 @@ 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include "dev_serial.h"
#include "dev.h"
#include "event.h"
#include "serial/sball.h"
#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
#define EVQUEUE_SZ 64
enum {
SB4000 = 1,
FLIPXY = 2
};
struct sball {
int fd;
unsigned int flags;
int nbuttons;
char buf[INP_BUF_SZ];
int len;
short mot[6];
unsigned int keystate, keymask;
struct termios saved_term;
int saved_mstat;
struct dev_input evqueue[EVQUEUE_SZ];
int evq_rd, evq_wr;
int (*parse)(struct sball*, int, char*, int);
};
static void close_dev_serial(struct device *dev);
static int read_dev_serial(struct device *dev, struct dev_input *inp);
static int stty_sball(struct sball *sb);
static int stty_mag(struct sball *sb);
static void stty_save(struct sball *sb);
static void stty_restore(struct sball *sb);
static int proc_input(struct sball *sb);
static int mag_parsepkt(struct sball *sb, int id, char *data, int len);
static int sball_parsepkt(struct sball *sb, int id, char *data, int len);
static int guess_num_buttons(const char *verstr);
static void make_printable(char *buf, int len);
static int read_timeout(int fd, char *buf, int bufsz, long tm_usec);
static void enqueue_motion(struct sball *sb, int axis, int val);
static void gen_button_events(struct sball *sb, unsigned int prev);
int open_dev_serial(struct device *dev)
{
if(!(dev->data = sball_open(dev->path))) {
return -1;
}
dev->fd = sball_get_fd(dev->data);
int fd, sz;
char buf[128];
struct sball *sb = 0;
if((fd = open(dev->path, O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1) {
fprintf(stderr, "sball_open: failed to open device: %s: %s\n", dev->path, strerror(errno));
return 0;
}
if(!(sb = calloc(1, sizeof *sb))) {
fprintf(stderr, "sball_open: failed to allocate sball object\n");
goto err;
}
dev->data = sb;
dev->fd = sb->fd = fd;
dev->close = close_dev_serial;
dev->read = read_dev_serial;
return 0;
stty_save(sb);
if(stty_sball(sb) == -1) {
goto err;
}
write(fd, "\r@RESET\r", 8);
if((sz = read_timeout(fd, buf, sizeof buf - 1, 2000000)) > 0 && strstr(buf, "\r@1")) {
/* we got a response, so it's a spaceball */
make_printable(buf, sz);
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. 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 0;
}
/* try as a magellan spacemouse */
if(stty_mag(sb) == -1) {
goto err;
}
write(fd, "vQ\r", 3);
if((sz = read_timeout(fd, buf, sizeof buf - 1, 250000)) > 0 && buf[0] == 'v') {
make_printable(buf, sz);
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 */
write(fd, "m3\r", 3);
sb->parse = mag_parsepkt;
return 0;
}
err:
stty_restore(sb);
close(fd);
free(sb);
return -1;
}
static void close_dev_serial(struct device *dev)
{
if(dev->data) {
sball_close(dev->data);
stty_restore(dev->data);
close(dev->fd);
}
dev->data = 0;
}
static int read_dev_serial(struct device *dev, struct dev_input *inp)
{
if(!dev->data || !sball_get_input(dev->data, inp)) {
int sz;
struct sball *sb = dev->data;
if(!sb) return -1;
while((sz = read(sb->fd, sb->buf + sb->len, INP_BUF_SZ - sb->len - 1)) > 0) {
sb->len += sz;
proc_input(sb);
}
/* if we fill the input buffer, make a last attempt to parse it, and discard
* it so we can receive more
*/
if(sb->len >= INP_BUF_SZ) {
proc_input(sb);
sb->len = 0;
}
if(sb->evq_rd != sb->evq_wr) {
*inp = sb->evqueue[sb->evq_rd];
sb->evq_rd = (sb->evq_rd + 1) & (EVQUEUE_SZ - 1);
return 0;
}
return -1;
}
/* 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;
struct termios term;
term = sb->saved_term;
term.c_oflag = 0;
term.c_lflag = 0;
term.c_cc[VMIN] = 0;
term.c_cc[VTIME] = 1;
term.c_cflag = CLOCAL | CREAD | CS8 | HUPCL;
term.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF;
cfsetispeed(&term, B9600);
cfsetospeed(&term, B9600);
if(tcsetattr(sb->fd, TCSAFLUSH, &term) == -1) {
perror("sball_open: tcsetattr");
return -1;
}
tcflush(sb->fd, TCIOFLUSH);
mstat = sb->saved_mstat | TIOCM_DTR | TIOCM_RTS;
ioctl(sb->fd, TIOCMGET, &mstat);
return 0;
}
/* 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;
struct termios term;
term = sb->saved_term;
term.c_oflag = 0;
term.c_lflag = ICANON;
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_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);
cfsetospeed(&term, B9600);
if(tcsetattr(sb->fd, TCSAFLUSH, &term) == -1) {
perror("sball_open: tcsetattr");
return -1;
}
tcflush(sb->fd, TCIOFLUSH);
mstat = sb->saved_mstat | TIOCM_DTR | TIOCM_RTS;
ioctl(sb->fd, TIOCMGET, &mstat);
return 0;
}
static void stty_save(struct sball *sb)
{
tcgetattr(sb->fd, &sb->saved_term);
ioctl(sb->fd, TIOCMGET, &sb->saved_mstat);
}
static void stty_restore(struct sball *sb)
{
tcsetattr(sb->fd, TCSAFLUSH, &sb->saved_term);
tcflush(sb->fd, TCIOFLUSH);
ioctl(sb->fd, TIOCMSET, &sb->saved_mstat);
}
static int proc_input(struct sball *sb)
{
int sz;
char *bptr = sb->buf;
char *start = sb->buf;
char *end = sb->buf + sb->len;
/* see if we have a CR in the buffer */
while(bptr < end) {
if(*bptr == '\r') {
*bptr = 0;
sb->parse(sb, *start, start + 1, bptr - start - 1);
start = ++bptr;
} else {
bptr++;
}
}
sz = start - sb->buf;
if(sz > 0) {
memmove(sb->buf, start, sz);
sb->len -= sz;
}
return 0;
}
static int mag_parsepkt(struct sball *sb, int id, char *data, int len)
{
int i, prev, motion_pending = 0;
unsigned int prev_key;
/*printf("magellan packet: %c - %s (%d bytes)\n", (char)id, data, len);*/
switch(id) {
case 'd':
if(len != 24) {
fprintf(stderr, "magellan: invalid data packet, expected 24 bytes, got: %d\n", len);
return -1;
}
for(i=0; i<6; i++) {
prev = sb->mot[i];
sb->mot[i] = ((((int)data[0] & 0xf) << 12) | (((int)data[1] & 0xf) << 8) |
(((int)data[2] & 0xf) << 4) | (data[3] & 0xf)) - 0x8000;
data += 4;
if(sb->mot[i] != prev) {
enqueue_motion(sb, i, sb->mot[i]);
motion_pending++;
}
}
if(motion_pending) {
enqueue_motion(sb, -1, 0);
}
break;
case 'k':
if(len < 3) {
fprintf(stderr, "magellan: invalid keyboard pakcet, expected 3 bytes, got: %d\n", len);
return -1;
}
prev_key = sb->keystate;
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;
}
if(sb->keystate != prev_key) {
gen_button_events(sb, prev_key);
}
break;
case 'e':
if(data[0] == 1) {
fprintf(stderr, "magellan error: illegal command: %c%c\n", data[1], data[2]);
} else if(data[0] == 2) {
fprintf(stderr, "magellan error: framing error\n");
} else {
fprintf(stderr, "magellan error: unknown device error\n");
}
return -1;
default:
break;
}
return 0;
}
static int sball_parsepkt(struct sball *sb, int id, char *data, int len)
{
int i, prev, motion_pending = 0;
char c, *rd, *wr;
unsigned int prev_key;
/* decode data packet, replacing escaped values with the correct ones */
rd = wr = data;
while(rd < data + len) {
if((c = *rd++) == '^') {
switch(*rd++) {
case 'Q':
*wr++ = 0x11; /* XON */
break;
case 'S':
*wr++ = 0x13; /* XOFF */
break;
case 'M':
*wr++ = 13; /* CR */
break;
case '^':
*wr++ = '^';
break;
default:
fprintf(stderr, "sball decode: ignoring invalid escape code: %xh\n", (unsigned int)c);
}
} else {
*wr++ = c;
}
}
len = wr - data; /* update the decoded length */
switch(id) {
case 'D':
if(len != 14) {
fprintf(stderr, "sball: invalid data packet, expected 14 bytes, got: %d\n", len);
return -1;
}
#ifndef SBALL_BIG_ENDIAN
rd = data;
for(i=0; i<6; i++) {
rd += 2;
c = rd[0];
rd[0] = rd[1];
rd[1] = c;
}
#endif
for(i=0; i<6; i++) {
char *dest = (char*)(sb->mot + i);
data += 2;
prev = sb->mot[i];
*dest++ = data[0];
*dest++ = data[1];
if(sb->mot[i] != prev) {
enqueue_motion(sb, i, sb->mot[i]);
motion_pending++;
}
}
if(motion_pending) {
enqueue_motion(sb, -1, 0);
}
break;
case 'K':
if(len != 2) {
fprintf(stderr, "sball: invalid key packet, expected 2 bytes, got: %d\n", len);
return -1;
}
if(sb->flags & SB4000) break; /* ignore K packets from spaceball 4000 devices */
prev_key = sb->keystate;
/* data[1] bits 0-3 -> buttons 0,1,2,3
* data[1] bits 4,5 (3003 L/R) -> buttons 0, 1
* 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) << 3)) & sb->keymask;
if(sb->keystate != prev_key) {
gen_button_events(sb, prev_key);
}
break;
case '.':
if(len != 2) {
fprintf(stderr, "sball: invalid sb4k key packet, expected 2 bytes, got: %d\n", len);
return -1;
}
/* spaceball 4000 key packet */
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) {
sb->flags |= FLIPXY;
} else {
sb->flags &= ~FLIPXY;
}
*/
prev_key = sb->keystate;
/* data[1] bits 0-5 -> buttons 0,1,2,3,4,5
* data[1] bit 7 -> button 6
* data[0] bits 0-4 -> buttons 7,8,9,10,11
*/
sb->keystate = (data[1] & 0x3f) | ((data[1] & 0x80) >> 1) | ((data[0] & 0x1f) << 7);
if(sb->keystate != prev_key) {
gen_button_events(sb, prev_key);
}
break;
case 'E':
fprintf(stderr, "sball: error:");
for(i=0; i<len; i++) {
if(isprint((int)data[i])) {
fprintf(stderr, " %c", data[i]);
} else {
fprintf(stderr, " %02xh", (unsigned int)data[i]);
}
}
break;
case 'M': /* ignore MSS responses */
case '?': /* ignore unrecognized command errors */
break;
default:
/* DEBUG */
fprintf(stderr, "sball: got '%c' packet:", (char)id);
for(i=0; i<len; i++) {
fprintf(stderr, " %02x", (unsigned int)data[i]);
}
fputc('\n', stderr);
}
return 0;
}
static int guess_num_buttons(const char *verstr)
{
int major, minor;
const char *s;
if((s = strstr(verstr, "Firmware version"))) { /* spaceball */
/* try to guess based on firmware number */
if(sscanf(s + 17, "%d.%d", &major, &minor) == 2 && major == 2) {
if(minor == 35 || minor == 62 || minor == 63) {
return 2; /* spaceball 3003/3003C */
}
if(minor == 43 || minor == 45) {
return 12; /* spaceball 4000flx/5000flx-a */
}
if(minor == 2 || minor == 13 || minor == 15 || minor == 42) {
/* 2.42 is also used by spaceball 4000flx. we'll guess 2003c for
* now, and change the buttons to 12 first time we get a '.'
* packet. I'll also request a key report during init to make
* sure this happens as soon as possible, before clients have a
* chance to connect.
*/
return 8; /* spaceball 1003/2003/2003c */
}
}
}
if(strstr(verstr, "MAGELLAN")) {
return 9; /* magellan spacemouse */
}
if(strstr(verstr, "SPACEBALL")) {
return 12; /* spaceball 5000 */
}
if(strstr(verstr, "CadMan")) {
return 4;
}
fprintf(stderr, "Can't guess number of buttons, default to 8, report this as a bug!\n");
return 8;
}
static void make_printable(char *buf, int len)
{
int i, c;
char *wr = buf;
for(i=0; i<len; i++) {
c = *buf++;
if(c == '\r') {
*wr++ = '\n';
while(*buf == '\n' || *buf == '\r') buf++;
} else {
*wr++ = c;
}
}
*wr = 0;
}
static int read_timeout(int fd, char *buf, int bufsz, long tm_usec)
{
int res;
long usec, sz = 0;
struct timeval tv0, tv;
fd_set rdset;
if(!buf || bufsz <= 0) return -1;
usec = tm_usec;
gettimeofday(&tv0, 0);
while(sz < bufsz && usec > 0) {
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
FD_ZERO(&rdset);
FD_SET(fd, &rdset);
if((res = select(fd + 1, &rdset, 0, 0, &tv)) > 0 && FD_ISSET(fd, &rdset)) {
sz += read(fd, buf + sz, bufsz - sz);
buf[sz] = 0;
tm_usec = usec = 128000; /* wait 128ms for the rest of the message to appear */
gettimeofday(&tv0, 0);
continue;
}
if(res == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
break;
}
gettimeofday(&tv, 0);
usec = tm_usec - ((tv.tv_sec - tv0.tv_sec) * 1000000 + (tv.tv_usec - tv0.tv_usec));
}
return sz > 0 ? sz : -1;
}
static void enqueue_motion(struct sball *sb, int axis, int val)
{
struct dev_input *inp = sb->evqueue + sb->evq_wr;
sb->evq_wr = (sb->evq_wr + 1) & (EVQUEUE_SZ - 1);
if(axis >= 0) {
inp->type = INP_MOTION;
inp->idx = axis;
inp->val = val;
} else {
inp->type = INP_FLUSH;
}
}
static void gen_button_events(struct sball *sb, unsigned int prev)
{
int i;
unsigned int bit = 1;
unsigned int diff = sb->keystate ^ prev;
struct dev_input *inp;
for(i=0; i<16; i++) {
if(diff & bit) {
inp = sb->evqueue + sb->evq_wr;
sb->evq_wr = (sb->evq_wr + 1) & (EVQUEUE_SZ - 1);
inp->type = INP_BUTTON;
inp->idx = i;
inp->val = sb->keystate & bit ? 1 : 0;
}
bit <<= 1;
}
}

Wyświetl plik

@ -1,28 +0,0 @@
/*
serialmagellan - decoding serial magellan spaceball data.
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERIAL_CONSTANTS_H_
#define SERIAL_CONSTANTS_H_
#define MAXPACKETSIZE 16
#define VERSION_STRING_MAX 512
#define DEVICE_NAME_MAX 64
#define MAXREADSIZE 512
#endif

Wyświetl plik

@ -1,423 +0,0 @@
/*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include "magellan/smag.h"
#include "magellan/smag_comm.h"
#include "magellan/smag_event.h"
#include "magellan/serialconstants.h"
static void gen_disp_events(int *newval);
static void proc_disp_packet(void);
static void gen_button_event(int button, int new_state);
static void read_copy(void);
static void proc_disp_packet(void);
static void proc_bn_k_packet(void);
static void proc_bn_c_packet(void);
static void proc_bn_n_packet(void);
static void proc_bn_q_packet(void);
static void clean_input();
static int dev_fd;
struct input_struct {
char rbuf[MAXREADSIZE];
int rbuf_sz;
char packet_buf[MAXPACKETSIZE];
int packet_buf_pos;
struct smag_event *evhead;
struct smag_event *evtail;
} input;
static int first_byte_parity[16] = {
0xE0, 0xA0, 0xA0, 0x60, 0xA0, 0x60, 0x60, 0xA0,
0x90, 0x50, 0x50, 0x90, 0xD0, 0x90, 0x90, 0x50
};
static int second_byte_parity[64] = {
0x80, 0x40, 0x40, 0x80, 0x40, 0x80, 0x80, 0x40,
0x40, 0x80, 0x80, 0x40, 0x80, 0x40, 0x40, 0x80,
0x40, 0x80, 0x80, 0x40, 0x80, 0x40, 0x40, 0x80,
0x80, 0x40, 0x40, 0x80, 0xC0, 0x80, 0x80, 0x40,
0xC0, 0x80, 0x80, 0x40, 0x80, 0x40, 0x40, 0x80,
0x80, 0x40, 0x40, 0x80, 0x40, 0x80, 0x80, 0x40,
0x80, 0x40, 0x40, 0x80, 0x40, 0x80, 0x80, 0x40,
0x40, 0x80, 0x80, 0x40, 0x80, 0x40, 0x00, 0x80
};
void smag_init_device(int fd)
{
smag_write(fd, "", 0);
smag_write(fd, "\r\rm0", 4);
smag_write(fd, "pAA", 3);
smag_write(fd, "q00", 3); /*default translation and rotation */
smag_write(fd, "nM", 2); /*zero radius. 0-15 defaults to 13 */
smag_write(fd, "z", 1); /*zero device */
smag_write(fd, "c33", 3); /*set translation, rotation on and dominant axis off */
smag_write(fd, "l2\r\0", 4);
smag_write(fd, "\r\r", 2);
smag_write(fd, "l300", 4);
smag_write(fd, "b9", 2); /*these are beeps */
smag_write(fd, "b9", 2);
usleep(SMAG_DELAY_USEC);
tcflush(fd, TCIOFLUSH);
clean_input();
}
static void read_copy(void)
{
int i;
for(i=0; i<input.rbuf_sz; i++) {
if(input.rbuf[i] == '\n' || input.rbuf[i] == '\r') {
input.packet_buf[input.packet_buf_pos] = 0; /* terminate string */
if(input.packet_buf[0] == 'd' && input.packet_buf_pos == 15) {
proc_disp_packet();
} else if(input.packet_buf[0] == 'k' && input.packet_buf_pos == 4) {
proc_bn_k_packet();
} else if(input.packet_buf[0] == 'c' && input.packet_buf_pos == 3) {
proc_bn_c_packet();
} else if(input.packet_buf[0] == 'n' && input.packet_buf_pos == 2) {
proc_bn_n_packet();
} else if(input.packet_buf[0] == 'q' && input.packet_buf_pos == 3) {
proc_bn_q_packet();
} else {
fprintf(stderr, "unknown packet %s\n", input.packet_buf);
}
input.packet_buf_pos = 0;
} else {
input.packet_buf[input.packet_buf_pos] = input.rbuf[i];
input.packet_buf_pos++;
if(input.packet_buf_pos == MAXPACKETSIZE) {
input.packet_buf_pos = 0;
fprintf(stderr, "packet buffer overrun\n");
}
}
}
}
int open_smag(const char *devfile)
{
if((dev_fd = smag_open_device(devfile)) == -1) {
return -1;
}
smag_set_port_magellan(dev_fd);
smag_init_device(dev_fd);
clean_input();
return 0;
}
int close_smag()
{
smag_write(dev_fd, "l000", 4);
close(dev_fd);
return 0;
}
int read_smag(struct dev_input *inp)
{
/*need to return 1 if we fill in inp or 0 if no events */
struct smag_event *ev;
input.rbuf_sz = smag_read(dev_fd, input.rbuf, MAXREADSIZE);
if(input.rbuf_sz > 0) {
read_copy();
}
ev = input.evhead;
if(ev) {
input.evhead = input.evhead->next;
*inp = ev->data;
free_event(ev);
return 1;
}
return 0;
}
int get_fd_smag()
{
return dev_fd;
}
void get_version_string(int fd, char *buf, int sz)
{
int bytesrd;
char tmpbuf[MAXREADSIZE];
smag_write(fd, "\r\rm0", 4);
smag_write(fd, "", 0);
smag_write(fd, "\r\rm0", 4);
smag_write(fd, "c03", 3);
smag_write(fd, "z", 1);
smag_write(fd, "Z", 1);
smag_write(fd, "l000", 4);
usleep(SMAG_DELAY_USEC);
tcflush(fd, TCIOFLUSH);
clean_input();
smag_write(fd, "vQ", 2);
bytesrd = smag_read(fd, tmpbuf, MAXREADSIZE);
if(bytesrd > 0 && bytesrd < sz) {
strcpy(buf, tmpbuf);
}
clean_input();
}
static void gen_disp_events(int *newval)
{
int i, pending;
static int oldval[6] = {0, 0, 0, 0, 0, 0};
struct smag_event *newev;
pending = 0;
for(i=0; i<6; i++) {
if(newval[i] == oldval[i]) {
continue;
}
oldval[i] = newval[i];
newev = alloc_event();
if(newev) {
newev->data.type = INP_MOTION;
newev->data.idx = i;
newev->data.val = newval[i];
newev->next = 0;
if(input.evhead) {
input.evtail->next = newev;
input.evtail = newev;
} else
input.evhead = input.evtail = newev;
pending = 1;
}
}
if(pending) {
newev = alloc_event();
if(newev) {
newev->data.type = INP_FLUSH;
newev->next = 0;
}
if(input.evhead) {
input.evtail->next = newev;
input.evtail = newev;
} else {
input.evhead = input.evtail = newev;
}
}
}
static void proc_disp_packet(void)
{
int i, last_bytes, offset, values[6];
short int accum_last, number, accum_last_adj;
accum_last = offset = 0;
for(i=1; i<13; i+=2) {
/*first byte check */
unsigned char low, up;
low = input.packet_buf[i] & 0x0F;
up = input.packet_buf[i] & 0xF0;
if(up != first_byte_parity[low]) {
fprintf(stderr, "bad first packet\n");
return;
}
/*second byte check */
low = input.packet_buf[i + 1] & 0x3F;
up = input.packet_buf[i + 1] & 0xC0;
if(up != second_byte_parity[low]) {
fprintf(stderr, "bad second packet\n");
return;
}
number = (short int)((input.packet_buf[i] << 6 & 0x03C0) | (input.packet_buf[i + 1] & 0x3F));
if(number > 512) {
number -= 1024;
}
accum_last += number;
if(number < 0) {
offset += ((int)(number + 1) / 64) - 1;
} else {
offset += (int)number / 64;
}
/*printf("%8i ", number); */
values[(i + 1) / 2 - 1] = number;
}
/*last byte of packet is a sum of 6 numbers and a factor of 64. use as a packet check.
still not sure what the second to last byte is for. */
accum_last_adj = accum_last & 0x003F;
accum_last_adj += offset;
if(accum_last_adj < 0) {
accum_last_adj += 64;
}
if(accum_last_adj > 63) {
accum_last_adj -= 64;
}
last_bytes = (short int)(input.packet_buf[14] & 0x3F);
if(accum_last_adj != last_bytes) {
printf(" bad packet\n");
return;
}
gen_disp_events(values);
return;
}
static void gen_button_event(int button, int new_state)
{
struct smag_event *newev = alloc_event();
if(!newev) {
return;
}
newev->data.type = INP_BUTTON;
newev->data.idx = button;
newev->data.val = new_state;
newev->next = 0;
if(input.evhead) {
input.evtail->next = newev;
input.evtail = newev;
} else {
input.evhead = input.evtail = newev;
}
}
static void proc_bn_k_packet(void)
{
static char old_state[5] = { 0, 0, 0, 0, 0 };
if(input.packet_buf[1] != old_state[1]) {
if((input.packet_buf[1] & 0x01) != (old_state[1] & 0x01)) {
gen_button_event(0, input.packet_buf[1] & 0x01);
}
if((input.packet_buf[1] & 0x02) != (old_state[1] & 0x02)) {
gen_button_event(1, input.packet_buf[1] & 0x02);
}
if((input.packet_buf[1] & 0x04) != (old_state[1] & 0x04)) {
gen_button_event(2, input.packet_buf[1] & 0x04);
}
if((input.packet_buf[1] & 0x08) != (old_state[1] & 0x08)) {
gen_button_event(3, input.packet_buf[1] & 0x08);
}
}
if(input.packet_buf[2] != old_state[2]) {
if((input.packet_buf[2] & 0x01) != (old_state[2] & 0x01)) {
gen_button_event(4, input.packet_buf[2] & 0x01);
}
if((input.packet_buf[2] & 0x02) != (old_state[2] & 0x02)) {
gen_button_event(5, input.packet_buf[2] & 0x02);
}
if((input.packet_buf[2] & 0x04) != (old_state[2] & 0x04)) {
gen_button_event(6, input.packet_buf[2] & 0x04);
}
if((input.packet_buf[2] & 0x08) != (old_state[2] & 0x08)) {
gen_button_event(7, input.packet_buf[2] & 0x08);
}
}
/*skipping asterisk button. asterisk function come in through other packets. */
/*magellan plus has left and right (10, 11) buttons not magellan classic */
/*not sure if we need to filter out lower button events for magellan classic */
if(input.packet_buf[3] != old_state[3]) {
/*
if (input.packet_buf[3] & 0x01)
printf("button asterisk ");
*/
if((input.packet_buf[3] & 0x02) != (old_state[3] & 0x02)) {
gen_button_event(8, input.packet_buf[3] & 0x02); /*left button */
}
if((input.packet_buf[3] & 0x04) != (old_state[3] & 0x04)) {
gen_button_event(9, input.packet_buf[3] & 0x04); /*right button */
}
}
strcpy(old_state, input.packet_buf);
}
static void proc_bn_c_packet(void)
{
/*these are implemented at device and these signals are to keep the driver in sync */
if(input.packet_buf[1] & 0x02) {
printf("translation is on ");
} else {
printf("translation is off ");
}
if(input.packet_buf[1] & 0x01) {
printf("rotation is on ");
} else {
printf("rotation is off ");
}
if(input.packet_buf[1] & 0x04) {
printf("dominant axis is on ");
} else {
printf("dominant axis is off ");
}
printf("\n");
/*printf("%s\n", input.packet_buf); */
}
static void proc_bn_n_packet(void)
{
int radius;
radius = (int)input.packet_buf[1] & 0x0F;
printf("zero radius set to %i\n", radius);
}
static void proc_bn_q_packet(void)
{
/* this has no effect on the device numbers. Driver is to implement any scale of numbers */
int rotation, translation;
rotation = (int)input.packet_buf[1] & 0x07;
translation = (int)input.packet_buf[2] & 0x07;
printf("rotation = %i translation = %i\n", rotation, translation);
}
static void clean_input(void)
{
memset(input.rbuf, 0x00, MAXREADSIZE);
input.rbuf_sz = 0;
memset(input.packet_buf, 0x00, MAXPACKETSIZE);
input.packet_buf_pos = 0;
}

Wyświetl plik

@ -1,31 +0,0 @@
/*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#include "event.h"
int open_smag(const char *devfile);
int close_smag();
int read_smag(struct dev_input *inp);
int get_fd_smag();
void get_version_string(int fd, char *buf, int sz);
void smag_init_device(int fd);
void clearInput(void);
void readCopy(void);

Wyświetl plik

@ -1,153 +0,0 @@
/*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include "magellan/smag_comm.h"
int smag_open_device(const char *fname)
{
return open(fname, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
}
int smag_set_port_spaceball(int fd)
{
int status;
struct termios term;
if(tcgetattr(fd, &term) == -1) {
perror("error tcgetattr");
return -1;
}
term.c_cflag = CREAD | CS8 | CLOCAL | HUPCL;
term.c_iflag |= IGNBRK | IGNPAR;
term.c_oflag = 0;
term.c_lflag = 0;
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
cfsetispeed(&term, 9600);
cfsetospeed(&term, 9600);
if(tcsetattr(fd, TCSANOW, &term) == -1) {
perror("error tcsetattr");
return -1;
}
if(ioctl(fd, TIOCMGET, &status) == -1) {
perror("error TIOMCGET");
return -1;
}
status |= TIOCM_DTR;
status |= TIOCM_RTS;
if(ioctl(fd, TIOCMSET, &status) == -1) {
perror("error TIOCMSET");
return -1;
}
return 0;
}
int smag_set_port_magellan(int fd)
{
int status;
struct termios term;
if(tcgetattr(fd, &term) == -1) {
perror("error tcgetattr");
return -1;
}
term.c_cflag = CS8 | CSTOPB | CRTSCTS | CREAD | HUPCL | CLOCAL;
term.c_iflag |= IGNBRK | IGNPAR;
term.c_oflag = 0;
term.c_lflag = 0;
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
cfsetispeed(&term, 9600);
cfsetospeed(&term, 9600);
if(tcsetattr(fd, TCSANOW, &term) == -1) {
perror("error tcsetattr");
return -1;
}
if(ioctl(fd, TIOCMGET, &status) == -1) {
perror("error TIOCMGET");
return -1;
}
status |= TIOCM_DTR;
status |= TIOCM_RTS;
if(ioctl(fd, TIOCMSET, &status) == -1) {
perror("error TIOCMSET");
return -1;
}
return 0;
}
#define LONG_DELAY 150000
void smag_write(int fd, const char *buf, int sz)
{
int i;
for(i=0; i<sz; i++) {
write(fd, buf + i, 1);
usleep(SMAG_DELAY_USEC);
}
write(fd, "\r", 1);
usleep(LONG_DELAY);
}
int smag_read(int fd, char *buf, int sz)
{
int bytesrd = read(fd, buf, sz - 1);
if(bytesrd < 1) {
return 0;
}
buf[bytesrd] = 0;
return bytesrd;
}
int smag_wait_read(int fd, char *buf, int sz, int wait_sec)
{
int res;
fd_set set;
struct timeval tv;
FD_ZERO(&set);
FD_SET(fd, &set);
tv.tv_sec = wait_sec;
tv.tv_usec = 0;
do {
res = select(fd + 1, &set, 0, 0, &tv);
} while(res == -1 && errno == EINTR);
return res == -1 ? -1 : smag_read(fd, buf, sz);
}

Wyświetl plik

@ -1,32 +0,0 @@
/*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef SMAG_COMM_H_
#define SMAG_COMM_H_
#define SMAG_DELAY_USEC 2000
int smag_open_device(const char *fname);
int smag_set_port_spaceball(int fd);
int smag_set_port_magellan(int fd);
void smag_write(int fd, const char *buf, int sz);
int smag_read(int fd, char *buf, int sz);
int smag_wait_read(int fd, char *buf, int sz, int wait_sec);
#endif

Wyświetl plik

@ -1,104 +0,0 @@
/*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "magellan/smag.h"
#include "magellan/smag_detect.h"
#include "magellan/serialconstants.h"
#include "magellan/smag_comm.h"
/*swap out /r for /n for string printing*/
static void make_printable(char *str)
{
while(*str) {
if(*str == '\r') {
*str = '\n';
}
str++;
}
}
int smag_detect(const char *fname, char *buf, int sz)
{
int fd, bytesrd, pos;
char tmpbuf[MAXREADSIZE];
if((fd = smag_open_device(fname)) == -1) {
fprintf(stderr, "%s: couldn't open device file: %s\n", __func__, fname);
return -1;
}
if(smag_set_port_spaceball(fd) == -1) {
close(fd);
fprintf(stderr, "%s: couldn't setup port\n", __func__);
return -1;
}
/* first look for spaceball. should have data after open and port setup.
* I was hoping that using the select inside serialWaitRead would allow me
* to get rid of the following sleep. Removing the sleep causes port to freeze.
*/
sleep(1);
bytesrd = 0;
pos = 0;
while((pos = smag_wait_read(fd, tmpbuf + bytesrd, MAXREADSIZE - bytesrd, 1)) > 0) {
bytesrd += pos;
}
if(bytesrd > 0) {
smag_write(fd, "hm", 2);
while((pos = smag_wait_read(fd, tmpbuf + bytesrd, MAXREADSIZE - bytesrd, 1)) > 0) {
bytesrd += pos;
}
smag_write(fd, "\"", 1);
while((pos = smag_wait_read(fd, tmpbuf + bytesrd, MAXREADSIZE - bytesrd, 1)) > 0) {
bytesrd += pos;
}
make_printable(tmpbuf);
strncpy(buf, tmpbuf, sz);
if(bytesrd < sz) {
fprintf(stderr, "%s: buffer overrun\n", __func__);
return -1;
}
}
/*now if we are here we don't have a spaceball and now we need to check for a magellan */
close(fd);
pos = 0;
if((fd = smag_open_device(fname)) == -1) {
return -1;
}
if(smag_set_port_magellan(fd) == -1) {
return -1;
}
sleep(1);
smag_init_device(fd);
get_version_string(fd, tmpbuf, MAXREADSIZE);
make_printable(tmpbuf);
strncpy(buf, tmpbuf, sz);
close(fd);
return 0;
}

Wyświetl plik

@ -1,25 +0,0 @@
/*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef SMAG_DETECT_H_
#define SMAG_DETECT_H_
int smag_detect(const char *fname, char *buf, int sz);
#endif /* SMAG_DETECT_H_ */

Wyświetl plik

@ -1,49 +0,0 @@
/*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas <nuclear@member.fsf.org>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "smag_event.h"
static int evpool_size;
static struct smag_event *ev_free_list;
struct smag_event *alloc_event(void)
{
struct smag_event *ev;
if(ev_free_list) {
ev = ev_free_list;
ev_free_list = ev->next;
} else {
if((ev = malloc(sizeof *ev))) {
evpool_size++;
}
}
return ev;
}
void free_event(struct smag_event *ev)
{
if(evpool_size > 512) {
free(ev);
evpool_size--;
} else {
ev->next = ev_free_list;
ev_free_list = ev;
}
}

Wyświetl plik

@ -1,33 +0,0 @@
/*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas <nuclear@member.fsf.org>
Copyright (C) 2010 Thomas Anderson <ta@nextgenengineering.com>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef SMAG_EVENT_H_
#define SMAG_EVENT_H_
#include "event.h"
struct smag_event {
struct dev_input data;
struct smag_event *next;
};
struct smag_event *alloc_event(void);
void free_event(struct smag_event *ev);
#endif /* SMAG_EVENT_H_ */

Wyświetl plik

@ -1,747 +0,0 @@
/*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas <nuclear@member.fsf.org>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
This file incorporates work covered by the following copyright and
permission notice:
Copyright 1997-2001 John E. Stone (j.stone@acm.org)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#define _POSIX_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "sball.h"
#include "sballserial.h"
struct event {
struct dev_input data;
struct event *next;
};
static struct event *ev_free_list;
static int evpool_size;
static struct event *alloc_event(void);
static void free_event(struct event *ev);
typedef struct {
SBallCommHandle commhandle;
unsigned char buf[256];
char resetstring[256];
int bufpos; /* current char position in packet buffer */
int packtype; /* what kind of packet is it */
int packlen; /* how many bytes do we ultimately expect? */
int escapedchar; /* if set, we're processing an escape sequence */
int erroroccured; /* if set, we've received an error packet or packets */
int resetoccured; /* if set, ball was reset, so have to reinitialize it */
int spaceball4000; /* if set, its a Spaceball 4000 */
int leftymode4000; /* if set, Spaceball 4000 in "lefty" orientation */
int trans[3]; /* last translational data received */
int rot[3]; /* last rotational data received */
int buttons; /* current button status */
int timer; /* time since last packet was received */
int usenullregion; /* software-implemented null region flag */
int nulltrans[3]; /* translational null region values */
int nullrot[3]; /* rotational null region values */
/* event list added for spacenavd integration */
struct event *evhead, *evtail;
} sballhandle;
static void generate_motion_events(sballhandle *handle, int *prev_val, int *new_val, int timer);
static void generate_button_events(sballhandle *handle, int prevstate, int newstate);
/* Spaceball 1003/2003 recommended initialization string. */
/* Newer documentation suggests eliminating several of these */
/* settings during initialization, leaving them at factory values. */
static char *initstring = "CB\rNT\rFTp\rFRp\rP@r@r\rMSSV\rZ\rBcCcC\r";
/* Reset spaceball and ideally determine model */
static void sball_hwreset(sballhandle * handle)
{
/* Reset some state variables back to zero */
handle->spaceball4000 = 0; /* re-determine which type it is */
handle->leftymode4000 = 0; /* re-determine if its in lefty mode */
if(!handle->resetoccured) {
#if defined(DEBUG)
printf("Sending reset command to spaceball...\n");
#endif
handle->resetoccured = 1;
sball_comm_write(handle->commhandle, "@\r"); /* force reset */
}
#if 0
/* give the spaceball time to reset itself */
sleep(2);
#endif
#if defined(DEBUG)
printf("Sending initialization sequence to spaceball...\n");
#endif
sball_comm_write(handle->commhandle, initstring); /* do remaining init */
}
SBallHandle sball_open(const char *sballname)
{
sballhandle *handle;
if(sballname == NULL)
return NULL;
handle = (sballhandle *) malloc(sizeof(sballhandle));
if(handle == NULL)
return NULL;
/* clear all values in sballhandle to 0 */
memset(handle, 0, sizeof(sballhandle));
handle->packlen = 1;
handle->resetoccured = 0;
if(sball_comm_open(sballname, &handle->commhandle) == -1) {
free(handle);
return NULL;
}
sball_hwreset(handle);
return handle; /* successfull open */
}
int sball_close(SBallHandle voidhandle)
{
sballhandle *handle = voidhandle;
if(handle == NULL)
return -1;
sball_comm_close(&handle->commhandle);
free(handle);
return 0; /* successfull close */
}
static int sball_update(SBallHandle voidhandle)
{
int i, num, packs;
unsigned char rawbuf[1024];
sballhandle *handle = voidhandle;
if(handle == NULL)
return -1;
packs = 0; /* no packs received yet */
num = sball_comm_read(handle->commhandle, (char *)rawbuf, 1023);
if(num > 0) {
for(i = 0; i < num; i++) {
/* process potentially occuring escaped character sequences */
if(rawbuf[i] == '^') {
if(!handle->escapedchar) {
handle->escapedchar = 1;
continue; /* eat the escape character from buffer */
}
}
if(handle->escapedchar) {
handle->escapedchar = 0;
switch(rawbuf[i]) {
case '^': /* leave char in buffer unchanged */
break;
case 'Q':
case 'S':
case 'M':
rawbuf[i] &= 0x1F; /* convert character to unescaped form */
break;
default:
#if defined(DEBUG)
printf("\nGot a bad escape sequence! 0x%02x", rawbuf[i]);
if(isprint(rawbuf[i]))
printf(" (%c)", rawbuf[i]);
else
printf(" (unprintable)");
printf("\n");
#endif
break;
}
}
/* figure out what kind of packet we received */
if(handle->bufpos == 0) {
switch(rawbuf[i]) {
case 'D': /* Displacement packet */
handle->packtype = 'D';
handle->packlen = 16; /* D packets are 15 bytes long */
break;
case 'K': /* Button/Key packet */
handle->packtype = 'K';
handle->packlen = 4; /* K packets are 3 bytes long */
break;
case '.': /* Spaceball 4000 FLX "advanced" button press event */
handle->packtype = '.';
handle->packlen = 4; /* . packets are 3 bytes long */
break;
case 'C': /* Communications mode packet */
handle->packtype = 'C';
handle->packlen = 4;
break;
case 'F': /* Spaceball sensitization mode packet */
handle->packtype = 'F';
handle->packlen = 4;
break;
case 'M': /* Movement mode packet */
handle->packtype = 'M';
handle->packlen = 5;
break;
case 'N': /* Null region packet */
handle->packtype = 'N';
handle->packlen = 3;
break;
case 'P': /* Update rate packet */
handle->packtype = 'P';
handle->packlen = 6;
break;
case '\v': /* XON at poweron */
handle->packtype = '\v';
handle->packlen = 1;
break;
case '\n': /* carriage return at poweron */
case '\r': /* carriage return at poweron */
handle->packtype = '\r';
handle->packlen = 1;
break;
case '@': /* Spaceball Hard/Soft Reset packet */
handle->resetoccured = 1;
handle->packtype = '@';
handle->packlen = 62; /* Resets aren't longer than 62 chars */
break;
case 'E': /* Error packet */
handle->packtype = 'E';
handle->packlen = 8; /* E packets are up to 7 bytes long */
break;
case 'Z': /* Zero packet (Spaceball 2003/3003/4000 FLX) */
handle->packtype = 'Z';
handle->packlen = 14; /* Z packets are hardware dependent */
break;
default: /* Unknown packet! */
#if defined(DEBUG)
printf("\nUnknown packet (1): 0x%02x \n ", rawbuf[i]);
printf(" char: ");
if(isprint(rawbuf[i]))
printf("%c", rawbuf[i]);
else
printf(" (unprintable)");
printf("\n");
#endif
continue;
}
}
handle->buf[handle->bufpos] = rawbuf[i];
handle->bufpos++;
/* Reset packet processing */
if(handle->packtype == '@') {
if(rawbuf[i] != '\r')
continue;
else
handle->packlen = handle->bufpos;
}
/* Error packet processing */
if(handle->packtype == 'E') {
if(rawbuf[i] != '\r')
continue;
else
handle->packlen = handle->bufpos;
} else if(handle->bufpos != handle->packlen)
continue;
switch(handle->packtype) {
case 'D': /* ball displacement event */
/* modified by John Tsiombikas for spacenavd integration */
{
unsigned int tx, ty, tz, rx, ry, rz;
int i, prev_val[6], new_val[6];
/* number of 1/16ths of milliseconds since last */
/* ball displacement packet */
handle->timer = ((handle->buf[1]) << 8) | (handle->buf[2]);
tx = ((handle->buf[3]) << 8) | ((handle->buf[4]));
ty = ((handle->buf[5]) << 8) | ((handle->buf[6]));
tz = ((handle->buf[7]) << 8) | ((handle->buf[8]));
rx = ((handle->buf[9]) << 8) | ((handle->buf[10]));
ry = ((handle->buf[11]) << 8) | ((handle->buf[12]));
rz = ((handle->buf[13]) << 8) | ((handle->buf[14]));
for(i=0; i<3; i++) {
prev_val[i] = handle->trans[i];
prev_val[i + 3] = handle->rot[i];
}
new_val[0] = (((int)tx) << 16) >> 16;
new_val[1] = (((int)ty) << 16) >> 16;
new_val[2] = (((int)tz) << 16) >> 16;
new_val[3] = (((int)rx) << 16) >> 16;
new_val[4] = (((int)ry) << 16) >> 16;
new_val[5] = (((int)rz) << 16) >> 16;
generate_motion_events(handle, prev_val, new_val, handle->timer);
for(i=0; i<3; i++) {
handle->trans[i] = new_val[i];
handle->rot[i] = new_val[i + 3];
}
}
break;
case 'K': /* button press event */
/* modified by John Tsiombikas for spacenavd integration */
{
int newstate;
/* Spaceball 2003A, 2003B, 2003 FLX, 3003 FLX, 4000 FLX */
/* button packet. (4000 only for backwards compatibility) */
/* The lowest 5 bits of the first byte are buttons 5-9 */
/* Button '8' on a Spaceball 2003 is the rezero button */
/* The lowest 4 bits of the second byte are buttons 1-4 */
/* For Spaceball 2003, we'll map the buttons 1-7 normally */
/* skip 8, as its a hardware "rezero button" on that device */
/* and call the "pick" button "8". */
/* On the Spaceball 3003, the "right" button also triggers */
/* the "pick" bit. We OR the 2003/3003 rezero bits together */
/* if we have found a Spaceball 4000, then we ignore the 'K' */
/* packets entirely, and only use the '.' packets. */
if(handle->spaceball4000)
break;
newstate = ((handle->buf[1] & 0x10) << 3) | /* 2003 pick button is "8" */
((handle->buf[1] & 0x20) << 9) | /* 3003 rezero button */
((handle->buf[1] & 0x08) << 11) | /* 2003 rezero button */
((handle->buf[1] & 0x07) << 4) | /* 5,6,7 (2003/4000) */
((handle->buf[2] & 0x30) << 8) | /* 3003 Left/Right buttons */
((handle->buf[2] & 0x0F)); /* 1,2,3,4 (2003/4000) */
generate_button_events(handle, handle->buttons, newstate);
handle->buttons = newstate;
}
break;
case '.': /* button press event (4000) */
/* modified by John Tsiombikas for spacenavd integration */
{
int newstate;
/* Spaceball 4000 FLX "expanded" button packet, with 12 buttons */
/* extra packet validity check, since we use this packet type */
/* to override the 'K' button packets, and determine if its a */
/* Spaceball 4000 or not... */
if(handle->buf[3] != '\r') {
break; /* if not terminated with a '\r', probably garbage */
}
/* if we got a valid '.' packet, this must be a Spaceball 4000 */
#if defined(DEBUG)
if(!handle->spaceball4000)
printf("\nDetected a Spaceball 4000 FLX\n");
#endif
handle->spaceball4000 = 1; /* Must be talking to a Spaceball 4000 */
/* Spaceball 4000 series "expanded" button press event */
/* includes data for 12 buttons, and left/right orientation */
newstate = (((~handle->buf[1]) & 0x20) << 10) | /* "left handed" mode */
((handle->buf[1] & 0x1F) << 7) | /* 8,9,10,11,12 */
((handle->buf[2] & 0x3F)) | /* 1,2,3,4,5,6 (4000) */
((handle->buf[2] & 0x80) >> 1); /* 7 (4000) */
generate_button_events(handle, handle->buttons, newstate);
handle->buttons = newstate;
#if defined(DEBUG)
if(handle->leftymode4000 != ((handle->buf[1] & 0x20) == 0))
printf("\nSpaceball 4000 mode changed to: %s\n",
(((handle->buf[1] & 0x20) ==
0) ? "left handed" : "right handed"));
#endif
/* set "lefty" orientation mode if "lefty bit" is _clear_ */
if((handle->buf[1] & 0x20) == 0)
handle->leftymode4000 = 1; /* left handed mode */
else
handle->leftymode4000 = 0; /* right handed mode */
}
break;
case 'C': /* Communications mode packet */
case 'F': /* Spaceball sensitization packet */
case 'P': /* Spaceball update rate packet */
case 'M': /* Spaceball movement mode packet */
case 'N': /* Null region packet */
case '\r': /* carriage return at poweron */
case '\v': /* XON at poweron */
/* eat and ignore these packets */
break;
case '@': /* Reset packet */
#ifdef DEBUG
printf("Spaceball reset: ");
for(j = 0; j < handle->packlen; j++) {
if(isprint(handle->buf[j]))
printf("%c", handle->buf[j]);
}
printf("\n");
#endif
/* if we get a reset packet, we have to re-initialize */
/* the device, and assume that its completely schizophrenic */
/* at this moment, we must reset it again at this point */
handle->resetoccured = 1;
sball_hwreset(handle);
break;
case 'E': /* Error packet, hardware/software problem */
handle->erroroccured++;
#ifdef DEBUG
printf("\nSpaceball Error!! ");
printf("Error code: ");
for(j = 0; j < handle->packlen; j++) {
printf(" 0x%02x ", handle->buf[j]);
}
printf("\n");
#endif
break;
case 'Z': /* Zero packet (Spaceball 2003/3003/4000 FLX) */
/* We just ignore these... */
break;
default:
#ifdef DEBUG
printf("Unknown packet (2): 0x%02x\n", handle->packtype);
printf(" char: ");
if(isprint(handle->packtype))
printf("%c", handle->packtype);
else
printf(" (unprintable)");
printf("\n");
#endif
break;
}
/* reset */
handle->bufpos = 0;
handle->packtype = 0;
handle->packlen = 1;
packs++;
}
}
return packs;
}
int sball_rezero(SBallHandle voidhandle)
{
sballhandle *handle = voidhandle;
char outbuf[200];
if(handle == NULL)
return -1;
sprintf(outbuf, "\rZ\r");
sball_comm_write(handle->commhandle, outbuf);
return 0;
}
int sball_init(SBallHandle voidhandle)
{
sballhandle *handle = voidhandle;
/*char outbuf[200]; */
if(handle == NULL)
return -1;
sball_update(handle);
#if 0
sprintf(outbuf, "\r");
sball_update(handle);
sball_comm_write(handle->commhandle, outbuf);
sball_rezero(handle);
#endif
return 0;
}
void sball_set_nullregion(SBallHandle voidhandle,
int nulltx, int nullty, int nulltz, int nullrx, int nullry, int nullrz)
{
sballhandle *handle = voidhandle;
handle->nulltrans[0] = abs(nulltx);
handle->nulltrans[1] = abs(nullty);
handle->nulltrans[2] = abs(nulltz);
handle->nullrot[0] = abs(nullrx);
handle->nullrot[1] = abs(nullry);
handle->nullrot[2] = abs(nullrz);
handle->usenullregion = 1;
}
static int nullregion(int null, int val)
{
if(abs(val) > null) {
return ((val > 0) ? (val - null) : (val + null));
}
return 0;
}
static void sball_do_nullregion(SBallHandle voidhandle)
{
sballhandle *handle = voidhandle;
handle->trans[0] = nullregion(handle->nulltrans[0], handle->trans[0]);
handle->trans[1] = nullregion(handle->nulltrans[1], handle->trans[1]);
handle->trans[2] = nullregion(handle->nulltrans[2], handle->trans[2]);
handle->rot[0] = nullregion(handle->nullrot[0], handle->rot[0]);
handle->rot[1] = nullregion(handle->nullrot[1], handle->rot[1]);
handle->rot[2] = nullregion(handle->nullrot[2], handle->rot[2]);
}
int sball_getstatus(SBallHandle voidhandle, int *tx, int *ty, int *tz,
int *rx, int *ry, int *rz, int *buttons)
{
sballhandle *handle = voidhandle;
int events;
if(handle == NULL)
return -1;
events = sball_update(handle); /* check for new data */
/* perform null region processing */
if(handle->usenullregion)
sball_do_nullregion(voidhandle);
if(tx != NULL)
*tx = handle->trans[0];
if(ty != NULL)
*ty = handle->trans[1];
if(tz != NULL)
*tz = handle->trans[2];
if(rx != NULL)
*rx = handle->rot[0];
if(ry != NULL)
*ry = handle->rot[1];
if(rz != NULL)
*rz = handle->rot[2];
if(buttons != NULL)
*buttons = handle->buttons;
/* no timer code yet */
return events;
}
/* everything from this point to the end of file was added by
* John Tsiombikas for spacenavd integration.
*/
int sball_get_input(SBallHandle voidhandle, struct dev_input *inp)
{
struct event *ev;
sballhandle *handle = voidhandle;
/* read pending packets from the device and append them in the event list */
sball_update(handle);
/* if there are any events in the list, grab the first and return it */
if((ev = handle->evhead)) {
handle->evhead = handle->evhead->next;
*inp = ev->data;
free_event(ev);
return 1;
}
return 0;
}
int sball_get_fd(SBallHandle voidhandle)
{
sballhandle *sball = voidhandle;
return sball_comm_fd(sball->commhandle);
}
static struct event *alloc_event(void)
{
struct event *ev;
if(ev_free_list) {
ev = ev_free_list;
ev_free_list = ev->next;
} else {
if((ev = malloc(sizeof *ev))) {
evpool_size++;
}
}
return ev;
}
static void free_event(struct event *ev)
{
if(evpool_size > 512) {
free(ev);
evpool_size--;
} else {
ev->next = ev_free_list;
ev_free_list = ev;
}
}
static void generate_motion_events(sballhandle *handle, int *prev_val, int *new_val, int timer)
{
int i, pending = 0;
struct event *ev;
for(i=0; i<6; i++) {
if(prev_val[i] == new_val[i]) {
continue;
}
if((ev = alloc_event())) {
ev->data.type = INP_MOTION;
ev->data.idx = i;
ev->data.val = new_val[i];
ev->next = 0;
if(handle->evhead) {
handle->evtail->next = ev;
handle->evtail = ev;
} else {
handle->evhead = handle->evtail = ev;
}
pending = 1;
}
}
if(pending) {
if((ev = alloc_event())) {
ev->data.type = INP_FLUSH;
ev->next = 0;
}
if(handle->evhead) {
handle->evtail->next = ev;
handle->evtail = ev;
} else {
handle->evhead = handle->evtail = ev;
}
}
}
static void generate_button_events(sballhandle *handle, int prevstate, int newstate)
{
int i;
for(i=0; i<16; i++) {
int newbit = (newstate >> i) & 1;
if(newbit != ((prevstate >> i) & 1)) {
/* state changed, trigger event */
struct event *ev = alloc_event();
if(!ev) continue;
ev->data.type = INP_BUTTON;
ev->data.idx = i;
ev->data.val = newbit;
ev->next = 0;
if(handle->evhead) {
handle->evtail->next = ev;
handle->evtail = ev;
} else {
handle->evhead = handle->evtail = ev;
}
}
}
}

Wyświetl plik

@ -1,177 +0,0 @@
/*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas <nuclear@member.fsf.org>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
This file incorporates work covered by the following copyright and
permission notice:
Copyright 1997-2001 John E. Stone (j.stone@acm.org)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#if !defined(SBALL_H)
#define SBALL_H 1
#include "event.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *SBallHandle; /* Handle type, used by all sball API functions */
/* Spaceball Button bit-masks */
#define SBALL_BUTTON_1 1 /* bit 0 */
#define SBALL_BUTTON_2 2 /* bit 1 */
#define SBALL_BUTTON_3 4 /* bit 2 */
#define SBALL_BUTTON_4 8 /* bit 3 */
#define SBALL_BUTTON_5 16 /* bit 4 */
#define SBALL_BUTTON_6 32 /* bit 5 */
#define SBALL_BUTTON_7 64 /* bit 6 */
#define SBALL_BUTTON_8 128 /* bit 7 */
#define SBALL_BUTTON_9 256 /* bit 8 */
#define SBALL_BUTTON_10 512 /* bit 9 */
#define SBALL_BUTTON_11 1024 /* bit 10 */
#define SBALL_BUTTON_12 2048 /* bit 11 */
/* The Spaceball 3003 and 3003 FLX only have "left" and "right" buttons */
#define SBALL_BUTTON_LEFT 4096 /* bit 12 */
#define SBALL_BUTTON_RIGHT 8192 /* bit 13 */
/* The Spaceball 2003A and 2003B have a dedicated pick button on the ball */
/* The Spaceball 2003 FLX uses "button 9" as the pick button. */
/* All of them return this as "button 9" in their encoded button data */
#define SBALL_BUTTON_PICK 128 /* bit 8 */
/* On Spaceball 2003A and 2003B, the Rezero is "button 8" on the device */
/* On the newer devices, there are dedicated rezero buttons */
#define SBALL_BUTTON_REZERO 16384 /* bit 14 */
/* The Spaceball 4000 FLX has a configurable palm rest which can be in */
/* either "left" or "right" handed mode. When it is configured in "left" */
/* handed mode, the "lefty" bit is set, and coordinate systems need to be */
/* inverted on one axis. */
#define SBALL_MODE_LEFTY 32768 /* bit 15 */
/*
* sball_open()
* Open a named serial port which a Spaceball is attached to.
* Returns a handle which is used by all other sball API functions.
* If the serial port open fails, or the sball does not pass initialization
* tests, then a NULL is returned as the handle.
*/
SBallHandle sball_open(const char *sballname);
/*
* sball_close()
* Closes down the Spaceball serial port, frees allocated resources and
* discards any unprocessed sball messages.
*/
int sball_close(SBallHandle voidhandle);
/*
* sball_getstatus()
* Polls the Spaceball serial port for new packets, performs any optional
* postprocessing of Spaceball data such as null-region, scaling, and
* value clamping. The most recent values for translation, rotation and
* buttons are stored in the memory locations supplied by the caller.
* Returns the number of events processed. If the number of events returned
* is less than 1, either an error occured or there were no Spaceball
* events to process.
*/
int sball_getstatus(SBallHandle voidhandle, int *tx, int *ty, int *tz, int *rx, int *ry, int *rz, int *buttons);
/* sball_get_input() - Added for spacenavd integration by John Tsiombikas.
*
* returns the first of any pending events through inp.
* returns 1 if it got an event, 0 if there where none pending
*/
int sball_get_input(SBallHandle voidhandle, struct dev_input *inp);
/* sball_get_fd() - Added for spacenavd integration by John Tsiombikas.
*
* retreives the device file descriptor */
int sball_get_fd(SBallHandle voidhandle);
/*
* sball_rezero()
* Forces the Orb to re-zero itself at the present twist/position.
* All future event data is relative to this zero point.
*/
int sball_rezero(SBallHandle voidhandle);
/*
* sball_init()
* Performs a software re-initialization of the Spaceball, clearing
* all unprocessed events. Initialization also forces the Orb to re-zero
* itself.
*/
int sball_init(SBallHandle voidhandle);
/*
* sball_set_nullregion()
* Enables null-region processing on Spaceball output.
* The null-region is the area (centered at 0) around which
* each coordinate will report zero even when the Spaceball itself
* reports a number whose absolute value is less than the null region
* value for that coordinate. For example, if the null region on the
* X translation coordinate is set to 50, all sball_getstatus() would report
* 0 if X is less than 50 and greater than -50. If X is 51, sball_getstatus
* would report 1. If X is -51, sball_getstatus() would report -1.
* Null-regions help novice users gradually become accustomed to the
* incredible sensitivity of the Spaceball, and make some applications
* significantly easier to control. A resonable default nullregion for all
* six axes is 65. Null regions should be tunable by the user, since its
* likely that not all Spaceballs are quite identical, and it is guaranteed
* that users have varying levels of manual dexterity.
* Note that setting the null-region too high significantly reduces the
* dynamic range of the output values from the Spaceball.
*/
void sball_set_nullregion(SBallHandle voidhandle, int nulltx, int nullty, int nulltz,
int nullrx, int nullry, int nullrz);
#ifdef __cplusplus
}
#endif
#endif

Wyświetl plik

@ -1,152 +0,0 @@
/*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas <nuclear@member.fsf.org>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
This file incorporates work covered by the following copyright and
permission notice:
Copyright 1997-2001 John E. Stone (j.stone@acm.org)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#define _POSIX_SOURCE 1
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "sballserial.h" /* protos and types for this file */
typedef struct {
int fd; /* serial port device file descriptor */
} commstruct;
int sball_comm_open(const char *commname, SBallCommHandle * commhandleptr)
{
struct termios sballtermio;
commstruct *comm;
*commhandleptr = NULL;
comm = malloc(sizeof(commstruct));
if(comm == NULL)
return -1;
comm->fd = open(commname, O_RDWR | O_NONBLOCK | O_NOCTTY);
if(comm->fd == -1) {
free(comm);
return -1; /* failed open of comm port */
}
tcgetattr(comm->fd, &sballtermio);
#if 0
/* TIOCEXCL exclusive access by this process */
#if defined(TIOCEXCL)
if(ioctl(comm->fd, TIOCEXCL) < 0) {
return -1; /* couldn't get exclusive use of port */
}
#endif
#endif
sballtermio.c_lflag = 0;
sballtermio.c_lflag = 0;
sballtermio.c_iflag = IGNBRK | IGNPAR;
sballtermio.c_oflag = 0;
sballtermio.c_cflag = CREAD | CS8 | CLOCAL | HUPCL;
sballtermio.c_cc[VEOL] = '\r';
sballtermio.c_cc[VERASE] = 0;
sballtermio.c_cc[VKILL] = 0;
sballtermio.c_cc[VMIN] = 0;
sballtermio.c_cc[VTIME] = 0;
/* use of baud rate in cflag is deprecated according to the */
/* single unix spec, also doesn't work in IRIX > 6.2 */
cfsetispeed(&sballtermio, B9600);
cfsetospeed(&sballtermio, B9600);
tcsetattr(comm->fd, TCSAFLUSH, &sballtermio);
*commhandleptr = (SBallCommHandle) comm;
return 0;
}
int sball_comm_write(SBallCommHandle commhandle, const char *buf)
{
commstruct *comm = (commstruct *) commhandle;
if(comm == NULL)
return -1;
return write(comm->fd, buf, strlen(buf));
}
int sball_comm_read(SBallCommHandle commhandle, char *buf, int sz)
{
commstruct *comm = (commstruct *) commhandle;
if(comm == NULL)
return -1;
return read(comm->fd, buf, sz);
}
int sball_comm_close(SBallCommHandle * commhandleptr)
{
commstruct *comm = (commstruct *) (*commhandleptr);
if(comm == NULL)
return -1;
close(comm->fd);
free(*commhandleptr);
*commhandleptr = NULL;
return 0;
}
int sball_comm_fd(SBallCommHandle commhandle)
{
return ((commstruct *) commhandle)->fd;
}
/* end of unix code */

Wyświetl plik

@ -1,67 +0,0 @@
/*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas <nuclear@member.fsf.org>
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
This file incorporates work covered by the following copyright and
permission notice:
Copyright 1997-2001 John E. Stone (j.stone@acm.org)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
/*
* Machine/OS dependent serial port I/O routines.
*
* sball_comm_open() - open the serial port device for communication with
* the sball. Settings are 9600,N,8,1, non-blocking,
* no controlling tty.
* sball_comm_read() - nonblocking read of up to size bytes
* sball_comm_write() - blocking write of up to size bytes
* sball_comm_close() - close the serial port device
*/
typedef void *SBallCommHandle;
int sball_comm_open(const char *commname, SBallCommHandle * commhandleptr);
int sball_comm_write(SBallCommHandle commhandle, const char *buf);
int sball_comm_read(SBallCommHandle commhandle, char *buf, int sz);
int sball_comm_close(SBallCommHandle * commhandleptr);
int sball_comm_fd(SBallCommHandle commhandle);