spacenavd-0.6/ 0000755 0001750 0001750 00000000000 12374256237 013202 5 ustar nuclear nuclear spacenavd-0.6/Makefile.in 0000644 0001750 0001750 00000002373 12162430754 015245 0 ustar nuclear nuclear src = $(wildcard src/*.c) $(wildcard src/serial/*.c) $(wildcard src/magellan/*.c)
hdr = $(wildcard src/*.h) $(wildcard src/serial/*.h) $(wildcard src/magellan/*.h)
obj = $(src:.c=.o)
dep = $(obj:.o=.d)
bin = spacenavd
ctl = spnavd_ctl
CC = gcc
INSTALL = install
CFLAGS = -pedantic -Wall $(dbg) $(opt) -fno-strict-aliasing -I$(srcdir)/src -I/usr/local/include $(add_cflags)
LDFLAGS = -L/usr/local/lib $(xlib) $(add_ldflags)
$(bin): $(obj)
$(CC) -o $@ $(obj) $(LDFLAGS)
-include $(dep)
tags: $(src) $(hdr)
ctags $(src) $(hdr)
%.o: $(srcdir)/%.c
$(CC) $(CFLAGS) -c $< -o $@
%.d: $(srcdir)/%.c
@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
.PHONY: clean
clean:
rm -f $(obj) $(bin)
.PHONY: cleandep
cleandep:
rm -f $(dep)
.PHONY: install
install: $(bin)
$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
$(INSTALL) -m 755 $(bin) $(DESTDIR)$(PREFIX)/bin/$(bin)
$(INSTALL) -m 755 $(srcdir)/$(ctl) $(DESTDIR)$(PREFIX)/bin/$(ctl)
cd $(srcdir) && ./setup_init --no-install
# [ -d /etc/hal/fdi/policy ] && \
# $(INSTALL) -m 644 spacenav.fdi $(DESTDIR)/etc/hal/fdi/policy/spacenav.fdi
.PHONY: uninstall
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/$(bin)
rm -f $(DESTDIR)$(PREFIX)/bin/$(ctl)
rm -f $(DESTDIR)/etc/hal/fdi/policy/spacenav.fdi
# cd $(srcdir) && ./setup_init remove
spacenavd-0.6/setup_init 0000755 0001750 0001750 00000002576 11535046476 015325 0 ustar nuclear nuclear #!/bin/sh
setup_sysv_init() {
rlvl=`cat /etc/inittab | grep :initdefault: | sed 's/^id://; s/:init.*$//'`
if [ $? != 0 -o -z "$rlvl" ]; then
echo 'default runlevel detection failed.'
rlvl=2
fi
echo "selected runlevel: $rlvl"
if [ "$1" = 'remove' ]; then
echo 'removing sysv init script'
rm -f /etc/init.d/spacenavd
rm -f /etc/rc${rlvl}.d/S99spacenavd
else
echo 'setting up sysv init script'
install -m 755 init_script /etc/init.d/spacenavd
cd /etc/rc${rlvl}.d
rm -f S99spacenavd
ln -s ../init.d/spacenavd S99spacenavd
fi
}
setup_bsd_init() {
echo 'setting up bsd init'
echo "BSD init setup not implemented yet, you'll have to do it manually."
}
if [ "$1" = '--no-install' ]; then
echo
echo --- Spacenavd installation complete ---
echo To have spacenavd start automatically at bootup, you must add an appropriate
echo "init script. Refer to your system's manual for details on how to do that."
echo An example init script is available in the spacenavd source directory.
echo If you wish to attempt and install an init script automatically, run ./setup_init
echo
exit 0
fi
if [ -d /etc/init.d -a -d /etc/rc0.d ]; then
setup_sysv_init $*
exit 0
fi
if [ -f /etc/rc -a -d /etc/rc.d ]; then
setup_bsd_init $*
exit 0
fi
echo "You're either using a non-standard init or this detection failed."
echo "You'll have to setup your init, to start spacenavd, manually."
spacenavd-0.6/spnavd_ctl 0000755 0001750 0001750 00000002215 11141453076 015254 0 ustar nuclear nuclear #!/bin/sh
# this script, starts and stops the communication between spacenavd and the
# local X server. (:0).
if [ "$1" != 'x11' ]; then
echo "the only valid control for the moment is x11 ($0 x11 start/stop)."
exit 1
fi
if [ -z "$2" ]; then
echo 'you must specify either "start" or "stop".'
exit 1
fi
if [ "$2" = 'start' ]; then
# check to see there is a local X server running.
DISPLAY=":0"
xdpyinfo >/dev/null 2>/dev/null
if [ $? != 0 ]; then
echo "You must have an X server running before starting up spacenavd-X11 events."
exit 1
fi
sig=-usr1
elif [ "$2" = "stop" ]; then
sig=-usr2
else
echo 'you must specify either "start" or "stop".'
exit 1
fi
# detect daemon's process id
pid=`cat /var/run/spnavd.pid 2>/dev/null`
if [ $? != 0 ]; then
pid=`ps -e | grep spacenavd | awk '{ print $1 }'`
if [ -z "$pid" ]; then
echo 'spacenavd daemon is not running, nothing to do.'
exit 1
fi
fi
kill $sig $pid
if [ $? = 0 ]; then
if [ $sig = '-usr1' ]; then
echo 'signalled spacenavd, it should now start sending X events.'
else
echo 'signalled spacenavd to stop sending X events.'
fi
else
echo 'sending signal to spacenavd failed.'
fi
spacenavd-0.6/spacenavd.sln 0000644 0001750 0001750 00000001563 12167571175 015672 0 ustar nuclear nuclear
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spacenavd", "spacenavd.vcproj", "{C1F098DD-4900-4820-98D5-4601340C8F90}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C1F098DD-4900-4820-98D5-4601340C8F90}.Debug|Win32.ActiveCfg = Debug|Win32
{C1F098DD-4900-4820-98D5-4601340C8F90}.Debug|Win32.Build.0 = Debug|Win32
{C1F098DD-4900-4820-98D5-4601340C8F90}.Release|Win32.ActiveCfg = Release|Win32
{C1F098DD-4900-4820-98D5-4601340C8F90}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
spacenavd-0.6/init_script 0000755 0001750 0001750 00000001342 11232220727 015442 0 ustar nuclear nuclear #!/bin/sh
#
# spacenavd free driver for 3Dconnexion 6dof devices
#
# chkconfig: 2345 99 99
# description: A free user space driver for 3Dconnexion input devices,\
# compatible with the proprietary 3dxsrv daemon.
DAEMON=/usr/local/bin/spacenavd
[ -x "$DAEMON" ] || exit 0
case "$1" in
start)
echo 'Starting spacenavd daemon'
$DAEMON -v
;;
stop)
echo 'Stopping spacenavd daemon'
# detect daemon's process id
pid=`cat /var/run/spnavd.pid 2>/dev/null`
if [ $? != 0 ]; then
pid=`ps -e | grep spacenavd | awk '{ print $1 }'`
if [ -z "$pid" ]; then
echo 'spacenavd daemon is not running, nothing to do.'
exit 1
fi
fi
kill $pid
;;
reload|restart|force-reload)
$0 stop && sleep 1 && $0 start
;;
esac
spacenavd-0.6/spacenavd.vcproj 0000644 0001750 0001750 00000007002 12167571175 016373 0 ustar nuclear nuclear
spacenavd-0.6/src/ 0000755 0001750 0001750 00000000000 12374256237 013771 5 ustar nuclear nuclear spacenavd-0.6/src/spnavd.h 0000644 0001750 0001750 00000002371 12162430754 015431 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
*/
#ifndef SPNAVD_H_
#define SPNAVD_H_
#include "config.h"
#include "cfgfile.h"
#define SOCK_NAME "/var/run/spnav.sock"
#define PIDFILE "/var/run/spnavd.pid"
#define LOGFILE "/var/log/spnavd.log"
/* Multiple devices support */
#ifndef MAX_DEVICES
#define MAX_DEVICES 8
#endif
#if defined(__cplusplus) || (__STDC_VERSION__ >= 199901L)
#define INLINE inline
#else /* not C++ or C99 */
#ifdef __GNUC__
#define INLINE __inline__
#else
#define INLINE
#endif
#endif
struct cfg cfg;
int verbose;
#endif /* SPNAVD_H_ */
spacenavd-0.6/src/cfgfile.c 0000644 0001750 0001750 00000034241 12162430754 015531 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2013 John Tsiombikas
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 .
*/
#include
#include
#include
#include
#include
#include
#include "cfgfile.h"
enum {TX, TY, TZ, RX, RY, RZ};
static const int def_axmap[] = {0, 2, 1, 3, 5, 4};
static const int def_axinv[] = {0, 1, 1, 0, 1, 1};
void default_cfg(struct cfg *cfg)
{
int i;
cfg->sensitivity = 1.0;
for(i=0; i<3; i++) {
cfg->sens_trans[i] = cfg->sens_rot[i] = 1.0;
}
for(i=0; i<6; i++) {
cfg->dead_threshold[i] = 2;
}
cfg->led = 1;
cfg->grab_device = 1;
for(i=0; i<6; i++) {
cfg->invert[i] = def_axinv[i];
cfg->map_axis[i] = def_axmap[i];
}
for(i=0; imap_button[i] = i;
cfg->kbmap_str[i] = 0;
cfg->kbmap[i] = 0;
}
cfg->repeat_msec = -1;
for(i=0; idevname[i] = 0;
cfg->devid[i][0] = cfg->devid[i][1] = -1;
}
}
#define EXPECT(cond) \
do { \
if(!(cond)) { \
fprintf(stderr, "%s: invalid value for %s\n", __func__, key_str); \
continue; \
} \
} while(0)
int read_cfg(const char *fname, struct cfg *cfg)
{
FILE *fp;
char buf[512];
struct flock flk;
int num_devid = 0;
/*int num_devnames = 0;*/
default_cfg(cfg);
if(!(fp = fopen(fname, "r"))) {
fprintf(stderr, "failed to open config file %s: %s. using defaults.\n", fname, strerror(errno));
return -1;
}
/* aquire shared read lock */
flk.l_type = F_RDLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
while(fcntl(fileno(fp), F_SETLKW, &flk) == -1);
while(fgets(buf, sizeof buf, fp)) {
int isint, isfloat, ival, i, bnidx, axisidx;
float fval;
char *endp, *key_str, *val_str, *line = buf;
while(*line == ' ' || *line == '\t') line++;
if(!*line || *line == '\n' || *line == '\r' || *line == '#') {
continue;
}
if(!(key_str = strtok(line, " =\n\t\r"))) {
fprintf(stderr, "invalid config line: %s, skipping.\n", line);
continue;
}
if(!(val_str = strtok(0, " =\n\t\r"))) {
fprintf(stderr, "missing value for config key: %s\n", key_str);
continue;
}
ival = strtol(val_str, &endp, 10);
isint = (endp > val_str);
fval = strtod(val_str, &endp);
isfloat = (endp > val_str);
if(strcmp(key_str, "repeat-interval") == 0) {
EXPECT(isint);
cfg->repeat_msec = ival;
} else if(strcmp(key_str, "dead-zone") == 0) {
EXPECT(isint);
for(i=0; i<6; i++) {
cfg->dead_threshold[i] = ival;
}
} else if(strcmp(key_str, "dead-zone-translation-x") == 0) {
EXPECT(isint);
cfg->dead_threshold[0] = ival;
} else if(strcmp(key_str, "dead-zone-translation-y") == 0) {
EXPECT(isint);
cfg->dead_threshold[1] = ival;
} else if(strcmp(key_str, "dead-zone-translation-z") == 0) {
EXPECT(isint);
cfg->dead_threshold[2] = ival;
} else if(strcmp(key_str, "dead-zone-rotation-x") == 0) {
EXPECT(isint);
cfg->dead_threshold[3] = ival;
} else if(strcmp(key_str, "dead-zone-rotation-y") == 0) {
EXPECT(isint);
cfg->dead_threshold[4] = ival;
} else if(strcmp(key_str, "dead-zone-rotation-z") == 0) {
EXPECT(isint);
cfg->dead_threshold[5] = ival;
} else if(strcmp(key_str, "sensitivity") == 0) {
EXPECT(isfloat);
cfg->sensitivity = fval;
} else if(strcmp(key_str, "sensitivity-translation") == 0) {
EXPECT(isfloat);
cfg->sens_trans[0] = cfg->sens_trans[1] = cfg->sens_trans[2] = fval;
} else if(strcmp(key_str, "sensitivity-translation-x") == 0) {
EXPECT(isfloat);
cfg->sens_trans[0] = fval;
} else if(strcmp(key_str, "sensitivity-translation-y") == 0) {
EXPECT(isfloat);
cfg->sens_trans[1] = fval;
} else if(strcmp(key_str, "sensitivity-translation-z") == 0) {
EXPECT(isfloat);
cfg->sens_trans[2] = fval;
} else if(strcmp(key_str, "sensitivity-rotation") == 0) {
EXPECT(isfloat);
cfg->sens_rot[0] = cfg->sens_rot[1] = cfg->sens_rot[2] = fval;
} else if(strcmp(key_str, "sensitivity-rotation-x") == 0) {
EXPECT(isfloat);
cfg->sens_rot[0] = fval;
} else if(strcmp(key_str, "sensitivity-rotation-y") == 0) {
EXPECT(isfloat);
cfg->sens_rot[1] = fval;
} else if(strcmp(key_str, "sensitivity-rotation-z") == 0) {
EXPECT(isfloat);
cfg->sens_rot[2] = fval;
} else if(strcmp(key_str, "invert-rot") == 0) {
if(strchr(val_str, 'x')) {
cfg->invert[RX] = !def_axinv[RX];
}
if(strchr(val_str, 'y')) {
cfg->invert[RY] = !def_axinv[RY];
}
if(strchr(val_str, 'z')) {
cfg->invert[RZ] = !def_axinv[RZ];
}
} else if(strcmp(key_str, "invert-trans") == 0) {
if(strchr(val_str, 'x')) {
cfg->invert[TX] = !def_axinv[TX];
}
if(strchr(val_str, 'y')) {
cfg->invert[TY] = !def_axinv[TY];
}
if(strchr(val_str, 'z')) {
cfg->invert[TZ] = !def_axinv[TZ];
}
} else if(strcmp(key_str, "swap-yz") == 0) {
int i, swap_yz = 0;
if(isint) {
swap_yz = ival;
} else {
if(strcmp(val_str, "true") == 0 || strcmp(val_str, "on") == 0 || strcmp(val_str, "yes") == 0) {
swap_yz = 1;
} else if(strcmp(val_str, "false") == 0 || strcmp(val_str, "off") == 0 || strcmp(val_str, "no") == 0) {
swap_yz = 0;
} else {
fprintf(stderr, "invalid configuration value for %s, expected a boolean value.\n", key_str);
continue;
}
}
for(i=0; i<6; i++) {
cfg->map_axis[i] = swap_yz ? i : def_axmap[i];
}
} else if(sscanf(key_str, "axismap%d", &axisidx) == 1) {
EXPECT(isint);
if(axisidx < 0 || axisidx >= MAX_AXES) {
fprintf(stderr, "invalid option %s, valid input axis numbers 0 - %d\n", key_str, MAX_AXES - 1);
continue;
}
if(ival < 0 || ival >= 6) {
fprintf(stderr, "invalid config value for %s, expected a number from 0 to 6\n", key_str);
continue;
}
cfg->map_axis[axisidx] = ival;
} else if(sscanf(key_str, "bnmap%d", &bnidx) == 1) {
EXPECT(isint);
if(bnidx < 0 || bnidx >= MAX_BUTTONS || ival < 0 || ival >= MAX_BUTTONS) {
fprintf(stderr, "invalid configuration value for %s, expected a number from 0 to %d\n", key_str, MAX_BUTTONS);
continue;
}
if(cfg->map_button[bnidx] != bnidx) {
printf("warning: multiple mappings for button %d\n", bnidx);
}
cfg->map_button[bnidx] = ival;
} else if(sscanf(key_str, "kbmap%d", &bnidx) == 1) {
if(bnidx < 0 || bnidx >= MAX_BUTTONS) {
fprintf(stderr, "invalid configuration value for %s, expected a number from 0 to %d\n", key_str, MAX_BUTTONS);
continue;
}
if(cfg->kbmap_str[bnidx]) {
printf("warning: multiple keyboard mappings for button %d: %s -> %s\n", bnidx, cfg->kbmap_str[bnidx], val_str);
free(cfg->kbmap_str[bnidx]);
}
cfg->kbmap_str[bnidx] = strdup(val_str);
} else if(strcmp(key_str, "led") == 0) {
if(isint) {
cfg->led = ival;
} else {
if(strcmp(val_str, "true") == 0 || strcmp(val_str, "on") == 0 || strcmp(val_str, "yes") == 0) {
cfg->led = 1;
} else if(strcmp(val_str, "false") == 0 || strcmp(val_str, "off") == 0 || strcmp(val_str, "no") == 0) {
cfg->led = 0;
} else {
fprintf(stderr, "invalid configuration value for %s, expected a boolean value.\n", key_str);
continue;
}
}
} else if(strcmp(key_str, "grab") == 0) {
if(isint) {
cfg->grab_device = ival;
} else {
if(strcmp(val_str, "true") == 0 || strcmp(val_str, "on") == 0 || strcmp(val_str, "yes") == 0) {
cfg->grab_device = 1;
} else if(strcmp(val_str, "false") == 0 || strcmp(val_str, "off") == 0 || strcmp(val_str, "no") == 0) {
cfg->grab_device = 0;
} else {
fprintf(stderr, "invalid configuration value for %s, expected a boolean value.\n", key_str);
continue;
}
}
} else if(strcmp(key_str, "serial") == 0) {
strncpy(cfg->serial_dev, val_str, PATH_MAX);
} else if(strcmp(key_str, "device-id") == 0) {
unsigned int vendor, prod;
if(sscanf(val_str, "%x:%x", &vendor, &prod) == 2) {
cfg->devid[num_devid][0] = (int)vendor;
cfg->devid[num_devid][1] = (int)prod;
num_devid++;
} else {
fprintf(stderr, "invalid configuration value for %s, expected a vendorid:productid pair\n", key_str);
continue;
}
} else {
fprintf(stderr, "unrecognized config option: %s\n", key_str);
}
}
/* unlock */
flk.l_type = F_UNLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
fcntl(fileno(fp), F_SETLK, &flk);
fclose(fp);
return 0;
}
int write_cfg(const char *fname, struct cfg *cfg)
{
int i, wrote_comment;
FILE *fp;
struct flock flk;
if(!(fp = fopen(fname, "w"))) {
fprintf(stderr, "failed to write config file %s: %s\n", fname, strerror(errno));
return -1;
}
/* aquire exclusive write lock */
flk.l_type = F_WRLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
while(fcntl(fileno(fp), F_SETLKW, &flk) == -1);
fprintf(fp, "# sensitivity is multiplied with every motion (1.0 normal).\n");
fprintf(fp, "sensitivity = %.3f\n\n", cfg->sensitivity);
fprintf(fp, "# separate sensitivity for rotation and translation.\n");
if(cfg->sens_trans[0] == cfg->sens_trans[1] && cfg->sens_trans[1] == cfg->sens_trans[2]) {
fprintf(fp, "sensitivity-translation = %.3f\n", cfg->sens_trans[0]);
} else {
fprintf(fp, "sensitivity-translation-x = %.3f\n", cfg->sens_trans[0]);
fprintf(fp, "sensitivity-translation-y = %.3f\n", cfg->sens_trans[1]);
fprintf(fp, "sensitivity-translation-z = %.3f\n", cfg->sens_trans[2]);
}
if(cfg->sens_rot[0] == cfg->sens_rot[1] && cfg->sens_rot[1] == cfg->sens_rot[2]) {
fprintf(fp, "sensitivity-rotation = %.3f\n", cfg->sens_rot[0]);
} else {
fprintf(fp, "sensitivity-rotation-x = %.3f\n", cfg->sens_rot[0]);
fprintf(fp, "sensitivity-rotation-y = %.3f\n", cfg->sens_rot[1]);
fprintf(fp, "sensitivity-rotation-z = %.3f\n", cfg->sens_rot[2]);
}
fputc('\n', fp);
fprintf(fp, "# dead zone; any motion less than this number, is discarded as noise.\n");
if(cfg->dead_threshold[0] == cfg->dead_threshold[1] && cfg->dead_threshold[1] == cfg->dead_threshold[2] && cfg->dead_threshold[2] == cfg->dead_threshold[3] && cfg->dead_threshold[3] == cfg->dead_threshold[4] && cfg->dead_threshold[4] == cfg->dead_threshold[5]) {
fprintf(fp, "dead-zone = %d\n", cfg->dead_threshold[0]);
} else {
fprintf(fp, "dead-zone-translation-x = %d\n", cfg->dead_threshold[0]);
fprintf(fp, "dead-zone-translation-y = %d\n", cfg->dead_threshold[1]);
fprintf(fp, "dead-zone-translation-z = %d\n", cfg->dead_threshold[2]);
fprintf(fp, "dead-zone-rotation-x = %d\n", cfg->dead_threshold[3]);
fprintf(fp, "dead-zone-rotation-y = %d\n", cfg->dead_threshold[4]);
fprintf(fp, "dead-zone-rotation-z = %d\n", cfg->dead_threshold[5]);
}
fputc('\n', fp);
fprintf(fp, "# repeat interval; non-deadzone events are repeated every so many milliseconds (-1 to disable)\n");
fprintf(fp, "repeat-interval = %d\n", cfg->repeat_msec);
if(cfg->invert[0] != def_axinv[0] || cfg->invert[1] != def_axinv[1] || cfg->invert[2] != def_axinv[2]) {
fprintf(fp, "# invert translations on some axes.\n");
fprintf(fp, "invert-trans = ");
if(cfg->invert[0] != def_axinv[0]) fputc('x', fp);
if(cfg->invert[1] != def_axinv[1]) fputc('y', fp);
if(cfg->invert[2] != def_axinv[2]) fputc('z', fp);
fputs("\n\n", fp);
}
if(cfg->invert[3] != def_axinv[3] || cfg->invert[4] != def_axinv[4] || cfg->invert[5] != def_axinv[5]) {
fprintf(fp, "# invert rotations around some axes.\n");
fprintf(fp, "invert-rot = ");
if(cfg->invert[3] != def_axinv[3]) fputc('x', fp);
if(cfg->invert[4] != def_axinv[4]) fputc('y', fp);
if(cfg->invert[5] != def_axinv[5]) fputc('z', fp);
fputs("\n\n", fp);
}
fprintf(fp, "# swap translation along Y and Z axes\n");
fprintf(fp, "swap-yz = %s\n\n", cfg->map_axis[1] == def_axmap[1] ? "false" : "true");
wrote_comment = 0;
for(i=0; imap_button[i] != i) {
if(!wrote_comment) {
fprintf(fp, "# button mappings\n");
wrote_comment = 1;
}
fprintf(fp, "bnmap%d = %d\n", i, cfg->map_button[i]);
}
}
if(wrote_comment) {
fputc('\n', fp);
}
wrote_comment = 0;
for(i=0; ikbmap_str[i]) {
if(!wrote_comment) {
fprintf(fp, "# button to key mappings\n");
wrote_comment = 1;
}
fprintf(fp, "kbmap%d = %s\n", i, cfg->kbmap_str[i]);
}
}
if(wrote_comment) {
fputc('\n', fp);
}
if(!cfg->led) {
fprintf(fp, "# disable led\n");
fprintf(fp, "led = 0\n\n");
}
if(!cfg->grab_device) {
fprintf(fp, "# Don't grab USB device\n");
fprintf(fp, "# Grabbing the device ensures that other programs won't be able to use it without\n");
fprintf(fp, "# talking to spacenavd. For instance some versions of Xorg will use the device to move\n");
fprintf(fp, "# the mouse pointer if we don't grab it.\n");
fprintf(fp, "# Set this to false if you want to use programs that try to talk to the device directly\n");
fprintf(fp, "# such as google earth, then follow FAQ 11 http://spacenav.sourceforge.net/faq.html#faq11\n");
fprintf(fp, "# to force the X server to ignore the device\n");
fprintf(fp, "grab = false\n\n");
}
fprintf(fp, "# serial device\n");
fprintf(fp, "# Set this only if you have a serial device, and make sure you specify the\n");
fprintf(fp, "# correct device file (On linux usually: /dev/ttyS0, /dev/ttyS1, /dev/ttyUSB0 ... etc).\n");
if(cfg->serial_dev[0]) {
fprintf(fp, "serial = %s\n\n", cfg->serial_dev);
} else {
fprintf(fp, "#serial = /dev/ttyS0\n");
}
fprintf(fp, "# custom list USB device ids to open if present\n");
fprintf(fp, "# (multiple entries can be listed)\n");
for(i=0; idevid[i][0] != -1 && cfg->devid[i][1] != -1) {
fprintf(fp, "device-id = %x:%x\n", cfg->devid[i][0], cfg->devid[i][1]);
}
}
/* unlock */
flk.l_type = F_UNLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
fcntl(fileno(fp), F_SETLK, &flk);
fclose(fp);
return 0;
}
spacenavd-0.6/src/dev_usb.c 0000644 0001750 0001750 00000002521 12162151603 015546 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2013 John Tsiombikas
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 .
*/
#include
#include
#include "dev_usb.h"
void free_usb_devices_list(struct usb_device_info *list)
{
while(list) {
int i;
struct usb_device_info *tmp = list;
list = list->next;
free(tmp->name);
for(i=0; inum_devfiles; i++) {
free(tmp->devfiles[i]);
}
free(tmp);
}
}
void print_usb_device_info(struct usb_device_info *devinfo)
{
int i;
printf("[%x:%x]: \"%s\" (", devinfo->vendorid, devinfo->productid,
devinfo->name ? devinfo->name : "unknown");
for(i=0; inum_devfiles; i++) {
printf("%s ", devinfo->devfiles[i]);
}
fputs(")\n", stdout);
}
spacenavd-0.6/src/event.c 0000644 0001750 0001750 00000015143 12161355713 015253 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2013 John Tsiombikas
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 .
*/
#include "config.h"
#include
#include
#include "event.h"
#include "client.h"
#include "proto_unix.h"
#include "spnavd.h"
#ifdef USE_X11
#include "proto_x11.h"
#include "kbemu.h"
#endif
enum {
MOT_X, MOT_Y, MOT_Z,
MOT_RX, MOT_RY, MOT_RZ
};
struct dev_event {
spnav_event event;
struct timeval timeval;
struct device *dev;
int pending;
struct dev_event *next;
};
static struct dev_event *add_dev_event(struct device *dev);
static struct dev_event *device_event_in_use(struct device *dev);
static void dispatch_event(struct dev_event *dev);
static void send_event(spnav_event *ev, struct client *c);
static unsigned int msec_dif(struct timeval tv1, struct timeval tv2);
static struct dev_event *dev_ev_list = NULL;
static struct dev_event *add_dev_event(struct device *dev)
{
struct dev_event *dev_ev, *iter;
int i;
if((dev_ev = malloc(sizeof *dev_ev)) == NULL) {
return NULL;
}
dev_ev->event.motion.data = (int*)&dev_ev->event.motion.x;
for(i=0; i<6; i++)
dev_ev->event.motion.data[i] = 0;
gettimeofday(&dev_ev->timeval, 0);
dev_ev->dev = dev;
dev_ev->next = NULL;
if(dev_ev_list == NULL)
return dev_ev_list = dev_ev;
iter = dev_ev_list;
while(iter->next) {
iter = iter->next;
}
iter->next = dev_ev;
return dev_ev;
}
/* remove_dev_event takes a device pointer as argument so that upon removal of
* a device the pending event (if any) can be removed.
*/
void remove_dev_event(struct device *dev)
{
struct dev_event dummy;
struct dev_event *iter;
dummy.next = dev_ev_list;
iter = &dummy;
while(iter->next) {
if(iter->next->dev == dev) {
struct dev_event *ev = iter->next;
iter->next = ev->next;
if(verbose) {
printf("removing pending device event of: %s\n", dev->path);
}
free(ev);
} else {
iter = iter->next;
}
}
dev_ev_list = dummy.next;
}
static struct dev_event *device_event_in_use(struct device *dev)
{
struct dev_event *iter = dev_ev_list;
while(iter) {
if(iter->dev == dev) {
return iter;
}
iter = iter->next;
}
return NULL;
}
/* process_input processes an device input event, and dispatches
* spacenav events to the clients by calling dispatch_event.
* relative inputs (INP_MOTION) are accumulated, and dispatched when
* we get an INP_FLUSH event. Button events are dispatched immediately
* and they implicitly flush any pending motion event.
*/
void process_input(struct device *dev, struct dev_input *inp)
{
int sign;
struct dev_event *dev_ev;
switch(inp->type) {
case INP_MOTION:
if(abs(inp->val) < cfg.dead_threshold[inp->idx] ) {
inp->val = 0;
}
inp->idx = cfg.map_axis[inp->idx];
sign = cfg.invert[inp->idx] ? -1 : 1;
inp->val = (int)((float)inp->val * cfg.sensitivity * (inp->idx < 3 ? cfg.sens_trans[inp->idx] : cfg.sens_rot[inp->idx - 3]));
dev_ev = device_event_in_use(dev);
if(verbose && dev_ev == NULL)
printf("adding dev event for device: %s\n", dev->path);
if(dev_ev == NULL && (dev_ev = add_dev_event(dev)) == NULL) {
fprintf(stderr, "failed to get dev_event\n");
break;
}
dev_ev->event.type = EVENT_MOTION;
dev_ev->event.motion.data = (int*)&dev_ev->event.motion.x;
dev_ev->event.motion.data[inp->idx] = sign * inp->val;
dev_ev->pending = 1;
break;
case INP_BUTTON:
#ifdef USE_X11
/* check to see if we must emulate a keyboard event instead of a
* retular button event for this button
*/
if(cfg.kbmap_str[inp->idx]) {
if(!cfg.kbmap[inp->idx]) {
cfg.kbmap[inp->idx] = kbemu_keysym(cfg.kbmap_str[inp->idx]);
printf("mapping ``%s'' to keysym %d\n", cfg.kbmap_str[inp->idx], (int)cfg.kbmap[inp->idx]);
}
send_kbevent(cfg.kbmap[inp->idx], inp->val);
break;
}
#endif
dev_ev = device_event_in_use(dev);
if(dev_ev && dev_ev->pending) {
dispatch_event(dev_ev);
dev_ev->pending = 0;
}
inp->idx = cfg.map_button[inp->idx];
/* button events are not queued */
{
struct dev_event dev_button_event;
dev_button_event.dev = dev;
dev_button_event.event.type = EVENT_BUTTON;
dev_button_event.event.button.press = inp->val;
dev_button_event.event.button.bnum = inp->idx;
dispatch_event(&dev_button_event);
}
/* to have them replace motion events in the queue uncomment next section */
/* dev_ev = add_dev_event(dev);
* dev_ev->event.type = EVENT_BUTTON;
* dev_ev->event.button.press = inp->val;
* dev_ev->event.button.bnum = inp->idx;
* dispatch_event(dev_ev);
*/
break;
case INP_FLUSH:
dev_ev = device_event_in_use(dev);
if(dev_ev && dev_ev->pending) {
dispatch_event(dev_ev);
dev_ev->pending = 0;
}
break;
default:
break;
}
}
int in_deadzone(struct device *dev)
{
int i;
struct dev_event *dev_ev;
if((dev_ev = device_event_in_use(dev)) == NULL)
return -1;
for(i=0; i<6; i++) {
if(dev_ev->event.motion.data[i] != 0)
return 0;
}
return 1;
}
void repeat_last_event(struct device *dev)
{
struct dev_event *dev_ev;
if((dev_ev = device_event_in_use(dev)) == NULL)
return;
dispatch_event(dev_ev);
}
static void dispatch_event(struct dev_event *dev_ev)
{
struct client *c, *client_iter;
int dev_idx;
if(dev_ev->event.type == EVENT_MOTION) {
struct timeval tv;
gettimeofday(&tv, 0);
dev_ev->event.motion.period = msec_dif(tv, dev_ev->timeval);
dev_ev->timeval = tv;
}
dev_idx = get_device_index(dev_ev->dev);
client_iter = first_client();
while(client_iter) {
c = client_iter;
client_iter = next_client();
if(get_client_device_index(c) <= dev_idx) /* use <= until API changes, else == */
send_event(&dev_ev->event, c);
}
}
static void send_event(spnav_event *ev, struct client *c)
{
switch(get_client_type(c)) {
#ifdef USE_X11
case CLIENT_X11:
send_xevent(ev, c);
break;
#endif
case CLIENT_UNIX:
send_uevent(ev, c);
break;
default:
break;
}
}
static unsigned int msec_dif(struct timeval tv1, struct timeval tv2)
{
unsigned int ms1, ms2;
ms1 = tv1.tv_sec * 1000 + tv1.tv_usec / 1000;
ms2 = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
return ms1 - ms2;
}
spacenavd-0.6/src/proto_unix.h 0000644 0001750 0001750 00000002026 11403040606 016327 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
*/
#ifndef PROTO_UNIX_H_
#define PROTO_UNIX_H_
#include "config.h"
#include "event.h"
#include "client.h"
int init_unix(void);
void close_unix(void);
int get_unix_socket(void);
void send_uevent(spnav_event *ev, struct client *c);
int handle_uevents(fd_set *rset);
#endif /* PROTO_UNIX_H_ */
spacenavd-0.6/src/dev.h 0000644 0001750 0001750 00000003115 12162430754 014711 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2013 John Tsiombikas
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 .
*/
#ifndef SPNAV_DEV_H_
#define SPNAV_DEV_H_
#include
#include "config.h"
struct dev_input;
#define MAX_DEV_NAME 256
struct device {
int fd;
void *data;
char name[MAX_DEV_NAME];
char path[PATH_MAX];
int num_axes;
int *minval, *maxval; /* input value range (default: -500, 500) */
int *fuzz; /* noise threshold */
void (*close)(struct device*);
int (*read)(struct device*, struct dev_input*);
void (*set_led)(struct device*, int);
struct device *next;
};
int init_devices(void);
void remove_device(struct device *dev);
int get_device_fd(struct device *dev);
#define is_device_valid(dev) (get_device_fd(dev) >= 0)
int get_device_index(struct device *dev);
int read_device(struct device *dev, struct dev_input *inp);
void set_device_led(struct device *dev, int state);
struct device *get_devices(void);
#endif /* SPNAV_DEV_H_ */
spacenavd-0.6/src/hotplug_linux.c 0000644 0001750 0001750 00000005430 12127374572 017037 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas
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 .
*/
#ifdef __linux__
#include "config.h"
#include
#include
#include
#include
#ifdef USE_NETLINK
#include
#include
#include
#endif
#include "hotplug.h"
#include "dev.h"
#include "spnavd.h"
#include "cfgfile.h"
static int con_hotplug(void);
static void poll_timeout(int sig);
static int hotplug_fd = -1;
static int poll_time, poll_pipe;
int init_hotplug(void)
{
if(hotplug_fd != -1) {
fprintf(stderr, "WARNING: calling init_hotplug while hotplug is running!\n");
return hotplug_fd;
}
if((hotplug_fd = con_hotplug()) == -1) {
int pfd[2];
if(verbose) {
printf("hotplug failed will resort to polling\n");
}
if(pipe(pfd) == -1) {
perror("failed to open polling self-pipe");
return -1;
}
poll_pipe = pfd[1];
hotplug_fd = pfd[0];
poll_time = 1;
signal(SIGALRM, poll_timeout);
alarm(poll_time);
}
return hotplug_fd;
}
void shutdown_hotplug(void)
{
if(hotplug_fd != -1) {
close(hotplug_fd);
hotplug_fd = -1;
}
if(poll_pipe != -1) {
close(poll_pipe);
poll_pipe = -1;
}
}
int get_hotplug_fd(void)
{
return hotplug_fd;
}
int handle_hotplug(void)
{
char buf[512];
read(hotplug_fd, buf, sizeof buf);
if(verbose)
printf("\nhandle_hotplug called\n");
if (init_devices() == -1)
return -1;
return 0;
}
static int con_hotplug(void)
{
int s = -1;
#ifdef USE_NETLINK
struct sockaddr_nl addr;
if((s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) == -1) {
perror("failed to open hotplug netlink socket");
return -1;
}
memset(&addr, 0, sizeof addr);
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = -1;
if(bind(s, (struct sockaddr*)&addr, sizeof addr) == -1) {
perror("failed to bind to hotplug netlink socket");
close(s);
return -1;
}
#endif /* USE_NETLINK */
return s;
}
static void poll_timeout(int sig)
{
signal(sig, poll_timeout);
if(sig == SIGALRM) {
if(poll_pipe != -1) {
write(poll_pipe, &sig, 1);
poll_time *= 2;
alarm(poll_time);
}
}
}
#endif /* __linux__ */
spacenavd-0.6/src/hotplug.h 0000644 0001750 0001750 00000001653 11752110171 015612 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas
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 .
*/
#ifndef SPNAV_HOTPLUG_H_
#define SPNAV_HOTPLUG_H_
int init_hotplug(void);
void shutdown_hotplug(void);
int get_hotplug_fd(void);
int handle_hotplug(void);
#endif /* SPNAV_HOTPLUG_H_ */
spacenavd-0.6/src/xdetect_freebsd.c 0000644 0001750 0001750 00000007024 11754722440 017265 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2011 John Tsiombikas
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 .
*/
#if defined(__FreeBSD__) || defined(__APPLE__)
#include "config.h"
#ifdef USE_X11
#include
#include
#include
#include
#include
#include
#include
#include
#include "proto_x11.h"
#include "spnavd.h"
static int kq = -1;
static int fd_x11 = -1;
static int fd_tmp = -1;
int xdet_start(void)
{
struct timespec ts = {0, 0};
struct kevent kev;
if((kq = kqueue()) == -1) {
perror("failed to create kqueue");
return -1;
}
if((fd_x11 = open("/tmp/.X11-unix", O_RDONLY)) == -1) {
if((fd_tmp = open("/tmp", O_RDONLY)) == -1) {
perror("failed to open /tmp");
goto err;
}
}
EV_SET(&kev, fd_x11 != -1 ? fd_x11 : fd_tmp, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
if(kevent(kq, &kev, 1, 0, 0, &ts) == -1) {
perror("failed to register kqueue event notification");
goto err;
}
if(verbose) {
printf("waiting for the X socket file to appear\n");
}
return kq;
err:
if(fd_x11 != -1)
close(fd_x11);
if(fd_tmp != -1)
close(fd_tmp);
if(kq != -1)
close(kq);
kq = -1;
return -1;
}
void xdet_stop(void)
{
if(kq != -1) {
if(verbose) {
printf("stopping X watch\n");
}
if(fd_x11 != -1)
close(fd_x11);
if(fd_tmp != -1)
close(fd_tmp);
close(kq);
kq = fd_x11 = fd_tmp = -1;
}
}
int xdet_get_fd(void)
{
return kq;
}
int handle_xdet_events(fd_set *rset)
{
struct kevent kev;
struct timespec ts = {0, 0};
if(kq == -1 || !FD_ISSET(kq, rset)) {
return -1;
}
if(kevent(kq, 0, 0, &kev, 1, &ts) <= 0) {
return -1;
}
if(kev.ident == fd_tmp) {
assert(fd_x11 == -1);
/* try to open the socket dir, see if that was what was added to /tmp */
if((fd_x11 = open("/tmp/.X11-unix", O_RDONLY)) == -1) {
return -1;
}
EV_SET(&kev, fd_x11, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
if(kevent(kq, &kev, 1, 0, 0, &ts) == -1) {
perror("failed to register kqueue event notification for /tmp/.X11-unix");
close(fd_x11);
fd_x11 = -1;
return -1;
}
/* successfully added the notification for /tmp/.X11-unix, now we
* don't need the /tmp notification anymore. by closing the fd it's
* automatically removed from the kqueue.
*/
close(fd_tmp);
fd_tmp = -1;
} else if(kev.ident == fd_x11) {
int i;
if(verbose) {
printf("found X socket, will now attempt to connect to the X server\n");
}
/* poll for approximately 30 seconds (well a bit more than that) */
for(i=0; i<30; i++) {
sleep(1);
if(init_x11() != -1) {
/* done, we don't need the X socket notification any more */
close(fd_x11);
fd_x11 = -1;
return 0; /* success */
}
}
fprintf(stderr, "found X socket yet failed to connect\n");
}
return -1;
}
#endif /* USE_X11 */
#else
int spacenavd_xdetect_freebsd_shut_up_empty_source_warning;
#endif /* __FreeBSD__ */
spacenavd-0.6/src/proto_x11.c 0000644 0001750 0001750 00000022314 12147160444 015763 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas
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 .
*/
#include "config.h"
#ifdef USE_X11
#include
#include
#include
#include
#include
#ifdef HAVE_ALLOCA_H
#include
#endif
#ifdef HAVE_MALLOC_H
#include
#endif
#include
#include
#include "proto_x11.h"
#include "client.h"
#include "spnavd.h"
#include "xdetect.h"
#include "kbemu.h"
enum cmd_msg {
CMD_NONE,
CMD_APP_WINDOW = 27695, /* set client window */
CMD_APP_SENS /* set app sensitivity */
};
static int xerr(Display *dpy, XErrorEvent *err);
static int xioerr(Display *dpy);
static Display *dpy;
static Window win;
static Atom xa_event_motion, xa_event_bpress, xa_event_brelease, xa_event_cmd;
/* XXX This stands in for the client sensitivity. Due to the
* bad design of the original magellan protocol, we can't know
* which client requested the sensitivity change, so we have
* to keep it global for all X clients.
*/
static float x11_sens = 1.0;
static jmp_buf jbuf;
int init_x11(void)
{
int i, screen, scr_count;
Window root;
XSetWindowAttributes xattr;
Atom wm_delete, cmd_type;
XTextProperty tp_wname;
XClassHint class_hint;
char *win_title = "Magellan Window";
if(dpy) return 0;
/* if the server started from init, it probably won't have a DISPLAY env var
* so let's add a default one.
*/
if(!getenv("DISPLAY")) {
putenv("DISPLAY=:0.0");
}
/* ... also there won't be an XAUTHORITY env var, so set one up */
if(!getenv("XAUTHORITY")) {
struct passwd *p = getpwuid(getuid());
char *home, *buf;
if(!p || !p->pw_dir) {
if(!p) {
fprintf(stderr, "getpwuid failed: %s\n", strerror(errno));
}
fprintf(stderr, "falling back to getting the home directory from the HOME env var...\n");
if(!(home = getenv("HOME"))) {
fprintf(stderr, "HOME env var not found, using /tmp as a home directory...\n");
home = "/tmp";
}
} else {
home = p->pw_dir;
}
buf = alloca(strlen("XAUTHORITY=") + strlen(home) + strlen("/.Xauthority") + 1);
sprintf(buf, "XAUTHORITY=%s/.Xauthority", home);
putenv(buf);
}
if(verbose) {
printf("trying to open X11 display \"%s\"\n", getenv("DISPLAY"));
printf(" XAUTHORITY=%s\n", getenv("XAUTHORITY"));
}
if(!(dpy = XOpenDisplay(0))) {
fprintf(stderr, "failed to open X11 display \"%s\"\n", getenv("DISPLAY"));
xdet_start();
return -1;
}
XSetErrorHandler(xerr);
XSetIOErrorHandler(xioerr);
if(setjmp(jbuf)) {
return -1;
}
scr_count = ScreenCount(dpy);
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
/* intern the various atoms used for communicating with the magellan clients */
xa_event_motion = XInternAtom(dpy, "MotionEvent", False);
xa_event_bpress = XInternAtom(dpy, "ButtonPressEvent", False);
xa_event_brelease = XInternAtom(dpy, "ButtonReleaseEvent", False);
xa_event_cmd = XInternAtom(dpy, "CommandEvent", False);
/* Create a dummy window, so that clients are able to send us events
* through the magellan API. No need to map the window.
*/
xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, screen);
xattr.colormap = DefaultColormap(dpy, screen);
win = XCreateWindow(dpy, root, 0, 0, 10, 10, 0, CopyFromParent, InputOutput,
DefaultVisual(dpy, screen), CWColormap | CWBackPixel | CWBorderPixel, &xattr);
wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(dpy, win, &wm_delete, 1);
XStringListToTextProperty(&win_title, 1, &tp_wname);
XSetWMName(dpy, win, &tp_wname);
XFree(tp_wname.value);
class_hint.res_name = "magellan";
class_hint.res_class = "magellan_win";
XSetClassHint(dpy, win, &class_hint);
/* I believe this is a bit hackish, but the magellan API expects to find the CommandEvent
* property on the root window, containing our window id.
* The API doesn't look for a specific property type, so I made one up here (MagellanCmdType).
*/
cmd_type = XInternAtom(dpy, "MagellanCmdType", False);
for(i=0; itype) {
case EVENT_MOTION:
xevent.xclient.message_type = xa_event_motion;
xevent.xclient.format = 16;
for(i=0; i<6; i++) {
float val = (float)ev->motion.data[i] * x11_sens;
xevent.xclient.data.s[i + 2] = (short)val;
}
xevent.xclient.data.s[0] = xevent.xclient.data.s[1] = 0;
xevent.xclient.data.s[8] = ev->motion.period;
break;
case EVENT_BUTTON:
xevent.xclient.message_type = ev->button.press ? xa_event_bpress : xa_event_brelease;
xevent.xclient.format = 16;
xevent.xclient.data.s[2] = ev->button.bnum;
break;
default:
break;
}
XSendEvent(dpy, get_client_window(c), False, 0, &xevent);
XFlush(dpy);
}
int handle_xevents(fd_set *rset)
{
if(!dpy) {
if(xdet_get_fd() != -1) {
handle_xdet_events(rset);
}
return -1;
}
/* process any pending X events */
if(FD_ISSET(ConnectionNumber(dpy), rset)) {
if(setjmp(jbuf)) {
return 0;
}
while(XPending(dpy)) {
XEvent xev;
XNextEvent(dpy, &xev);
if(xev.type == ClientMessage && xev.xclient.message_type == xa_event_cmd) {
unsigned int win_id;
switch(xev.xclient.data.s[2]) {
case CMD_APP_WINDOW:
win_id = xev.xclient.data.s[1];
win_id |= (unsigned int)xev.xclient.data.s[0] << 16;
set_client_window((Window)win_id);
break;
case CMD_APP_SENS:
x11_sens = *(float*)xev.xclient.data.s; /* see decl of x11_sens for details */
break;
default:
break;
}
}
}
}
return 0;
}
/* adds a new X11 client to the list, IF it does not already exist */
void set_client_window(Window win)
{
int i, scr_count;
struct client *cnode;
/* When a magellan application exits, the SDK sets another window to avoid
* crashing the original proprietary daemon. The new free SDK will set
* consistently the root window for that purpose, which we can ignore here
* easily.
*/
scr_count = ScreenCount(dpy);
for(i=0; ierror_code == BadWindow) {
/* we may get a BadWindow error when trying to send events to
* clients that have disconnected in the meanwhile.
*/
remove_client_window((Window)err->resourceid);
} else {
XGetErrorText(dpy, err->error_code, buf, sizeof buf);
fprintf(stderr, "Caught unexpected X error: %s\n", buf);
}
return 0;
}
/* X11 I/O error handler
* This function must not return or xlib will abort.
*/
static int xioerr(Display *display)
{
fprintf(stderr, "Lost the X server!\n");
dpy = 0;
close_x11();
xdet_start();
longjmp(jbuf, 1);
return 0;
}
#else
int spacenavd_proto_x11_shut_up_empty_source_warning;
#endif /* USE_X11 */
spacenavd-0.6/src/proto_x11.h 0000644 0001750 0001750 00000002213 11403040606 015753 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
*/
#ifndef PROTO_X11_H_
#define PROTO_X11_H_
#include "config.h"
#include
#include
#include "event.h"
#include "client.h"
int init_x11(void);
void close_x11(void);
int get_x11_socket(void);
void send_xevent(spnav_event *ev, struct client *c);
int handle_xevents(fd_set *rset);
void set_client_window(Window win);
void remove_client_window(Window win);
#endif /* PROTO_X11_H_ */
spacenavd-0.6/src/kbemu.c 0000644 0001750 0001750 00000003126 11751134441 015230 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas
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 .
*/
#include "config.h"
#ifdef USE_X11
#include
#include
#include "kbemu.h"
static Display *dpy;
void kbemu_set_display(Display *d)
{
dpy = d;
}
KeySym kbemu_keysym(const char *str)
{
return XStringToKeysym(str);
}
void send_kbevent(KeySym key, int press)
{
XEvent xevent;
Window win;
int rev_state;
if(!dpy) return;
XGetInputFocus(dpy, &win, &rev_state);
xevent.type = press ? KeyPress : KeyRelease;
xevent.xkey.display = dpy;
xevent.xkey.root = DefaultRootWindow(dpy);
xevent.xkey.window = win;
xevent.xkey.subwindow = None;
xevent.xkey.keycode = XKeysymToKeycode(dpy, key);
xevent.xkey.state = 0;
xevent.xkey.time = CurrentTime;
xevent.xkey.x = xevent.xkey.y = 1;
xevent.xkey.x_root = xevent.xkey.y_root = 1;
XSendEvent(dpy, win, True, press ? KeyPressMask : KeyReleaseMask, &xevent);
XFlush(dpy);
}
#endif /* USE_X11 */
spacenavd-0.6/src/xdetect.h 0000644 0001750 0001750 00000001661 11403040606 015565 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
*/
#ifndef XDETECT_H_
#define XDETECT_H_
#include "config.h"
int xdet_start(void);
void xdet_stop(void);
int xdet_get_fd(void);
int handle_xdet_events(fd_set *rset);
#endif /* XDETECT_H_ */
spacenavd-0.6/src/event.h 0000644 0001750 0001750 00000003147 12127374572 015267 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas
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 .
*/
#ifndef EVENT_H_
#define EVENT_H_
#include "config.h"
#include
#include "dev.h"
enum {
EVENT_MOTION,
EVENT_BUTTON /* includes both press and release */
};
struct event_motion {
int type;
int x, y, z;
int rx, ry, rz;
unsigned int period;
int *data;
};
struct event_button {
int type;
int press;
int bnum;
};
typedef union spnav_event {
int type;
struct event_motion motion;
struct event_button button;
} spnav_event;
enum {
INP_MOTION,
INP_BUTTON,
INP_FLUSH
};
struct dev_input {
int type;
struct timeval tm;
int idx;
int val;
};
void remove_dev_event(struct device *dev);
void process_input(struct device *dev, struct dev_input *inp);
/* non-zero if the last processed motion event was in the deadzone */
int in_deadzone(struct device *dev);
/* dispatches the last event */
void repeat_last_event(struct device *dev);
#endif /* EVENT_H_ */
spacenavd-0.6/src/serial/ 0000755 0001750 0001750 00000000000 12374256237 015250 5 ustar nuclear nuclear spacenavd-0.6/src/serial/sballserial.c 0000644 0001750 0001750 00000010643 11403040606 017674 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
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
#include
#include
#include
#include
#include
#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 */
spacenavd-0.6/src/serial/sball.c 0000644 0001750 0001750 00000047422 11403040606 016501 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
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
#include
#include
#include
#include
#include "sball.h"
#include "sballserial.h"
struct event {
struct dev_input data;
struct event *next;
};
static struct event *ev_free_list;
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 {
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;
}
}
}
}
spacenavd-0.6/src/serial/sballserial.h 0000644 0001750 0001750 00000005765 11403040606 017712 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
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);
spacenavd-0.6/src/serial/sball.h 0000644 0001750 0001750 00000016245 11403040606 016505 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
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
spacenavd-0.6/src/dev.c 0000644 0001750 0001750 00000012253 12305113415 014676 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2013 John Tsiombikas
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 .
*/
#include "config.h"
#include
#include
#include
#include
#include "dev.h"
#include "dev_usb.h"
#include "dev_serial.h"
#include "event.h" /* remove pending events upon device removal */
#include "spnavd.h"
static struct device *add_device(void);
static struct device *dev_path_in_use(char const * dev_path);
static int match_usbdev(const struct usb_device_info *devinfo);
static struct device *dev_list = NULL;
int init_devices(void)
{
struct device *dev;
int i, device_added = 0;
struct usb_device_info *usblist, *usbdev;
/* try to open a serial device if specified in the config file */
if(cfg.serial_dev[0]) {
if(!dev_path_in_use(cfg.serial_dev)) {
dev = add_device();
strcpy(dev->path, cfg.serial_dev);
if(open_dev_serial(dev) == -1) {
remove_device(dev);
} else {
strcpy(dev->name, "serial device");
printf("using device: %s\n", cfg.serial_dev);
device_added++;
}
}
}
/* detect any supported USB devices */
usblist = find_usb_devices(match_usbdev);
usbdev = usblist;
while(usbdev) {
for(i=0; inum_devfiles; i++) {
if((dev = dev_path_in_use(usbdev->devfiles[i]))) {
if(verbose) {
fprintf(stderr, "already using device: %s (%s)\n", dev->name, dev->path);
}
break;
}
dev = add_device();
strcpy(dev->path, usbdev->devfiles[i]);
if(open_dev_usb(dev) == -1) {
remove_device(dev);
} else {
printf("using device: %s\n", dev->path);
device_added++;
break;
}
}
usbdev = usbdev->next;
}
free_usb_devices_list(usblist);
if(!device_added) {
fprintf(stderr, "failed to find any supported devices\n");
return -1;
}
return 0;
}
static struct device *add_device(void)
{
struct device *dev;
if(!(dev = malloc(sizeof *dev))) {
return 0;
}
memset(dev, 0, sizeof *dev);
printf("adding device.\n");
dev->fd = -1;
dev->next = dev_list;
dev_list = dev;
return dev_list;
}
void remove_device(struct device *dev)
{
struct device dummy;
struct device *iter;
printf("removing device: %s\n", dev->name);
dummy.next = dev_list;
iter = &dummy;
while(iter->next) {
if(iter->next == dev) {
iter->next = dev->next;
break;
}
iter = iter->next;
}
dev_list = dummy.next;
remove_dev_event(dev);
if(dev->close) {
dev->close(dev);
}
free(dev);
}
static struct device *dev_path_in_use(char const *dev_path)
{
struct device *iter = dev_list;
while(iter) {
if(strcmp(iter->path, dev_path) == 0) {
return iter;
}
iter = iter->next;
}
return 0;
}
int get_device_fd(struct device *dev)
{
return dev ? dev->fd : -1;
}
int get_device_index(struct device *dev)
{
struct device *iter = dev_list;
int index = 0;
while(iter) {
if(dev == iter) {
return index;
}
index++;
iter = iter->next;
}
return -1;
}
int read_device(struct device *dev, struct dev_input *inp)
{
if(dev->read == NULL) {
return -1;
}
return dev->read(dev, inp);
}
void set_device_led(struct device *dev, int state)
{
if(dev->set_led) {
dev->set_led(dev, state);
}
}
struct device *get_devices(void)
{
return dev_list;
}
static int devid_list[][2] = {
/* 3Dconnexion devices */
{0x46d, 0xc603}, /* spacemouse plus XT */
{0x46d, 0xc605}, /* cadman */
{0x46d, 0xc606}, /* spacemouse classic */
{0x46d, 0xc621}, /* spaceball 5000 */
{0x46d, 0xc623}, /* space traveller */
{0x46d, 0xc625}, /* space pilot */
{0x46d, 0xc626}, /* space navigator */
{0x46d, 0xc627}, /* space explorer */
{0x46d, 0xc628}, /* space navigator for notebooks*/
{0x46d, 0xc629}, /* space pilot pro*/
{0x46d, 0xc62b}, /* space mouse pro*/
{0x46d, 0xc640}, /* nulooq */
{-1, -1}
};
static int match_usbdev(const struct usb_device_info *devinfo)
{
int i;
/* if it's a 3Dconnexion device match it immediately */
if((devinfo->name && strstr(devinfo->name, "3Dconnexion"))) {
return 1;
}
/* match any device in the devid_list */
if(devinfo->vendorid != -1 && devinfo->productid != -1) {
for(i=0; devid_list[i][0] > 0; i++) {
if(devinfo->vendorid == devid_list[i][0] && devinfo->productid == devid_list[i][1]) {
return 1;
}
}
}
/* match any joystick devices listed in the config file */
for(i=0; ivendorid &&
(unsigned int)cfg.devid[i][1] == devinfo->productid) {
return 1;
}
if(cfg.devname[i] && devinfo->name && strcmp(cfg.devname[i], devinfo->name) == 0) {
return 1;
}
}
return 0; /* no match */
}
spacenavd-0.6/src/dev_serial.c 0000644 0001750 0001750 00000002674 12127374572 016262 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas
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 .
*/
#include "config.h"
#include "dev_serial.h"
#include "dev.h"
#include "event.h"
#include "serial/sball.h"
static void close_dev_serial(struct device *dev);
static int read_dev_serial(struct device *dev, struct dev_input *inp);
int open_dev_serial(struct device *dev)
{
if(!(dev->data = sball_open(dev->path))) {
return -1;
}
dev->fd = sball_get_fd(dev->data);
dev->close = close_dev_serial;
dev->read = read_dev_serial;
return 0;
}
static void close_dev_serial(struct device *dev)
{
if(dev->data) {
sball_close(dev->data);
}
dev->data = 0;
}
static int read_dev_serial(struct device *dev, struct dev_input *inp)
{
if(!dev->data || !sball_get_input(dev->data, inp)) {
return -1;
}
return 0;
}
spacenavd-0.6/src/client.c 0000644 0001750 0001750 00000006230 12127374572 015413 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
*/
#include "config.h"
#include
#include
#include "client.h"
#ifdef USE_X11
#include
#include
#endif
struct client {
int type;
int sock; /* UNIX domain socket */
#ifdef USE_X11
Window win; /* X11 client window */
#endif
float sens; /* sensitivity */
int dev_idx; /* device index */
struct client *next;
};
static struct client *client_list = NULL;
static struct client *client_iter; /* iterator (used by first/next calls) */
/* add a client to the list
* cdata points to the socket fd for new-protocol clients, or the
* window XID for clients talking to us through the magellan protocol
*/
struct client *add_client(int type, void *cdata)
{
struct client *client;
#ifdef USE_X11
if(!cdata || (type != CLIENT_UNIX && type != CLIENT_X11))
#else
if(!cdata || type != CLIENT_UNIX)
#endif
{
return 0;
}
if(!(client = malloc(sizeof *client))) {
return 0;
}
client->type = type;
if(type == CLIENT_UNIX) {
client->sock = *(int*)cdata;
#ifdef USE_X11
} else {
client->win = *(Window*)cdata;
#endif
}
client->sens = 1.0f;
client->dev_idx = 0; /* default/first device */
if(client_list == NULL) {
client->next = NULL;
return (client_list = client);
}
client->next = client_list;
client_list = client;
return client;
}
void remove_client(struct client *client)
{
struct client *iter = client_list;
if(iter == NULL)
return;
if(iter == client) {
client_list = iter->next;
free(iter);
if((iter = client_list) == NULL)
return;
}
while(iter->next) {
if(iter->next == client) {
struct client *tmp = iter->next;
iter->next = tmp->next;
free(tmp);
} else {
iter = iter->next;
}
}
}
int get_client_type(struct client *client)
{
return client->type;
}
int get_client_socket(struct client *client)
{
return client->sock;
}
#ifdef USE_X11
Window get_client_window(struct client *client)
{
return client->win;
}
#endif
void set_client_sensitivity(struct client *client, float sens)
{
client->sens = sens;
}
float get_client_sensitivity(struct client *client)
{
return client->sens;
}
void set_client_device_index(struct client *client, int dev_idx)
{
client->dev_idx = dev_idx;
}
int get_client_device_index(struct client *client)
{
return client->dev_idx;
}
struct client *first_client(void)
{
return (client_iter = client_list);
}
struct client *next_client(void)
{
if(client_iter)
client_iter = client_iter->next;
return client_iter;
}
spacenavd-0.6/src/xdetect_linux.c 0000644 0001750 0001750 00000007155 12162700004 017001 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2010 John Tsiombikas
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 .
*/
#ifdef __linux__
#include "config.h"
#ifdef USE_X11
#include
#include
#include
#include
#include
#include
#include
#include
#include "proto_x11.h"
#include "spnavd.h"
/* TODO implement fallback to polling if inotify is not available */
static int try_xconnect(void);
static int fd = -1;
static int watch_tmp = -1, watch_x11 = -1;
int xdet_start(void)
{
if((fd = inotify_init()) == -1) {
perror("failed to create inotify queue");
return -1;
}
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
if((watch_x11 = inotify_add_watch(fd, "/tmp/.X11-unix", IN_CREATE)) == -1) {
if((watch_tmp = inotify_add_watch(fd, "/tmp", IN_CREATE)) == -1) {
perror("failed to watch /tmp for file events");
close(fd);
fd = -1;
return -1;
}
}
if(verbose) {
printf("waiting for the X socket file to appear\n");
}
return fd;
}
/* this is called by init_x11 if it's successful */
void xdet_stop(void)
{
if(fd != -1) {
if(verbose) {
printf("stopping X watch\n");
}
close(fd);
fd = watch_tmp = watch_x11 = -1;
}
}
int xdet_get_fd(void)
{
return fd;
}
int handle_xdet_events(fd_set *rset)
{
char buf[512];
struct inotify_event *ev = (struct inotify_event*)buf;
ssize_t res;
if(fd == -1 || !FD_ISSET(fd, rset)) {
return -1;
}
for(;;) {
if((res = read(fd, buf, sizeof buf)) <= 0) {
if(res == 0) {
/* kernels before 2.6.14 returned 0 for not enough space */
errno = EINVAL;
}
if(errno == EINTR) continue;
if(errno != EAGAIN) {
perror("failed to read inotify event");
}
return -1;
}
if(ev->wd == watch_tmp) {
if(watch_x11 != -1) {
inotify_rm_watch(fd, watch_tmp);
continue;
}
if(ev->len > 0 && strcmp(ev->name, ".X11-unix") == 0) {
if((watch_x11 = inotify_add_watch(fd, "/tmp/.X11-unix", IN_CREATE)) == -1) {
perror("failed to add /tmp/.X11-unix to the watch queue");
continue;
}
if(try_xconnect() == 0) {
return 0;
}
}
} else if(ev->wd == watch_x11) {
char *dpystr, sock_file[64];
int dpynum = 0;
if((dpystr = getenv("DISPLAY"))) {
char *tmp = strchr(dpystr, ':');
if(tmp && isdigit(tmp[1])) {
dpynum = atoi(tmp + 1);
}
}
sprintf(sock_file, "X%d", dpynum);
if(ev->len > 0 && strcmp(ev->name, sock_file) == 0) {
if(verbose) {
printf("found X socket, will now attempt to connect to the X server\n");
}
if(try_xconnect() == 0) {
return 0;
}
fprintf(stderr, "found X socket yet failed to connect\n");
}
}
}
return -1;
}
static int try_xconnect(void)
{
int i;
/* poll for approximately 15 seconds (well a bit more than that) */
for(i=0; i<15; i++) {
sleep(1);
if(init_x11() != -1) {
return 0; /* success */
}
}
return -1;
}
#endif /* USE_X11 */
#else
int spacenavd_xdetect_linux_shut_up_empty_source_warning;
#endif /* __linux__ */
spacenavd-0.6/src/kbemu.h 0000644 0001750 0001750 00000001720 11751134441 015233 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2012 John Tsiombikas
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 .
*/
#ifndef KBEMU_H_
#define KBEMU_H_
#include
#include
void kbemu_set_display(Display *dpy);
KeySym kbemu_keysym(const char *str);
void send_kbevent(KeySym key, int press);
#endif /* KBEMU_H_ */
spacenavd-0.6/src/spnavd.c 0000644 0001750 0001750 00000017065 12273205246 015431 0 ustar nuclear nuclear /*
spacenavd - a free software replacement driver for 6dof space-mice.
Copyright (C) 2007-2013 John Tsiombikas
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 .
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "spnavd.h"
#include "dev.h"
#include "hotplug.h"
#include "client.h"
#include "proto_unix.h"
#ifdef USE_X11
#include "proto_x11.h"
#endif
static void cleanup(void);
static void daemonize(void);
static int write_pid_file(void);
static int find_running_daemon(void);
static void handle_events(fd_set *rset);
static void sig_handler(int s);
int main(int argc, char **argv)
{
int i, pid, ret, become_daemon = 1;
for(i=1; i max_fd) max_fd = fd;
}
dev = dev->next;
}
if((fd = get_hotplug_fd()) != -1) {
FD_SET(fd, &rset);
if(fd > max_fd) max_fd = fd;
}
/* the UNIX domain socket listening for connections */
if((fd = get_unix_socket()) != -1) {
FD_SET(fd, &rset);
if(fd > max_fd) max_fd = fd;
}
/* all the UNIX socket clients */
client_iter = first_client();
while(client_iter) {
if(get_client_type(client_iter) == CLIENT_UNIX) {
int s = get_client_socket(client_iter);
assert(s >= 0);
FD_SET(s, &rset);
if(s > max_fd) max_fd = s;
}
client_iter = next_client();
}
/* and the X server socket */
#ifdef USE_X11
if((fd = get_x11_socket()) != -1) {
FD_SET(fd, &rset);
if(fd > max_fd) max_fd = fd;
}
#endif
do {
/* if there is at least one device out of the deadzone and repeat is enabled
* wait for only as long as specified in cfg.repeat_msec
*/
struct timeval tv, *timeout = 0;
if(cfg.repeat_msec >= 0) {
dev = get_devices();
while(dev) {
if(is_device_valid(dev) && !in_deadzone(dev)) {
tv.tv_sec = cfg.repeat_msec / 1000;
tv.tv_usec = cfg.repeat_msec % 1000;
timeout = &tv;
break;
}
dev = dev->next;
}
}
ret = select(max_fd + 1, &rset, 0, 0, timeout);
} while(ret == -1 && errno == EINTR);
if(ret > 0) {
handle_events(&rset);
} else {
if(cfg.repeat_msec >= 0) {
dev = get_devices();
while(dev) {
if(!in_deadzone(dev)) {
repeat_last_event(dev);
}
dev = dev->next;
}
}
}
}
return 0; /* unreachable */
}
static void cleanup(void)
{
struct device *dev;
#ifdef USE_X11
close_x11(); /* call to avoid leaving garbage in the X server's root windows */
#endif
close_unix();
shutdown_hotplug();
dev = get_devices();
while(dev) {
struct device *tmp = dev;
dev = dev->next;
remove_device(tmp);
}
remove(PIDFILE);
}
static void daemonize(void)
{
int i, pid;
if((pid = fork()) == -1) {
perror("failed to fork");
exit(1);
} else if(pid) {
exit(0);
}
setsid();
chdir("/");
/* redirect standard input/output/error */
for(i=0; i<3; i++) {
close(i);
}
open("/dev/zero", O_RDONLY);
if(open(LOGFILE, O_WRONLY | O_CREAT | O_TRUNC, 0644) == -1) {
open("/dev/null", O_WRONLY);
}
dup(1);
setvbuf(stdout, 0, _IOLBF, 0);
setvbuf(stderr, 0, _IONBF, 0);
}
static int write_pid_file(void)
{
FILE *fp;
int pid = getpid();
if(!(fp = fopen(PIDFILE, "w"))) {
return -1;
}
fprintf(fp, "%d\n", pid);
fclose(fp);
return 0;
}
static int find_running_daemon(void)
{
FILE *fp;
int s, pid;
struct sockaddr_un addr;
/* try to open the pid-file */
if(!(fp = fopen(PIDFILE, "r"))) {
return -1;
}
if(fscanf(fp, "%d\n", &pid) != 1) {
fclose(fp);
return -1;
}
fclose(fp);
/* make sure it's not just a stale pid-file */
if((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
return -1;
}
memset(&addr, 0, sizeof addr);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCK_NAME, sizeof addr.sun_path);
if(connect(s, (struct sockaddr*)&addr, sizeof addr) == -1) {
close(s);
return -1;
}
/* managed to connect alright, it's running... */
close(s);
return pid;
}
static void handle_events(fd_set *rset)
{
int dev_fd, hotplug_fd;
struct device *dev;
struct dev_input inp;
/* handle anything coming through the UNIX socket */
handle_uevents(rset);
#ifdef USE_X11
/* handle any X11 events (magellan protocol) */
handle_xevents(rset);
#endif
/* finally read any pending device input data */
dev = get_devices();
while(dev) {
/* keep the next pointer because read_device can potentially destroy
* the device node if the read fails.
*/
struct device *next = dev->next;
if((dev_fd = get_device_fd(dev)) != -1 && FD_ISSET(dev_fd, rset)) {
/* read an event from the device ... */
while(read_device(dev, &inp) != -1) {
/* ... and process it, possibly dispatching a spacenav event to clients */
process_input(dev, &inp);
}
}
dev = next;
}
if((hotplug_fd = get_hotplug_fd()) != -1) {
if(FD_ISSET(hotplug_fd, rset)) {
handle_hotplug();
}
}
}
/* signals usr1 & usr2 are sent by the spnav_x11 script to start/stop the
* daemon's connection to the X server.
*/
static void sig_handler(int s)
{
int prev_led = cfg.led;
switch(s) {
case SIGHUP:
read_cfg("/etc/spnavrc", &cfg);
if(cfg.led != prev_led) {
struct device *dev = get_devices();
while(dev) {
if(is_device_valid(dev)) {
if(verbose) {
printf("turn led %s, device: %s\n", cfg.led ? "on": "off", dev->name);
}
set_device_led(dev, cfg.led);
}
dev = dev->next;
}
}
break;
case SIGSEGV:
fprintf(stderr, "Segmentation fault caught, trying to exit gracefully\n");
case SIGINT:
case SIGTERM:
exit(0);
#ifdef USE_X11
case SIGUSR1:
init_x11();
break;
case SIGUSR2:
close_x11();
break;
#endif
default:
break;
}
}
spacenavd-0.6/src/magellan/ 0000755 0001750 0001750 00000000000 12374256237 015551 5 ustar nuclear nuclear spacenavd-0.6/src/magellan/smag_detect.h 0000644 0001750 0001750 00000001627 12043026343 020171 0 ustar nuclear nuclear /*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas
Copyright (C) 2010 Thomas Anderson
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 .
*/
#ifndef SMAG_DETECT_H_
#define SMAG_DETECT_H_
int smag_detect(const char *fname, char *buf, int sz);
#endif /* SMAG_DETECT_H_ */
spacenavd-0.6/src/magellan/smag.c 0000644 0001750 0001750 00000024466 12043026343 016642 0 ustar nuclear nuclear /*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas
Copyright (C) 2010 Thomas Anderson
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 .
*/
#include
#include
#include
#include
#include
#include
#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 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;
}
spacenavd-0.6/src/magellan/smag_event.h 0000644 0001750 0001750 00000002011 12043026343 020026 0 ustar nuclear nuclear /*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas
Copyright (C) 2010 Thomas Anderson
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 .
*/
#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_ */
spacenavd-0.6/src/magellan/serialconstants.h 0000644 0001750 0001750 00000001622 12043026343 021121 0 ustar nuclear nuclear
/*
serialmagellan - decoding serial magellan spaceball data.
Copyright (C) 2010 Thomas Anderson
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 .
*/
#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
spacenavd-0.6/src/magellan/smag.h 0000644 0001750 0001750 00000002030 12043026343 016626 0 ustar nuclear nuclear /*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas
Copyright (C) 2010 Thomas Anderson
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 .
*/
#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);
spacenavd-0.6/src/magellan/smag_comm.c 0000644 0001750 0001750 00000006204 12147167510 017652 0 ustar nuclear nuclear /*
serial magellan device support for spacenavd
Copyright (C) 2012 John Tsiombikas
Copyright (C) 2010 Thomas Anderson
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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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