Removing a bunch of "static" declarations from the "fgPlatform" function definitions...
[freeglut] / src / Common / freeglut_input_devices.c
1 /*\r
2  * freeglut_input_devices.c\r
3  *\r
4  * Handles miscellaneous input devices via direct serial-port access.\r
5  * Proper X11 XInput device support is not yet supported.\r
6  * Also lacks Mac support.\r
7  *\r
8  * Written by Joe Krahn <krahn@niehs.nih.gov> 2005\r
9  *\r
10  * Copyright (c) 2005 Stephen J. Baker. All Rights Reserved.\r
11  *\r
12  * Permission is hereby granted, free of charge, to any person obtaining a\r
13  * copy of this software and associated documentation files (the "Software"),\r
14  * to deal in the Software without restriction, including without limitation\r
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
16  * and/or sell copies of the Software, and to permit persons to whom the\r
17  * Software is furnished to do so, subject to the following conditions:\r
18  *\r
19  * The above copyright notice and this permission notice shall be included\r
20  * in all copies or substantial portions of the Software.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
25  * PAWEL W. OLSZTA OR STEPHEN J. BAKER BE LIABLE FOR ANY CLAIM, DAMAGES OR\r
26  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\r
27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
28  * DEALINGS IN THE SOFTWARE.\r
29  */\r
30 \r
31 #ifdef HAVE_CONFIG_H\r
32 #    include "config.h"\r
33 #endif\r
34 \r
35 #include <GL/freeglut.h>\r
36 #include "freeglut_internal.h"\r
37 \r
38 #if TARGET_HOST_POSIX_X11\r
39 #ifdef HAVE_ERRNO_H\r
40 #include <errno.h>\r
41 #endif\r
42 #include <sys/ioctl.h>\r
43 #include <stdio.h>\r
44 #include <stdlib.h>\r
45 #include <string.h>\r
46 #include <termios.h>\r
47 #include <fcntl.h>\r
48 \r
49 struct {\r
50    int fd;\r
51    struct termios termio, termio_save;\r
52 } _serialport;\r
53 \r
54 #endif\r
55 \r
56 typedef struct _serialport SERIALPORT;\r
57 \r
58 \r
59 /********************* Dialbox definitions ***********************/\r
60 \r
61 #define DIAL_NUM_VALUATORS 8\r
62 \r
63 /* dial parser state machine states */\r
64 #define DIAL_NEW                (-1)\r
65 #define DIAL_WHICH_DEVICE       0\r
66 #define DIAL_VALUE_HIGH         1\r
67 #define DIAL_VALUE_LOW          2\r
68 \r
69 /* dial/button box commands */\r
70 #define DIAL_INITIALIZE                 0x20\r
71 #define DIAL_SET_LEDS                   0x75\r
72 #define DIAL_SET_TEXT                   0x61\r
73 #define DIAL_SET_AUTO_DIALS             0x50\r
74 #define DIAL_SET_AUTO_DELTA_DIALS       0x51\r
75 #define DIAL_SET_FILTER                 0x53\r
76 #define DIAL_SET_BUTTONS_MOM_TYPE       0x71\r
77 #define DIAL_SET_AUTO_MOM_BUTTONS       0x73\r
78 #define DIAL_SET_ALL_LEDS               0x4b\r
79 #define DIAL_CLEAR_ALL_LEDS             0x4c\r
80 \r
81 /* dial/button box replies and events */\r
82 #define DIAL_INITIALIZED        0x20\r
83 #define DIAL_BASE               0x30\r
84 #define DIAL_DELTA_BASE         0x40\r
85 #define DIAL_PRESS_BASE         0xc0\r
86 #define DIAL_RELEASE_BASE       0xe0\r
87 \r
88 /* macros to determine reply type */\r
89 #define IS_DIAL_EVENT(ch)       (((ch)>=DIAL_BASE)&&((ch)<DIAL_BASE+DIAL_NUM_VALUATORS))\r
90 #define IS_KEY_PRESS(ch)        (((ch)>=DIAL_PRESS_BASE)&&((ch)<DIAL_PRESS_BASE+DIAL_NUM_BUTTONS))\r
91 #define IS_KEY_RELEASE(ch)      (((ch)>=DIAL_RELEASE_BASE)&&((ch)<DIAL_RELEASE_BASE+DIAL_NUM_BUTTONS))\r
92 #define IS_INIT_EVENT(ch)       ((ch)==DIAL_INITIALIZED)\r
93 \r
94 /*****************************************************************/\r
95 \r
96 extern SERIALPORT *serial_open ( const char *device );\r
97 extern void serial_close ( SERIALPORT *port );\r
98 extern int serial_getchar ( SERIALPORT *port );\r
99 extern int serial_putchar ( SERIALPORT *port, unsigned char ch );\r
100 extern void serial_flush ( SERIALPORT *port );\r
101 \r
102 extern void fgPlatformRegisterDialDevice ( const char *dial_device );\r
103 static void send_dial_event(int dial, int value);\r
104 static void poll_dials(int id);\r
105 \r
106 /* local variables */\r
107 static SERIALPORT *dialbox_port=NULL;\r
108 \r
109 /*****************************************************************/\r
110 \r
111 /*\r
112  * Implementation for glutDeviceGet(GLUT_HAS_DIAL_AND_BUTTON_BOX)\r
113  */\r
114 int fgInputDeviceDetect( void )\r
115 {\r
116     fgInitialiseInputDevices ();\r
117 \r
118     if ( !dialbox_port )\r
119         return 0;\r
120 \r
121     if ( !fgState.InputDevsInitialised )\r
122         return 0;\r
123 \r
124     return 1;\r
125 }\r
126 \r
127 /*\r
128  * Try initializing the input device(s)\r
129  */\r
130 #if TARGET_HOST_POSIX_X11\r
131 void fgPlatformRegisterDialDevice ( const char *dial_device )\r
132 {\r
133 }\r
134 #endif\r
135 \r
136 void fgInitialiseInputDevices ( void )\r
137 {\r
138     if( !fgState.InputDevsInitialised )\r
139     {\r
140         const char *dial_device=NULL;\r
141         dial_device = getenv ( "GLUT_DIALS_SERIAL" );\r
142                 fgPlatformRegisterDialDevice ( dial_device );\r
143 \r
144         if ( !dial_device ) return;\r
145         if ( !( dialbox_port = serial_open ( dial_device ) ) ) return;\r
146         serial_putchar(dialbox_port,DIAL_INITIALIZE);\r
147         glutTimerFunc ( 10, poll_dials, 0 );\r
148         fgState.InputDevsInitialised = GL_TRUE;\r
149     }\r
150 }\r
151 \r
152 /*\r
153  *\r
154  */\r
155 void fgInputDeviceClose( void )\r
156 {\r
157     if ( fgState.InputDevsInitialised )\r
158     {\r
159         serial_close ( dialbox_port );\r
160         dialbox_port = NULL;\r
161         fgState.InputDevsInitialised = GL_FALSE;\r
162     }\r
163 }\r
164 \r
165 /********************************************************************/\r
166 \r
167 /* Check all windows for dialbox callbacks */\r
168 static void fghcbEnumDialCallbacks ( SFG_Window *window, SFG_Enumerator *enumerator )\r
169 {\r
170     /* Built-in to INVOKE_WCB():  if window->Callbacks[CB_Dials] */\r
171     INVOKE_WCB ( *window,Dials, ( ((int*)enumerator->data)[0], ((int*)enumerator->data)[1]) );\r
172     fgEnumSubWindows ( window, fghcbEnumDialCallbacks, enumerator );\r
173 }\r
174 \r
175 static void send_dial_event ( int num, int value )\r
176 {\r
177     SFG_Enumerator enumerator;\r
178     int data[2];\r
179     data[0] = num;\r
180     data[1] = value;\r
181     enumerator.found = GL_FALSE;\r
182     enumerator.data  =  data;\r
183     fgEnumWindows ( fghcbEnumDialCallbacks, &enumerator );\r
184 }\r
185 \r
186 /********************************************************************/\r
187 static void poll_dials ( int id )\r
188 {\r
189     int data;\r
190     static int dial_state = DIAL_NEW;\r
191     static int dial_which;\r
192     static int dial_value;\r
193     static int dials[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };\r
194 \r
195     if ( !dialbox_port ) return;\r
196 \r
197     while ( (data=serial_getchar(dialbox_port)) != EOF )\r
198     {\r
199         if ( ( dial_state > DIAL_WHICH_DEVICE ) || IS_DIAL_EVENT ( data ) )\r
200         {\r
201             switch ( dial_state )\r
202             {\r
203             case DIAL_WHICH_DEVICE:\r
204                 dial_which = data - DIAL_BASE;\r
205                 dial_state++;\r
206                 break;\r
207             case DIAL_VALUE_HIGH:\r
208                 dial_value = ( data << 8 );\r
209                 dial_state++;\r
210                 break;\r
211             case DIAL_VALUE_LOW:\r
212                 dial_value |= data;\r
213                 if ( dial_value & 0x8000 ) dial_value -= 0x10000;\r
214                 dials[dial_which] = dial_value;\r
215                 send_dial_event ( dial_which + 1, dial_value * 360 / 256 );\r
216                 dial_state = DIAL_WHICH_DEVICE;\r
217                 break;\r
218             default:\r
219                 /* error: Impossible state value! */\r
220                 break;\r
221             }\r
222         }\r
223         else if ( data == DIAL_INITIALIZED )\r
224         {\r
225             fgState.InputDevsInitialised = GL_TRUE;\r
226             dial_state = DIAL_WHICH_DEVICE;\r
227             serial_putchar(dialbox_port,DIAL_SET_AUTO_DIALS);\r
228             serial_putchar(dialbox_port,0xff);\r
229             serial_putchar(dialbox_port,0xff);\r
230         }\r
231         else  /* Unknown data; try flushing. */\r
232             serial_flush(dialbox_port);\r
233     }\r
234 \r
235     glutTimerFunc ( 2, poll_dials, 0 );\r
236 }\r
237 \r
238 \r
239 /******** OS Specific Serial I/O routines *******/\r
240 #if TARGET_HOST_POSIX_X11 /* ==> Linux/BSD/UNIX POSIX serial I/O */\r
241 static SERIALPORT *serial_open ( const char *device )\r
242 {\r
243     int fd;\r
244     struct termios termio;\r
245     SERIALPORT *port;\r
246 \r
247     fd = open(device, O_RDWR | O_NONBLOCK );\r
248     if (fd <0) {\r
249         perror(device);\r
250         return NULL;\r
251     }\r
252 \r
253     port = malloc(sizeof(SERIALPORT));\r
254     memset(port, 0, sizeof(SERIALPORT));\r
255     port->fd = fd;\r
256 \r
257     /* save current port settings */\r
258     tcgetattr(fd,&port->termio_save);\r
259 \r
260     memset(&termio, 0, sizeof(termio));\r
261     termio.c_cflag = CS8 | CREAD | HUPCL ;\r
262     termio.c_iflag = IGNPAR | IGNBRK ;\r
263     termio.c_cc[VTIME]    = 0;   /* inter-character timer */\r
264     termio.c_cc[VMIN]     = 1;   /* block read until 1 chars received, when blocking I/O */\r
265 \r
266     cfsetispeed(&termio, B9600);\r
267     cfsetospeed(&termio, B9600);\r
268     tcsetattr(fd,TCSANOW,&termio);\r
269 \r
270     serial_flush(port);\r
271     return port;\r
272 }\r
273 \r
274 static void serial_close(SERIALPORT *port)\r
275 {\r
276     if (port)\r
277     {\r
278         /* restore old port settings */\r
279         tcsetattr(port->fd,TCSANOW,&port->termio_save);\r
280         close(port->fd);\r
281         free(port);\r
282     }\r
283 }\r
284 \r
285 static int serial_getchar(SERIALPORT *port)\r
286 {\r
287     unsigned char ch;\r
288     if (!port) return EOF;\r
289     if (read(port->fd,&ch,1)) return ch;\r
290     return EOF;\r
291 }\r
292 \r
293 static int serial_putchar(SERIALPORT *port, unsigned char ch){\r
294     if (!port) return 0;\r
295     return write(port->fd,&ch,1);\r
296 }\r
297 \r
298 static void serial_flush ( SERIALPORT *port )\r
299 {\r
300     tcflush ( port->fd, TCIOFLUSH );\r
301 }\r
302 \r
303 #endif\r