From 5bd25a50a0034f0d2f6181811ebfd7d348984156 Mon Sep 17 00:00:00 2001 From: "John F. Fay" Date: Thu, 23 Jun 2005 14:33:02 +0000 Subject: [PATCH] New file for Joe Krahn\'s dials input device git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@638 7f0cb862-5218-0410-a997-914c9d46530a --- src/freeglut_input_devices.c | 381 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100755 src/freeglut_input_devices.c diff --git a/src/freeglut_input_devices.c b/src/freeglut_input_devices.c new file mode 100755 index 0000000..a53a81b --- /dev/null +++ b/src/freeglut_input_devices.c @@ -0,0 +1,381 @@ +/* + * freeglut_input_devices.c + * + * Handles miscellaneous input devices via direct serial-port access. + * Proper X11 XInput device support is not yet supported. + * Also lacks Mac support. + * + * Written by Joe Krahn 2005 + * + * Copyright (c) 2005 Stephen J. Baker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA OR STEPHEN J. BAKER BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "freeglut_internal.h" + +#if TARGET_HOST_UNIX_X11 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + int fd; + struct termios termio, termio_save; +} SERIALPORT; + +#elif TARGET_HOST_WIN32 +#include +#include +typedef struct { + HANDLE fh; + COMMTIMEOUTS timeouts_save; + DCB dcb_save; +} SERIALPORT; + +#endif + +/********************* Dialbox definitions ***********************/ + +#define DIAL_NUM_VALUATORS 8 + + /* dial parser state machine states */ +#define DIAL_NEW -1 +#define DIAL_WHICH_DEVICE 0 +#define DIAL_VALUE_HIGH 1 +#define DIAL_VALUE_LOW 2 + + /* dial/button box commands */ +#define DIAL_INITIALIZE 0x20 +#define DIAL_SET_LEDS 0x75 +#define DIAL_SET_TEXT 0x61 +#define DIAL_SET_AUTO_DIALS 0x50 +#define DIAL_SET_AUTO_DELTA_DIALS 0x51 +#define DIAL_SET_FILTER 0x53 +#define DIAL_SET_BUTTONS_MOM_TYPE 0x71 +#define DIAL_SET_AUTO_MOM_BUTTONS 0x73 +#define DIAL_SET_ALL_LEDS 0x4b +#define DIAL_CLEAR_ALL_LEDS 0x4c + + /* dial/button box replies and events */ +#define DIAL_INITIALIZED 0x20 +#define DIAL_BASE 0x30 +#define DIAL_DELTA_BASE 0x40 +#define DIAL_PRESS_BASE 0xc0 +#define DIAL_RELEASE_BASE 0xe0 + + /* macros to determine reply type */ +#define IS_DIAL_EVENT(ch) (((ch)>=DIAL_BASE)&&((ch)=DIAL_PRESS_BASE)&&((ch)=DIAL_RELEASE_BASE)&&((ch)Callbacks[CB_Dials] */ + INVOKE_WCB ( *window,Dials, ( ((int*)enumerator->data)[0], ((int*)enumerator->data)[1]) ); + fgEnumSubWindows ( window, fghcbEnumDialCallbacks, enumerator ); +} + +static void send_dial_event ( int num, int value ) +{ + SFG_Enumerator enumerator; + int data[2]; + data[0] = num; + data[1] = value; + enumerator.found = GL_FALSE; + enumerator.data = data; + fgEnumWindows ( fghcbEnumDialCallbacks, &enumerator ); +} + +/********************************************************************/ +static void poll_dials ( int id ) +{ + int data; + static int dial_state = DIAL_NEW; + static int dial_which; + static int dial_value; + static int dials[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + if ( !dialbox_port ) return; + + while ( (data=serial_getchar(dialbox_port)) != EOF ) + { + if ( ( dial_state > DIAL_WHICH_DEVICE ) || IS_DIAL_EVENT ( data ) ) + { + switch ( dial_state ) + { + case DIAL_WHICH_DEVICE: + dial_which = data - DIAL_BASE; + dial_state++; + break; + case DIAL_VALUE_HIGH: + dial_value = ( data << 8 ); + dial_state++; + break; + case DIAL_VALUE_LOW: + dial_value |= data; + if ( dial_value & 0x8000 ) dial_value -= 0x10000; + dials[dial_which] = dial_value; + send_dial_event ( dial_which + 1, dial_value * 360 / 256 ); + dial_state = DIAL_WHICH_DEVICE; + break; + default: + /* error: Impossible state value! */ + break; + } + } + else if ( data == DIAL_INITIALIZED ) + { + fgState.InputDevsInitialised = GL_TRUE; + dial_state = DIAL_WHICH_DEVICE; + serial_putchar(dialbox_port,DIAL_SET_AUTO_DIALS); + serial_putchar(dialbox_port,0xff); + serial_putchar(dialbox_port,0xff); + } + else /* Unknown data; try flushing. */ + serial_flush(dialbox_port); + } + + glutTimerFunc ( 2, poll_dials, 0 ); +} + + +/******** OS Specific Serial I/O routines *******/ +#if TARGET_HOST_UNIX_X11 /* ==> Linux/BSD/UNIX POSIX serial I/O */ +static SERIALPORT *serial_open ( const char *device ) +{ + int fd; + struct termios termio; + SERIALPORT *port; + + fd = open(device, O_RDWR | O_NONBLOCK ); + if (fd <0) { + perror(device); + return NULL; + } + + port = malloc(sizeof(SERIALPORT)); + memset(port, 0, sizeof(SERIALPORT)); + port->fd = fd; + + /* save current port settings */ + tcgetattr(fd,&port->termio_save); + + memset(&termio, 0, sizeof(termio)); + cfmakeraw(&termio); + termio.c_cflag = CS8 | CREAD | HUPCL ; + termio.c_iflag = IGNPAR | IGNBRK ; + termio.c_cc[VTIME] = 0; /* inter-character timer */ + termio.c_cc[VMIN] = 1; /* block read until 1 chars received, when blocking I/O */ + + cfsetispeed(&termio, B9600); + cfsetospeed(&termio, B9600); + tcsetattr(fd,TCSANOW,&termio); + + serial_flush(port); + return port; +} + +static void serial_close(SERIALPORT *port) +{ + if (port) + { + /* restore old port settings */ + tcsetattr(port->fd,TCSANOW,&port->termio_save); + close(port->fd); + free(port); + } +} + +static int serial_getchar(SERIALPORT *port) +{ + unsigned char ch; + if (!port) return EOF; + if (read(port->fd,&ch,1)) return ch; + return EOF; +} + +static int serial_putchar(SERIALPORT *port, unsigned char ch){ + if (!port) return 0; + return write(port->fd,&ch,1); +} + +static void serial_flush ( SERIALPORT *port ) +{ + tcflush ( port->fd, TCIOFLUSH ); +} + +#elif TARGET_HOST_WIN32 + +static SERIALPORT *serial_open(const char *device){ + HANDLE fh; + DCB dcb={sizeof(DCB)}; + COMMTIMEOUTS timeouts; + SERIALPORT *port; + + fh = CreateFile(device,GENERIC_READ|GENERIC_WRITE,0,NULL, + OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if (!fh) return NULL; + + port = malloc(sizeof(SERIALPORT)); + ZeroMemory(port, sizeof(SERIALPORT)); + port->fh = fh; + + /* save current port settings */ + GetCommState(fh,&port->dcb_save); + GetCommTimeouts(fh,&port->timeouts_save); + + dcb.DCBlength=sizeof(DCB); + BuildCommDCB("96,n,8,1",&dcb); + SetCommState(fh,&dcb); + + ZeroMemory(&timeouts,sizeof(timeouts)); + timeouts.ReadTotalTimeoutConstant=1; + timeouts.WriteTotalTimeoutConstant=1; + SetCommTimeouts(fh,&timeouts); + + serial_flush(port); + + return port; +} + +static void serial_close(SERIALPORT *port){ + if (port){ + /* restore old port settings */ + SetCommState(port->fh,&port->dcb_save); + SetCommTimeouts(port->fh,&port->timeouts_save); + CloseHandle(port->fh); + free(port); + } +} + +static int serial_getchar(SERIALPORT *port){ + DWORD n; + unsigned char ch; + if (!port) return EOF; + if (!ReadFile(port->fh,&ch,1,&n,NULL)) return EOF; + if (n==1) return ch; + return EOF; +} + +static int serial_putchar(SERIALPORT *port, unsigned char ch){ + DWORD n; + if (!port) return 0; + return WriteFile(port->fh,&ch,1,&n,NULL); +} + +static void serial_flush ( SERIALPORT *port ) +{ + FlushFileBuffers(port->fh); +} + +#endif -- 1.7.10.4