"Initial commit to Gerrit"
[profile/ivi/gpsd.git] / gpspacket.c
1 /*
2  * Python binding for the packet.c module.
3  *
4  * This file is Copyright (c) 2010 by the GPSD project
5  * BSD terms apply: see the file COPYING in the distribution root for details.
6  *
7  */
8 #include <Python.h>
9
10 #include <stdio.h>
11 #include "gpsd.h"
12
13 static PyObject *ErrorObject = NULL;
14
15 static PyObject *report_callback = NULL;
16
17 void gpsd_report(int errlevel, const char *fmt, ... )
18 {
19     char buf[BUFSIZ];
20     PyObject *args;
21     va_list ap;
22
23     gpsd_hexdump_level = errlevel;
24
25     if (!report_callback)   /* no callback defined, exit early */
26         return; 
27     
28     if (!PyCallable_Check(report_callback)) {
29         PyErr_SetString(ErrorObject, "Cannot call Python callback function");
30         return;
31     }
32
33     va_start(ap, fmt);
34     (void)vsnprintf(buf, sizeof(buf), fmt, ap);
35     va_end(ap);
36
37     args = Py_BuildValue("(is)", errlevel, buf);
38     if (!args)
39         return;
40
41     PyObject_Call(report_callback, args, NULL);
42     Py_DECREF(args);
43 }
44
45 static PyTypeObject Lexer_Type;
46
47 typedef struct {
48         PyObject_HEAD
49         struct gps_packet_t lexer;
50 } LexerObject;
51
52 static LexerObject *
53 newLexerObject(PyObject *arg)
54 {
55     LexerObject *self;
56     self = PyObject_New(LexerObject, &Lexer_Type);
57     if (self == NULL)
58         return NULL;
59     memset(&self->lexer, 0, sizeof(struct gps_packet_t));
60     packet_reset(&self->lexer);
61     return self;
62 }
63
64 /* Lexer methods */
65
66 static int
67 Lexer_init(LexerObject *self)
68 {
69     packet_reset(&self->lexer);
70     return 0;
71 }
72
73 static PyObject *
74 Lexer_get(LexerObject *self, PyObject *args)
75 {
76     ssize_t len;
77     int fd;
78
79     if (!PyArg_ParseTuple(args, "i;missing or invalid file descriptor argument to gps.packet.get", &fd))
80         return NULL;
81
82     len = packet_get(fd, &self->lexer);
83     if (PyErr_Occurred())
84         return NULL;
85
86     return Py_BuildValue("(i, i, s#)",
87                          len,
88                          self->lexer.type, 
89                          self->lexer.outbuffer, 
90                          self->lexer.outbuflen);
91 }
92
93 static PyObject *
94 Lexer_reset(LexerObject *self)
95 {
96     packet_reset(&self->lexer);
97     if (PyErr_Occurred())
98         return NULL;
99     return 0;
100 }
101
102 static void
103 Lexer_dealloc(LexerObject *self)
104 {
105     PyObject_Del(self);
106 }
107
108 static PyMethodDef Lexer_methods[] = {
109     {"get",     (PyCFunction)Lexer_get, METH_VARARGS,
110                 PyDoc_STR("Get a packet from a file descriptor.")},
111     {"reset",   (PyCFunction)Lexer_reset,       METH_NOARGS,
112                 PyDoc_STR("Reset the packet lexer to ground state.")},
113     {NULL,              NULL}           /* sentinel */
114 };
115
116 static PyObject *
117 Lexer_getattr(LexerObject *self, char *name)
118 {
119     return Py_FindMethod(Lexer_methods, (PyObject *)self, name);
120 }
121
122 PyDoc_STRVAR(Lexer__doc__,
123 "GPS packet lexer object\n\
124 \n\
125 Fetch a single packet from file descriptor");
126
127 static PyTypeObject Lexer_Type = {
128         /* The ob_type field must be initialized in the module init function
129          * to be portable to Windows without using C++. */
130         PyObject_HEAD_INIT(NULL)
131         0,                      /*ob_size*/
132         "gps.packet.lexer",     /*tp_name*/
133         sizeof(LexerObject),    /*tp_basicsize*/
134         0,                      /*tp_itemsize*/
135         /* methods */
136         (destructor)Lexer_dealloc, /*tp_dealloc*/
137         0,                      /*tp_print*/
138         (getattrfunc)Lexer_getattr,                     /*tp_getattr*/
139         0,                      /*tp_setattr*/
140         0,                      /*tp_compare*/
141         0,                      /*tp_repr*/
142         0,                      /*tp_as_number*/
143         0,                      /*tp_as_sequence*/
144         0,                      /*tp_as_mapping*/
145         0,                      /*tp_hash*/
146         0,                      /*tp_call*/
147         0,                      /*tp_str*/
148         0,                      /*tp_getattro*/
149         0,                      /*tp_setattro*/
150         0,                      /*tp_as_buffer*/
151         Py_TPFLAGS_DEFAULT,     /*tp_flags*/
152         Lexer__doc__,          /*tp_doc*/
153         0,                      /*tp_traverse*/
154         0,                      /*tp_clear*/
155         0,                      /*tp_richcompare*/
156         0,                      /*tp_weaklistoffset*/
157         0,                      /*tp_iter*/
158         0,                      /*tp_iternext*/
159         Lexer_methods,          /*tp_methods*/
160         0,                      /*tp_members*/
161         0,                      /*tp_getset*/
162         0,                      /*tp_base*/
163         0,                      /*tp_dict*/
164         0,                      /*tp_descr_get*/
165         0,                      /*tp_descr_set*/
166         0,                      /*tp_dictoffset*/
167         (initproc)Lexer_init,   /*tp_init*/
168         0,                      /*tp_alloc*/
169         0,                      /*tp_new*/
170         0,                      /*tp_free*/
171         0,                      /*tp_is_gc*/
172 };
173
174 /* Function of no arguments returning new Lexer object */
175
176 static PyObject *
177 gpspacket_new(PyObject *self, PyObject *args)
178 {
179     LexerObject *rv;
180
181     if (!PyArg_ParseTuple(args, ":new"))
182         return NULL;
183     rv = newLexerObject(args);
184     if (rv == NULL)
185         return NULL;
186     return (PyObject *)rv;
187 }
188
189 PyDoc_STRVAR(register_report__doc__,
190 "register_report(callback)\n\
191 \n\
192 callback must be a callable object expecting a string as parameter.");
193
194 static PyObject *
195 register_report(LexerObject *self, PyObject *args)
196 {
197     PyObject *callback = NULL;
198
199     if (!PyArg_ParseTuple(args, "O:register_report", &callback))
200         return NULL;
201
202     if (!PyCallable_Check(callback)) {
203         PyErr_SetString(PyExc_TypeError, "First argument must be callable");
204         return NULL;
205     }
206
207     if (report_callback) {
208         Py_DECREF(report_callback);
209         report_callback = NULL;
210     }
211
212     report_callback = callback;
213     Py_INCREF(report_callback);
214
215     Py_INCREF(Py_None);
216     return Py_None;
217 }
218
219
220 /* List of functions defined in the module */
221
222 static PyMethodDef packet_methods[] = {
223     {"new",             gpspacket_new,          METH_VARARGS,
224      PyDoc_STR("new() -> new packet-lexer object")},
225     {"register_report", (PyCFunction)register_report, METH_VARARGS,
226                         register_report__doc__},
227     {NULL,              NULL}           /* sentinel */
228 };
229
230 PyDoc_STRVAR(module_doc,
231 "Python binding of the libgpsd module for recognizing GPS packets.\n\
232 The new() function returns a new packet-lexer instance.  Lexer instances\n\
233 have two methods:\n\
234     get() takes a file descriptor argument and returns a tuple consisting of\n\
235 the integer packet type and string packet value.  On end of file it returns\n\
236 (-1, '').\n\
237     reset() resets the packet-lexer to its initial state.\n\
238     The module also has a register_report() function that accepts a callback\n\
239 for debug message reporting.  The callback will get two arguments, the error\n\
240 level of the message and the message itself.\n\
241 ");
242
243 PyMODINIT_FUNC
244 initpacket(void)
245 {
246     PyObject *m;
247
248     if (PyType_Ready(&Lexer_Type) < 0)
249         return;
250
251     /* Create the module and add the functions */
252     m = Py_InitModule3("packet", packet_methods, module_doc);
253
254     PyModule_AddIntConstant(m, "BAD_PACKET", BAD_PACKET);
255     PyModule_AddIntConstant(m, "COMMENT_PACKET", COMMENT_PACKET);
256     PyModule_AddIntConstant(m, "NMEA_PACKET", NMEA_PACKET);
257     PyModule_AddIntConstant(m, "SIRF_PACKET", SIRF_PACKET);
258     PyModule_AddIntConstant(m, "ZODIAC_PACKET", ZODIAC_PACKET);
259     PyModule_AddIntConstant(m, "TSIP_PACKET", TSIP_PACKET);
260     PyModule_AddIntConstant(m, "EVERMORE_PACKET", EVERMORE_PACKET);
261     PyModule_AddIntConstant(m, "ITALK_PACKET", ITALK_PACKET);
262     PyModule_AddIntConstant(m, "GARMIN_PACKET", GARMIN_PACKET);
263     PyModule_AddIntConstant(m, "NAVCOM_PACKET", NAVCOM_PACKET);
264     PyModule_AddIntConstant(m, "RTCM2_PACKET", RTCM2_PACKET);
265     PyModule_AddIntConstant(m, "RTCM3_PACKET", RTCM3_PACKET);
266     PyModule_AddIntConstant(m, "UBX_PACKET", UBX_PACKET);
267     PyModule_AddIntConstant(m, "GARMINTXT_PACKET", GARMINTXT_PACKET);
268
269     PyModule_AddIntConstant(m, "LOG_IO", LOG_IO);
270 }