setoffs and settext now confirmed working, although setoffs still needs some work...
[PyX52.git] / PyX52.c
blobfb319f1f54da9394f8698ef6e933ed91e56464bd
1 #include <Python.h>
2 #include "structmember.h"
3 #include "datetime.h"
5 #include <time.h>
7 #include <x52pro.h>
9 enum x52pro_buttons
11 X52PRO_BUTTON_TRIGGER1 = 0,
12 X52PRO_BUTTON_FIRE,
13 X52PRO_BUTTON_A,
14 X52PRO_BUTTON_B,
15 X52PRO_BUTTON_C,
16 X52PRO_BUTTON_PINKIE,
17 X52PRO_BUTTON_D,
18 X52PRO_BUTTON_E,
19 X52PRO_BUTTON_T1,
20 X52PRO_BUTTON_T2,
21 X52PRO_BUTTON_T3,
22 X52PRO_BUTTON_T4,
23 X52PRO_BUTTON_T5,
24 X52PRO_BUTTON_T6,
25 X52PRO_BUTTON_TRIGGER2,
26 X52PRO_BUTTON_MOUSE_CLICK,
27 X52PRO_BUTTON_MOUSE_SCROLL_FORWARD,
28 X52PRO_BUTTON_MOUSE_SCROLL_BACK,
29 X52PRO_BUTTON_MOUSE_SCROLL_CLICK,
30 X52PRO_BUTTON_COOLIE_UP,
31 X52PRO_BUTTON_COOLIE_RIGHT,
32 X52PRO_BUTTON_COOLIE_DOWN,
33 X52PRO_BUTTON_COOLIE_LEFT,
34 X52PRO_BUTTON_THROTTLEHAT_BACK,
35 X52PRO_BUTTON_THROTTLEHAT_RIGHT,
36 X52PRO_BUTTON_THROTTLEHAT_FORWARD,
37 X52PRO_BUTTON_THROTTLEHAT_LEFT,
38 X52PRO_BUTTON_MODE1,
39 X52PRO_BUTTON_MODE2,
40 X52PRO_BUTTON_MODE3,
41 X52PRO_BUTTON_I,
42 X52PRO_BUTTON_MFD_FUNCTION,
43 X52PRO_BUTTON_MFD_STARTSTOP,
44 X52PRO_BUTTON_MFD_RESET,
45 X52PRO_BUTTON_MFD_PAGE_UP,
46 X52PRO_BUTTON_MFD_PAGE_DOWN,
47 X52PRO_BUTTON_MFD_SEL_UP,
48 X52PRO_BUTTON_MFD_SEL_DOWN,
49 X52PRO_BUTTON_MFD_SEL
52 typedef struct
54 PyObject_HEAD
55 struct x52 *handle;
56 } PyX52_X52_object;
58 static PyTypeObject PyX52_X52_type;
59 static PyMethodDef PyX52_methods[];
60 static PyMethodDef PyX52_X52_methods[];
62 static PyObject *PyX52_X52_new(PyTypeObject *);
63 static int PyX52_X52_init(PyX52_X52_object *);
64 static void PyX52_X52_dealloc(PyX52_X52_object *);
66 static PyObject *PyX52_X52_gettype(PyX52_X52_object *);
67 static PyObject *PyX52_X52_settext(PyX52_X52_object *, PyObject *, PyObject *);
68 static PyObject *PyX52_X52_setbri(PyX52_X52_object *, PyObject *, PyObject *);
69 static PyObject *PyX52_X52_setled(PyX52_X52_object *, PyObject *, PyObject *);
70 static PyObject *PyX52_X52_settime(PyX52_X52_object *, PyObject *, PyObject *);
71 static PyObject *PyX52_X52_setoffs(PyX52_X52_object *, PyObject *, PyObject *);
72 static PyObject *PyX52_X52_setsecond(PyX52_X52_object *, PyObject *, PyObject *);
73 static PyObject *PyX52_X52_setdate(PyX52_X52_object *, PyObject *, PyObject *);
75 static PyObject *
76 PyX52_X52_new(PyTypeObject *type)
79 PyX52_X52_object *self;
80 self = (PyX52_X52_object *)type->tp_alloc(type, 0);
81 if (self != NULL)
83 self->handle = NULL;
85 return (PyObject *)self;
88 static int
89 PyX52_X52_init(PyX52_X52_object *self)
92 self->handle = x52_init();
93 if (self->handle == NULL)
95 PyErr_SetString(PyExc_RuntimeError, "No compatible joysticks found.");
96 return -1;
98 x52_debug(self->handle, 0);
99 return 0;
102 static void
103 PyX52_X52_dealloc(PyX52_X52_object *self)
106 if (self->handle != NULL)
108 x52_close(self->handle);
110 self->handle = NULL;
111 self->ob_type->tp_free((PyObject *)self);
114 static PyObject *
115 PyX52_X52_gettype(PyX52_X52_object *self)
117 enum x52_type type = x52_gettype(self->handle);
118 return Py_BuildValue("i", type);
121 static PyObject *
122 PyX52_X52_settext(PyX52_X52_object *self, PyObject *args, PyObject *kws)
124 if (x52_gettype(self->handle) == DEV_YOKE)
126 PyErr_SetString(PyExc_RuntimeError, "Cannot call settext on this device.");
127 return NULL;
130 int line_no = 0;
131 PyObject *line = Py_BuildValue("s", "");
133 static char *kwlist[] = {"line_no", "line", NULL};
134 if (!PyArg_ParseTupleAndKeywords(args, kws, "iO", kwlist, &line_no, &line))
135 return NULL;
137 if (line_no < 0 || line_no > 2)
139 PyErr_SetString(PyExc_AttributeError, "line_no must be in the range 0-2.");
140 return NULL;
143 if (!PyString_Check(line))
145 PyErr_SetString(PyExc_AttributeError, "line must be a string or subtype of string.");
146 return NULL;
149 char *line_buf;
150 if (PyString_Size(line) > 0)
152 line_buf = (char *)malloc(sizeof(char)*17);
153 memset(line_buf, '\0', 16);
154 strncpy(line_buf, PyString_AsString(line), 17);
155 } else
157 line_buf = "";
160 if (x52_settext(self->handle, line_no, line_buf, strlen(line_buf)) != 0)
162 PyErr_SetString(PyExc_RuntimeError, "Could not set text.");
163 return NULL;
166 Py_INCREF(Py_None);
167 return Py_None;
170 static PyObject *
171 PyX52_X52_setbri(PyX52_X52_object *self, PyObject *args, PyObject *kws)
173 if (x52_gettype(self->handle) == DEV_YOKE)
175 PyErr_SetString(PyExc_RuntimeError, "Cannot call setbri on this device.");
176 return NULL;
179 int mode = 0;
180 int bri = 0;
182 static char *kwlist[] = {"mode", "bri", NULL};
183 if (!PyArg_ParseTupleAndKeywords(args, kws, "ii", kwlist, &mode, &bri))
184 return NULL;
186 if (mode != 0 && mode != 1)
188 PyErr_SetString(PyExc_AttributeError, "Invalid mode.");
189 return NULL;
192 if (mode == 0 && x52_gettype(self->handle) != DEV_X52PRO)
194 PyErr_SetString(PyExc_AttributeError, "Cannot set LED brightness on this device.");
195 return NULL;
198 if (bri < 0 || bri > 127)
200 PyErr_SetString(PyExc_AttributeError, "Invalid brightness value.");
201 return NULL;
204 if (x52_setbri(self->handle, mode, bri) != 0)
206 PyErr_SetString(PyExc_RuntimeError, "Could not set brightness.");
207 return NULL;
210 Py_INCREF(Py_None);
211 return Py_None;
214 static PyObject *
215 PyX52_X52_setled(PyX52_X52_object *self, PyObject *args, PyObject *kws)
217 if (x52_gettype(self->handle) != DEV_X52PRO)
219 PyErr_SetString(PyExc_RuntimeError, "Cannot call setled on this device.");
220 return NULL;
224 * TODO: Allow passing of a dict with LEDs/states
225 * TODO: Allow abstraction to button colour (i.e. PyX52.X52.buttons["coolie"].orange())
227 int led = 0;
228 int state = 0;
230 static char *kwlist[] = {"led", "state", NULL};
231 if (!PyArg_ParseTupleAndKeywords(args, kws, "ii", kwlist, &led, &state))
232 return NULL;
234 if (state != 0 && state != 1)
236 PyErr_SetString(PyExc_AttributeError, "Invalid LED state.");
237 return NULL;
240 if (led < X52PRO_LED_FIRE || led > X52PRO_LED_IGREEN)
242 PyErr_SetString(PyExc_AttributeError, "Invalid LED ID.");
243 return NULL;
246 if (x52_setled(self->handle, led, state) != 0)
248 PyErr_SetString(PyExc_RuntimeError, "Could not set LED status.");
249 return NULL;
252 Py_INCREF(Py_None);
253 return Py_None;
256 static PyObject *
257 PyX52_X52_settime(PyX52_X52_object *self, PyObject *args, PyObject *kws)
259 int h24 = 1;
261 struct tm *ltime = NULL;
262 time_t t = time(NULL);
263 ltime = gmtime(&t);
265 int hour = ltime->tm_hour;
266 int minute = ltime->tm_min;
268 static char *kwlist[] = {"hour", "minute", "h24", NULL};
269 if (!PyArg_ParseTupleAndKeywords(args, kws, "|iii", kwlist, &hour, &minute, &h24))
270 return NULL;
272 if (x52_settime(self->handle, h24, hour, minute) != 0)
274 PyErr_SetString(PyExc_RuntimeError, "Could not set time.");
275 return NULL;
278 Py_INCREF(Py_None);
279 return Py_None;
282 static PyObject *
283 PyX52_X52_setoffs(PyX52_X52_object *self, PyObject *args, PyObject *kws)
286 * TODO: default to local timezones
288 if (x52_gettype(self->handle) == DEV_YOKE)
290 PyErr_SetString(PyExc_RuntimeError, "Cannot call setoffs on this device.");
291 return NULL;
294 int offs2 = NULL;
295 int offs3 = NULL;
297 static char *kwlist[] = {"offs2", "offs3", NULL};
298 if (!PyArg_ParseTupleAndKeywords(args, kws, "|ii", kwlist, &offs2, &offs3))
299 return NULL;
301 int inv2, inv3 = 0;
302 if (offs2 != NULL)
304 if (offs2 < 0)
306 inv2 = 1;
307 offs2 *= -1;
309 x52_setoffs(self->handle, 0, 1, inv2, offs2);
311 if (offs3 != NULL)
313 if (offs3 < 0)
315 inv3 = 1;
316 offs3 *= -1;
318 x52_setoffs(self->handle, 1, 1, inv3, offs3);
321 Py_INCREF(Py_None);
322 return Py_None;
325 static PyObject *
326 PyX52_X52_setsecond(PyX52_X52_object *self, PyObject *args, PyObject *kws)
328 if (x52_gettype(self->handle) != DEV_YOKE)
330 PyErr_SetString(PyExc_RuntimeError, "Cannot call setsecond on this device.");
331 return NULL;
334 struct tm *ltime;
335 time_t t = time(NULL);
336 gmtime_r(&t, ltime);
338 int second = ltime->tm_sec;
340 static char *kwlist[] = {"second", NULL};
341 if (!PyArg_ParseTupleAndKeywords(args, kws, "|iii", kwlist, &second))
342 return NULL;
344 x52_setsecond(self->handle, second);
346 Py_INCREF(Py_None);
347 return Py_None;
350 static PyObject *
351 PyX52_X52_setdate(PyX52_X52_object *self, PyObject *args, PyObject *kws)
353 if (x52_gettype(self->handle) == DEV_YOKE)
355 PyErr_SetString(PyExc_RuntimeError, "Cannot call setdate on this device.");
356 return NULL;
359 struct tm *ltime;
360 time_t *t;
361 time(t);
362 ltime = gmtime(t);
364 int year = ltime->tm_year - 100;
365 int month = ltime->tm_mon + 1;
366 int day = ltime->tm_mday;
368 static char *kwlist[] = {"year", "month", "day", NULL};
369 if (!PyArg_ParseTupleAndKeywords(args, kws, "|iii", kwlist, &year, &month, &day))
370 return NULL;
372 if (x52_setdate(self->handle, year, month, day) != 0)
374 PyErr_SetString(PyExc_RuntimeError, "Could not set date.");
375 return NULL;
378 Py_INCREF(Py_None);
379 return Py_None;
382 static PyMethodDef PyX52_X52_methods[] = {
383 {"gettype", (PyCFunction)PyX52_X52_gettype, METH_NOARGS, "Get the type of X52 device."},
384 {"settext", (PyCFunction)PyX52_X52_settext, METH_VARARGS | METH_KEYWORDS, "Set the text on the MFD. (X52 and X52 Pro only.)"},
385 {"setbri", (PyCFunction)PyX52_X52_setbri, METH_VARARGS | METH_KEYWORDS, "Set the brightness of either the LEDs or the MFD. (X52 and X52 Pro only.)"},
386 {"setled", (PyCFunction)PyX52_X52_setled, METH_VARARGS | METH_KEYWORDS, "Set an LED's state. (X52 Pro only.)"},
387 {"settime", (PyCFunction)PyX52_X52_settime, METH_VARARGS | METH_KEYWORDS, "Set the MFD display time. If arguments are not supplied, sets the current time in 24 hour format. (X52, X52 Pro and Yoke.)"},
388 {"setoffs", (PyCFunction)PyX52_X52_setoffs, METH_VARARGS | METH_KEYWORDS, "Set the time offset. (X52, X52 Pro.)"},
389 {"setsecond", (PyCFunction)PyX52_X52_setsecond, METH_VARARGS | METH_KEYWORDS, "Set the second. If no arguments are supplied, current second is used. (Yoke only.)"},
390 {"setdate", (PyCFunction)PyX52_X52_setdate, METH_VARARGS | METH_KEYWORDS, "Set the date. If no arguments are supplied, current date is used. (X52, X52 Pro.)"},
391 {NULL, NULL, 0, NULL}
394 static PyTypeObject PyX52_X52_type = {
395 PyObject_HEAD_INIT(NULL)
396 0, /*ob_size*/
397 "PyX52.X52", /*tp_name*/
398 sizeof(PyX52_X52_object), /*tp_basicsize*/
399 0, /*tp_itemsize*/
400 (destructor)PyX52_X52_dealloc, /*tp_dealloc*/
401 0, /*tp_print*/
402 0, /*tp_getattr*/
403 0, /*tp_setattr*/
404 0, /*tp_compare*/
405 0, /*tp_repr*/
406 0, /*tp_as_number*/
407 0, /*tp_as_sequence*/
408 0, /*tp_as_mapping*/
409 0, /*tp_hash */
410 0, /*tp_call*/
411 0, /*tp_str*/
412 0, /*tp_getattro*/
413 0, /*tp_setattro*/
414 0, /*tp_as_buffer*/
415 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
416 "X52 joystick object", /* tp_doc */
417 0, /*tp_traverse*/
418 0, /* tp_clear */
419 0, /* tp_richcompare */
420 0, /* tp_weaklistoffset */
421 0, /* tp_iter */
422 0, /* tp_iternext */
423 PyX52_X52_methods, /* tp_methods */
424 0, /* tp_members */
425 0, /* tp_getset */
426 0, /* tp_base */
427 0, /* tp_dict */
428 0, /* tp_descr_get */
429 0, /* tp_descr_set */
430 0, /* tp_dictoffset */
431 (initproc)PyX52_X52_init, /* tp_init */
432 0, /* tp_alloc */
433 (newfunc)PyX52_X52_new, /* tp_new */
436 static PyMethodDef PyX52_methods[] = {
437 {NULL}
440 #ifndef PyMODINIT_FUNC
441 #define PyMODINIT_FUNC void
442 #endif
443 PyMODINIT_FUNC
444 initPyX52(void)
446 PyObject *m;
448 if (PyType_Ready(&PyX52_X52_type) < 0)
449 return;
451 m = Py_InitModule3("PyX52", PyX52_methods, "Provides functions for handling Saitek X52, X52 Pro and Yoke joystick devices.");
452 if (m == NULL)
453 return;
455 Py_INCREF(&PyX52_X52_type);
456 PyModule_AddObject(m, "X52", (PyObject *) &PyX52_X52_type);
458 PyModule_AddIntConstant(m, "LED_FIRE", X52PRO_LED_FIRE);
459 PyModule_AddIntConstant(m, "LED_ARED", X52PRO_LED_ARED);
460 PyModule_AddIntConstant(m, "LED_AGREEN", X52PRO_LED_AGREEN);
461 PyModule_AddIntConstant(m, "LED_BRED", X52PRO_LED_BRED);
462 PyModule_AddIntConstant(m, "LED_BGREEN", X52PRO_LED_BGREEN);
463 PyModule_AddIntConstant(m, "LED_DRED", X52PRO_LED_DRED);
464 PyModule_AddIntConstant(m, "LED_DGREEN", X52PRO_LED_DGREEN);
465 PyModule_AddIntConstant(m, "LED_ERED", X52PRO_LED_ERED);
466 PyModule_AddIntConstant(m, "LED_EGREEN", X52PRO_LED_EGREEN);
467 PyModule_AddIntConstant(m, "LED_T1RED", X52PRO_LED_T1RED);
468 PyModule_AddIntConstant(m, "LED_T1GREEN", X52PRO_LED_T1GREEN);
469 PyModule_AddIntConstant(m, "LED_T2RED", X52PRO_LED_T2RED);
470 PyModule_AddIntConstant(m, "LED_T2GREEN", X52PRO_LED_T2GREEN);
471 PyModule_AddIntConstant(m, "LED_T3RED", X52PRO_LED_T3RED);
472 PyModule_AddIntConstant(m, "LED_T3GREEN", X52PRO_LED_T3GREEN);
473 PyModule_AddIntConstant(m, "LED_CORED", X52PRO_LED_CORED);
474 PyModule_AddIntConstant(m, "LED_COGREEN", X52PRO_LED_COGREEN);
475 PyModule_AddIntConstant(m, "LED_IRED", X52PRO_LED_IRED);
476 PyModule_AddIntConstant(m, "LED_IGREEN", X52PRO_LED_IGREEN);
478 PyModule_AddIntConstant(m, "BUTTON_TRIGGER1", X52PRO_BUTTON_TRIGGER1);
479 PyModule_AddIntConstant(m, "BUTTON_FIRE", X52PRO_BUTTON_FIRE);
480 PyModule_AddIntConstant(m, "BUTTON_A", X52PRO_BUTTON_A);
481 PyModule_AddIntConstant(m, "BUTTON_B", X52PRO_BUTTON_B);
482 PyModule_AddIntConstant(m, "BUTTON_C", X52PRO_BUTTON_C);
483 PyModule_AddIntConstant(m, "BUTTON_PINKIE", X52PRO_BUTTON_PINKIE);
484 PyModule_AddIntConstant(m, "BUTTON_D", X52PRO_BUTTON_D);
485 PyModule_AddIntConstant(m, "BUTTON_E", X52PRO_BUTTON_E);
486 PyModule_AddIntConstant(m, "BUTTON_T1", X52PRO_BUTTON_T1);
487 PyModule_AddIntConstant(m, "BUTTON_T2", X52PRO_BUTTON_T2);
488 PyModule_AddIntConstant(m, "BUTTON_T3", X52PRO_BUTTON_T3);
489 PyModule_AddIntConstant(m, "BUTTON_T4", X52PRO_BUTTON_T4);
490 PyModule_AddIntConstant(m, "BUTTON_T5", X52PRO_BUTTON_T5);
491 PyModule_AddIntConstant(m, "BUTTON_T6", X52PRO_BUTTON_T6);
492 PyModule_AddIntConstant(m, "BUTTON_TRIGGER2", X52PRO_BUTTON_TRIGGER2);
493 PyModule_AddIntConstant(m, "BUTTON_MOUSE_CLICK", X52PRO_BUTTON_MOUSE_CLICK);
494 PyModule_AddIntConstant(m, "BUTTON_MOUSE_SCROLL_FORWARD", X52PRO_BUTTON_MOUSE_SCROLL_FORWARD);
495 PyModule_AddIntConstant(m, "BUTTON_MOUSE_SCROLL_BACK", X52PRO_BUTTON_MOUSE_SCROLL_BACK);
496 PyModule_AddIntConstant(m, "BUTTON_MOUSE_SCROLL_CLICK", X52PRO_BUTTON_MOUSE_SCROLL_CLICK);
497 PyModule_AddIntConstant(m, "BUTTON_COOLIE_UP", X52PRO_BUTTON_COOLIE_UP);
498 PyModule_AddIntConstant(m, "BUTTON_COOLIE_RIGHT", X52PRO_BUTTON_COOLIE_RIGHT);
499 PyModule_AddIntConstant(m, "BUTTON_COOLIE_DOWN", X52PRO_BUTTON_COOLIE_DOWN);
500 PyModule_AddIntConstant(m, "BUTTON_COOLIE_LEFT", X52PRO_BUTTON_COOLIE_LEFT);
501 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_BACK", X52PRO_BUTTON_THROTTLEHAT_BACK);
502 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_RIGHT", X52PRO_BUTTON_THROTTLEHAT_RIGHT);
503 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_FORWARD", X52PRO_BUTTON_THROTTLEHAT_FORWARD);
504 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_LEFT", X52PRO_BUTTON_THROTTLEHAT_LEFT);
505 PyModule_AddIntConstant(m, "BUTTON_MODE1", X52PRO_BUTTON_MODE1);
506 PyModule_AddIntConstant(m, "BUTTON_MODE2", X52PRO_BUTTON_MODE2);
507 PyModule_AddIntConstant(m, "BUTTON_MODE3", X52PRO_BUTTON_MODE3);
508 PyModule_AddIntConstant(m, "BUTTON_I", X52PRO_BUTTON_I);
509 PyModule_AddIntConstant(m, "BUTTON_MFD_FUNCTION", X52PRO_BUTTON_MFD_FUNCTION);
510 PyModule_AddIntConstant(m, "BUTTON_MFD_STARTSTOP", X52PRO_BUTTON_MFD_STARTSTOP);
511 PyModule_AddIntConstant(m, "BUTTON_MFD_RESET", X52PRO_BUTTON_MFD_RESET);
512 PyModule_AddIntConstant(m, "BUTTON_MFD_PAGE_UP", X52PRO_BUTTON_MFD_PAGE_UP);
513 PyModule_AddIntConstant(m, "BUTTON_MFD_PAGE_DN", X52PRO_BUTTON_MFD_PAGE_DOWN);
514 PyModule_AddIntConstant(m, "BUTTON_MFD_SEL_UP", X52PRO_BUTTON_MFD_SEL_UP);
515 PyModule_AddIntConstant(m, "BUTTON_MFD_SEL_DOWN", X52PRO_BUTTON_MFD_SEL_DOWN);
516 PyModule_AddIntConstant(m, "BUTTON_MFD_SEL", X52PRO_BUTTON_MFD_SEL);
518 PyModule_AddIntConstant(m, "TYPE_X52", DEV_X52);
519 PyModule_AddIntConstant(m, "TYPE_X52PRO", DEV_X52PRO);
520 PyModule_AddIntConstant(m, "TYPE_YOKE", DEV_YOKE);