attempt #2 for settext
[PyX52.git] / PyX52.c
blob040591ac0d14c40e6f1515139ddb36ae65fa58fe
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_PGUP,
46 X52PRO_BUTTON_MFD_PGDN,
47 X52PRO_BUTTON_MFD_SELUP,
48 X52PRO_BUTTON_MFD_SELDN,
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 *);
77 static PyObject *
78 PyX52_X52_new(PyTypeObject *type)
81 PyX52_X52_object *self;
82 self = (PyX52_X52_object *)type->tp_alloc(type, 0);
83 if (self != NULL)
85 self->handle = NULL;
87 return (PyObject *)self;
90 static int
91 PyX52_X52_init(PyX52_X52_object *self)
94 self->handle = x52_init();
95 if (self->handle == NULL)
97 PyErr_SetString(PyExc_RuntimeError, "No compatible joysticks found.");
98 return -1;
100 x52_debug(self->handle, 0);
101 return 0;
104 static void
105 PyX52_X52_dealloc(PyX52_X52_object *self)
108 if (self->handle != NULL)
110 x52_close(self->handle);
112 self->handle = NULL;
113 self->ob_type->tp_free((PyObject *)self);
116 static PyObject *
117 PyX52_X52_gettype(PyX52_X52_object *self)
119 enum x52_type type = x52_gettype(self->handle);
120 return Py_BuildValue("i", type);
123 static PyObject *
124 PyX52_X52_settext(PyX52_X52_object *self, PyObject *args, PyObject *kws)
126 if (x52_gettype(self->handle) == DEV_YOKE)
128 PyErr_SetString(PyExc_RuntimeError, "Cannot call settext on this device.");
129 return NULL;
132 int line_no = 0;
133 PyObject *line = Py_BuildValue("s", "");
135 static char *kwlist[] = {"line_no", "line", NULL};
136 if (!PyArg_ParseTupleAndKeywords(args, kws, "iO", kwlist, &line_no, line))
137 return NULL;
139 if (line_no < 0 || line_no > 2)
141 PyErr_SetString(PyExc_AttributeError, "line_no must be in the range 0-2.");
142 return NULL;
144 if (!PyString_Check(line))
146 PyErr_SetString(PyExc_AttributeError, "line must be a string or subtype of string.");
147 return NULL;
150 char *line_trunc = (char *)malloc(sizeof(char)*17);
151 memset(line_trunc, ' ', 16);
152 char *line_buf = PyString_AsString(line);
153 strncpy(line_trunc, line_buf, 16);
155 if (x52_settext(self->handle, line_no, line_buf, 16) != 0)
157 PyErr_SetString(PyExc_RuntimeError, "Could not set text.");
158 return NULL;
161 Py_DECREF(line);
162 Py_INCREF(Py_None);
163 return Py_None;
166 static PyObject *
167 PyX52_X52_setbri(PyX52_X52_object *self, PyObject *args, PyObject *kws)
169 if (x52_gettype(self->handle) == DEV_YOKE)
171 PyErr_SetString(PyExc_RuntimeError, "Cannot call setbri on this device.");
172 return NULL;
175 int mode = 0;
176 int bri = 0;
178 static char *kwlist[] = {"mode", "bri", NULL};
179 if (!PyArg_ParseTupleAndKeywords(args, kws, "ii", kwlist, &mode, &bri))
180 return NULL;
182 if (mode != 0 && mode != 1)
184 PyErr_SetString(PyExc_AttributeError, "Invalid mode.");
185 return NULL;
188 if (mode == 0 && x52_gettype(self->handle) != DEV_X52PRO)
190 PyErr_SetString(PyExc_AttributeError, "Cannot set LED brightness on this device.");
191 return NULL;
194 if (bri < 0 || bri > 127)
196 PyErr_SetString(PyExc_AttributeError, "Invalid brightness value.");
197 return NULL;
200 if (x52_setbri(self->handle, mode, bri) != 0)
202 PyErr_SetString(PyExc_RuntimeError, "Could not set brightness.");
203 return NULL;
206 Py_INCREF(Py_None);
207 return Py_None;
210 static PyObject *
211 PyX52_X52_setled(PyX52_X52_object *self, PyObject *args, PyObject *kws)
213 if (x52_gettype(self->handle) != DEV_X52PRO)
215 PyErr_SetString(PyExc_RuntimeError, "Cannot call setled on this device.");
216 return NULL;
220 * TODO: Allow passing of a dict with LEDs/states
221 * TODO: Allow abstraction to button colour (i.e. PyX52.X52.buttons["coolie"].orange())
223 int led = 0;
224 int state = 0;
226 static char *kwlist[] = {"led", "state", NULL};
227 if (!PyArg_ParseTupleAndKeywords(args, kws, "ii", kwlist, &led, &state))
228 return NULL;
230 if (state != 0 && state != 1)
232 PyErr_SetString(PyExc_AttributeError, "Invalid LED state.");
233 return NULL;
236 if (led < X52PRO_LED_FIRE || led > X52PRO_LED_IGREEN)
238 PyErr_SetString(PyExc_AttributeError, "Invalid LED ID.");
239 return NULL;
242 if (!x52_setled(self->handle, led, state))
244 PyErr_SetString(PyExc_RuntimeError, "Could not set LED status.");
245 return NULL;
248 Py_INCREF(Py_None);
249 return Py_None;
252 static PyObject *
253 PyX52_X52_settime(PyX52_X52_object *self, PyObject *args, PyObject *kws)
255 int h24 = 1;
257 struct tm *ltime = NULL;
258 time_t t = time(NULL);
259 ltime = gmtime(&t);
261 int hour = ltime->tm_hour;
262 int minute = ltime->tm_min;
264 static char *kwlist[] = {"hour", "minute", "h24", NULL};
265 if (!PyArg_ParseTupleAndKeywords(args, kws, "|iii", kwlist, &hour, &minute, &h24))
266 return NULL;
268 if (x52_settime(self->handle, h24, hour, minute) != 0)
270 PyErr_SetString(PyExc_RuntimeError, "Could not set time.");
271 return NULL;
274 Py_INCREF(Py_None);
275 return Py_None;
278 static PyObject *
279 PyX52_X52_setoffs(PyX52_X52_object *self, PyObject *args, PyObject *kws)
282 * TODO: default to local timezones
284 if (x52_gettype(self->handle) == DEV_YOKE)
286 PyErr_SetString(PyExc_RuntimeError, "Cannot call setoffs on this device.");
287 return NULL;
290 int offs2 = 0;
291 int offs3 = 0;
293 static char *kwlist[] = {"offs2", "offs3", NULL};
294 if (!PyArg_ParseTupleAndKeywords(args, kws, "|ii", kwlist, &offs2, &offs3))
295 return NULL;
297 Py_INCREF(Py_None);
298 return Py_None;
301 static PyObject *
302 PyX52_X52_setsecond(PyX52_X52_object *self, PyObject *args, PyObject *kws)
304 if (x52_gettype(self->handle) != DEV_YOKE)
306 PyErr_SetString(PyExc_RuntimeError, "Cannot call setsecond on this device.");
307 return NULL;
310 struct tm *ltime;
311 time_t t = time(NULL);
312 gmtime_r(&t, ltime);
314 int second = ltime->tm_sec;
316 static char *kwlist[] = {"second", NULL};
317 if (!PyArg_ParseTupleAndKeywords(args, kws, "|iii", kwlist, &second))
318 return NULL;
320 x52_setsecond(self->handle, second);
322 Py_INCREF(Py_None);
323 return Py_None;
326 static PyObject *
327 PyX52_X52_setdate(PyX52_X52_object *self, PyObject *args, PyObject *kws)
329 if (x52_gettype(self->handle) == DEV_YOKE)
331 PyErr_SetString(PyExc_RuntimeError, "Cannot call setdate on this device.");
332 return NULL;
335 struct tm *ltime;
336 time_t *t;
337 time(t);
338 ltime = gmtime(t);
340 int year = ltime->tm_year - 100;
341 int month = ltime->tm_mon + 1;
342 int day = ltime->tm_mday;
344 static char *kwlist[] = {"year", "month", "day", NULL};
345 if (!PyArg_ParseTupleAndKeywords(args, kws, "|iii", kwlist, &year, &month, &day))
346 return NULL;
348 if (x52_setdate(self->handle, year, month, day) != 0)
350 PyErr_SetString(PyExc_RuntimeError, "Could not set date.");
351 return NULL;
354 Py_INCREF(Py_None);
355 return Py_None;
358 static PyMethodDef PyX52_X52_methods[] = {
359 {"gettype", (PyCFunction)PyX52_X52_gettype, METH_NOARGS, "Get the type of X52 device."},
360 {"settext", (PyCFunction)PyX52_X52_settext, METH_VARARGS | METH_KEYWORDS, "Set the text on the MFD. (X52 and X52 Pro only.)"},
361 {"setbri", (PyCFunction)PyX52_X52_setbri, METH_VARARGS | METH_KEYWORDS, "Set the brightness of either the LEDs or the MFD. (X52 and X52 Pro only.)"},
362 {"setled", (PyCFunction)PyX52_X52_setled, METH_VARARGS | METH_KEYWORDS, "Set an LED's state. (X52 Pro only.)"},
363 {"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.)"},
364 {"setoffs", (PyCFunction)PyX52_X52_setoffs, METH_VARARGS | METH_KEYWORDS, "Set the time offset. (X52, X52 Pro.)"},
365 {"setsecond", (PyCFunction)PyX52_X52_setsecond, METH_VARARGS | METH_KEYWORDS, "Set the second. If no arguments are supplied, current second is used. (Yoke only.)"},
366 {"setdate", (PyCFunction)PyX52_X52_setdate, METH_VARARGS | METH_KEYWORDS, "Set the date. If no arguments are supplied, current date is used. (X52, X52 Pro.)"},
367 {NULL, NULL, 0, NULL}
370 static PyTypeObject PyX52_X52_type = {
371 PyObject_HEAD_INIT(NULL)
372 0, /*ob_size*/
373 "PyX52.X52", /*tp_name*/
374 sizeof(PyX52_X52_object), /*tp_basicsize*/
375 0, /*tp_itemsize*/
376 (destructor)PyX52_X52_dealloc, /*tp_dealloc*/
377 0, /*tp_print*/
378 0, /*tp_getattr*/
379 0, /*tp_setattr*/
380 0, /*tp_compare*/
381 0, /*tp_repr*/
382 0, /*tp_as_number*/
383 0, /*tp_as_sequence*/
384 0, /*tp_as_mapping*/
385 0, /*tp_hash */
386 0, /*tp_call*/
387 0, /*tp_str*/
388 0, /*tp_getattro*/
389 0, /*tp_setattro*/
390 0, /*tp_as_buffer*/
391 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
392 "X52 joystick object", /* tp_doc */
393 0, /*tp_traverse*/
394 0, /* tp_clear */
395 0, /* tp_richcompare */
396 0, /* tp_weaklistoffset */
397 0, /* tp_iter */
398 0, /* tp_iternext */
399 PyX52_X52_methods, /* tp_methods */
400 0, /* tp_members */
401 0, /* tp_getset */
402 0, /* tp_base */
403 0, /* tp_dict */
404 0, /* tp_descr_get */
405 0, /* tp_descr_set */
406 0, /* tp_dictoffset */
407 (initproc)PyX52_X52_init, /* tp_init */
408 0, /* tp_alloc */
409 (newfunc)PyX52_X52_new, /* tp_new */
412 static PyMethodDef PyX52_methods[] = {
413 {NULL}
416 #ifndef PyMODINIT_FUNC
417 #define PyMODINIT_FUNC void
418 #endif
419 PyMODINIT_FUNC
420 initPyX52(void)
422 PyObject *m;
424 if (PyType_Ready(&PyX52_X52_type) < 0)
425 return;
427 m = Py_InitModule3("PyX52", PyX52_methods, "Provides functions for handling Saitek X52, X52 Pro and Yoke joystick devices.");
428 if (m == NULL)
429 return;
431 Py_INCREF(&PyX52_X52_type);
432 PyModule_AddObject(m, "X52", (PyObject *) &PyX52_X52_type);
434 PyModule_AddIntConstant(m, "LED_FIRE", X52PRO_LED_FIRE);
435 PyModule_AddIntConstant(m, "LED_ARED", X52PRO_LED_ARED);
436 PyModule_AddIntConstant(m, "LED_AGREEN", X52PRO_LED_AGREEN);
437 PyModule_AddIntConstant(m, "LED_BRED", X52PRO_LED_BRED);
438 PyModule_AddIntConstant(m, "LED_BGREEN", X52PRO_LED_BGREEN);
439 PyModule_AddIntConstant(m, "LED_DRED", X52PRO_LED_DRED);
440 PyModule_AddIntConstant(m, "LED_DGREEN", X52PRO_LED_DGREEN);
441 PyModule_AddIntConstant(m, "LED_ERED", X52PRO_LED_ERED);
442 PyModule_AddIntConstant(m, "LED_EGREEN", X52PRO_LED_EGREEN);
443 PyModule_AddIntConstant(m, "LED_T1RED", X52PRO_LED_T1RED);
444 PyModule_AddIntConstant(m, "LED_T1GREEN", X52PRO_LED_T1GREEN);
445 PyModule_AddIntConstant(m, "LED_T2RED", X52PRO_LED_T2RED);
446 PyModule_AddIntConstant(m, "LED_T2GREEN", X52PRO_LED_T2GREEN);
447 PyModule_AddIntConstant(m, "LED_T3RED", X52PRO_LED_T3RED);
448 PyModule_AddIntConstant(m, "LED_T3GREEN", X52PRO_LED_T3GREEN);
449 PyModule_AddIntConstant(m, "LED_CORED", X52PRO_LED_CORED);
450 PyModule_AddIntConstant(m, "LED_COGREEN", X52PRO_LED_COGREEN);
451 PyModule_AddIntConstant(m, "LED_IRED", X52PRO_LED_IRED);
452 PyModule_AddIntConstant(m, "LED_IGREEN", X52PRO_LED_IGREEN);
454 PyModule_AddIntConstant(m, "BUTTON_TRIGGER1", X52PRO_BUTTON_TRIGGER1);
455 PyModule_AddIntConstant(m, "BUTTON_FIRE", X52PRO_BUTTON_FIRE);
456 PyModule_AddIntConstant(m, "BUTTON_A", X52PRO_BUTTON_A);
457 PyModule_AddIntConstant(m, "BUTTON_B", X52PRO_BUTTON_B);
458 PyModule_AddIntConstant(m, "BUTTON_C", X52PRO_BUTTON_C);
459 PyModule_AddIntConstant(m, "BUTTON_PINKIE", X52PRO_BUTTON_PINKIE);
460 PyModule_AddIntConstant(m, "BUTTON_D", X52PRO_BUTTON_D);
461 PyModule_AddIntConstant(m, "BUTTON_E", X52PRO_BUTTON_E);
462 PyModule_AddIntConstant(m, "BUTTON_T1", X52PRO_BUTTON_T1);
463 PyModule_AddIntConstant(m, "BUTTON_T2", X52PRO_BUTTON_T2);
464 PyModule_AddIntConstant(m, "BUTTON_T3", X52PRO_BUTTON_T3);
465 PyModule_AddIntConstant(m, "BUTTON_T4", X52PRO_BUTTON_T4);
466 PyModule_AddIntConstant(m, "BUTTON_T5", X52PRO_BUTTON_T5);
467 PyModule_AddIntConstant(m, "BUTTON_T6", X52PRO_BUTTON_T6);
468 PyModule_AddIntConstant(m, "BUTTON_TRIGGER2", X52PRO_BUTTON_TRIGGER2);
469 PyModule_AddIntConstant(m, "BUTTON_MOUSE_CLICK", X52PRO_BUTTON_MOUSE_CLICK);
470 PyModule_AddIntConstant(m, "BUTTON_MOUSE_SCROLL_FORWARD", X52PRO_BUTTON_MOUSE_SCROLL_FORWARD);
471 PyModule_AddIntConstant(m, "BUTTON_MOUSE_SCROLL_BACK", X52PRO_BUTTON_MOUSE_SCROLL_BACK);
472 PyModule_AddIntConstant(m, "BUTTON_MOUSE_SCROLL_CLICK", X52PRO_BUTTON_MOUSE_SCROLL_CLICK);
473 PyModule_AddIntConstant(m, "BUTTON_COOLIE_UP", X52PRO_BUTTON_COOLIE_UP);
474 PyModule_AddIntConstant(m, "BUTTON_COOLIE_RIGHT", X52PRO_BUTTON_COOLIE_RIGHT);
475 PyModule_AddIntConstant(m, "BUTTON_COOLIE_DOWN", X52PRO_BUTTON_COOLIE_DOWN);
476 PyModule_AddIntConstant(m, "BUTTON_COOLIE_LEFT", X52PRO_BUTTON_COOLIE_LEFT);
477 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_BACK", X52PRO_BUTTON_THROTTLEHAT_BACK);
478 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_RIGHT", X52PRO_BUTTON_THROTTLEHAT_RIGHT);
479 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_FORWARD", X52PRO_BUTTON_THROTTLEHAT_FORWARD);
480 PyModule_AddIntConstant(m, "BUTTON_THROTTLEHAT_LEFT", X52PRO_BUTTON_THROTTLEHAT_LEFT);
481 PyModule_AddIntConstant(m, "BUTTON_MODE1", X52PRO_BUTTON_MODE1);
482 PyModule_AddIntConstant(m, "BUTTON_MODE2", X52PRO_BUTTON_MODE2);
483 PyModule_AddIntConstant(m, "BUTTON_MODE3", X52PRO_BUTTON_MODE3);
484 PyModule_AddIntConstant(m, "BUTTON_I", X52PRO_BUTTON_I);
485 PyModule_AddIntConstant(m, "BUTTON_MFD_FUNCTION", X52PRO_BUTTON_MFD_FUNCTION);
486 PyModule_AddIntConstant(m, "BUTTON_MFD_STARTSTOP", X52PRO_BUTTON_MFD_STARTSTOP);
487 PyModule_AddIntConstant(m, "BUTTON_MFD_RESET", X52PRO_BUTTON_MFD_RESET);
488 PyModule_AddIntConstant(m, "BUTTON_MFD_PGUP", X52PRO_BUTTON_MFD_PGUP);
489 PyModule_AddIntConstant(m, "BUTTON_MFD_PGDN", X52PRO_BUTTON_MFD_PGDN);
490 PyModule_AddIntConstant(m, "BUTTON_MFD_SELUP", X52PRO_BUTTON_MFD_SELUP);
491 PyModule_AddIntConstant(m, "BUTTON_MFD_SELDN", X52PRO_BUTTON_MFD_SELDN);
492 PyModule_AddIntConstant(m, "BUTTON_MFD_SEL", X52PRO_BUTTON_MFD_SEL);
494 PyModule_AddIntConstant(m, "TYPE_X52", DEV_X52);
495 PyModule_AddIntConstant(m, "TYPE_X52PRO", DEV_X52PRO);
496 PyModule_AddIntConstant(m, "TYPE_YOKE", DEV_YOKE);