Ticket #913: vehicle_wince.c

File vehicle_wince.c, 23.5 KB (added by gregoire verlut, 9 years ago)

missing ;

Line 
1/**
2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 Navit Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA  02110-1301, USA.
18 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#ifdef HAVE_UNISTD_H
23#include <unistd.h>
24#endif
25#include <fcntl.h>
26#include <string.h>
27#include <glib.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <math.h>
31#include "config.h"
32#include "debug.h"
33#include "callback.h"
34#include "plugin.h"
35#include "coord.h"
36#include "item.h"
37#include "event.h"
38#include "vehicle.h"
39#include <windows.h>
40#include <windowsx.h>
41#include <io.h>
42#include <winioctl.h>
43#include <winbase.h>
44#include <wchar.h>
45#include "support/win32/ConvertUTF.h"
46
47#define SwitchToThread() Sleep(0)
48
49typedef int (WINAPI *PFN_BthSetMode)(DWORD pBthMode);
50typedef int (WINAPI *PFN_BthGetMode)(DWORD* pBthMode);
51
52char *_convert = NULL;
53wchar_t *_wconvert = NULL;
54#define W2A(lpw) (\
55    ((LPCSTR)lpw == NULL) ? NULL : (\
56          _convert = alloca(wcslen(lpw)+1),  wcstombs(_convert, lpw, wcslen(lpw) + 1), _convert) )
57
58#define A2W(lpa) (\
59    ((LPCSTR)lpa == NULL) ? NULL : (\
60          _wconvert = alloca(strlen(lpa)*2+1),  mbstowcs(_wconvert, lpa, strlen(lpa) * 2 + 1), _wconvert) )
61
62static void vehicle_wince_disable_watch(struct vehicle_priv *priv);
63static void vehicle_wince_enable_watch(struct vehicle_priv *priv);
64static int vehicle_wince_parse(struct vehicle_priv *priv, char *buffer);
65static int vehicle_wince_open(struct vehicle_priv *priv);
66static void vehicle_wince_close(struct vehicle_priv *priv);
67
68enum file_type {
69        file_type_pipe = 1, file_type_device, file_type_file, file_type_socket
70};
71
72static int buffer_size = 1024;
73
74struct gps_sat {
75        int prn;
76        int elevation;
77        int azimuth;
78        int snr;
79};
80
81
82struct vehicle_priv {
83        char *source;
84        struct callback_list *cbl;
85    struct callback_list *priv_cbl;
86        int is_running;
87        int thread_up;
88        int fd;
89        HANDLE                  m_hGPSDevice;           // Handle to the device
90        HANDLE                  m_hGPSThread;           // Handle to the thread
91        DWORD                   m_dwGPSThread;          // Thread id
92
93        char *buffer;
94        int   buffer_pos;
95        char *read_buffer;
96        int   read_buffer_pos;
97        char *nmea_data;
98        char *nmea_data_buf;
99
100        struct coord_geo geo;
101        double speed;
102        double direction;
103        double height;
104        double hdop;
105        double vdop;
106        char fixtime[20];
107        int fixyear;
108        int fixmonth;
109        int fixday;
110        int status;
111        int sats_used;
112        int sats_visible;
113        int sats_signal;
114        int time;
115        int on_eof;
116        int baudrate;
117        enum file_type file_type;
118        struct attr ** attrs;
119        char fixiso8601[128];
120        int checksum_ignore;
121        HMODULE hBthDll;
122        PFN_BthSetMode BthSetMode;
123        int magnetic_direction;
124        int current_count;
125        struct gps_sat current[24];
126        int next_count;
127        struct gps_sat next[24];
128        struct item sat_item;
129        int valid;
130        int has_data;
131        GMutex lock;
132};
133
134static void initBth(struct vehicle_priv *priv)
135{
136
137        BOOL succeeded = FALSE;
138        priv->hBthDll = LoadLibrary(TEXT("bthutil.dll"));
139        if ( priv->hBthDll )
140        {
141                DWORD bthMode;
142                PFN_BthGetMode BthGetMode  = (PFN_BthGetMode)GetProcAddress(priv->hBthDll, TEXT("BthGetMode") );
143
144                if ( BthGetMode && BthGetMode(&bthMode) == ERROR_SUCCESS && bthMode == 0 )
145                {
146                        priv->BthSetMode  = (PFN_BthSetMode)GetProcAddress(priv->hBthDll, TEXT("BthSetMode") );
147                        if( priv->BthSetMode &&  priv->BthSetMode(1) == ERROR_SUCCESS )
148                        {
149                                dbg(1, "bluetooth activated\n");
150                                succeeded = TRUE;
151                        }
152                }
153
154        }
155        else
156        {
157                dbg(0, "Bluetooth library notfound\n");
158        }
159
160        if ( !succeeded )
161        {
162
163                dbg(1, "Bluetooth already enabled or failed to enable it.\n");
164                priv->BthSetMode = NULL;
165                if ( priv->hBthDll )
166                {
167                        FreeLibrary(priv->hBthDll);
168                }
169        }
170}
171
172static int initDevice(struct vehicle_priv *priv)
173{
174        COMMTIMEOUTS commTiming;
175    HANDLE hGPS;
176    if ( priv->m_hGPSDevice )
177        CloseHandle(priv->m_hGPSDevice);
178   
179        if ( priv->file_type == file_type_device )
180        {
181            dbg(0, "Init Device\n");
182        /* GPD0 is the control port for the GPS driver */
183        hGPS = CreateFile(L"GPD0:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
184        if (hGPS != INVALID_HANDLE_VALUE) {
185#ifndef IOCTL_SERVICE_REFRESH
186#define IOCTL_SERVICE_REFRESH 0x4100000C
187#endif
188            DeviceIoControl(hGPS,IOCTL_SERVICE_REFRESH,0,0,0,0,0,0);
189#ifndef IOCTL_SERVICE_START
190#define IOCTL_SERVICE_START 0x41000004
191#endif
192            DeviceIoControl(hGPS,IOCTL_SERVICE_START,0,0,0,0,0,0);
193            CloseHandle(hGPS);
194        }
195
196        while (priv->is_running &&
197            (priv->m_hGPSDevice = CreateFile(A2W(priv->source),
198                GENERIC_READ, 0,
199                NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
200            Sleep(1000);
201            dbg(0, "Waiting to connect to %s\n", priv->source);
202        }
203        GetCommTimeouts (priv->m_hGPSDevice, &commTiming);
204        commTiming.ReadIntervalTimeout = 20;
205        commTiming.ReadTotalTimeoutMultiplier = 0;
206        commTiming.ReadTotalTimeoutConstant = 200;
207
208        commTiming.WriteTotalTimeoutMultiplier=5;
209        commTiming.WriteTotalTimeoutConstant=5;
210        SetCommTimeouts (priv->m_hGPSDevice, &commTiming);
211
212        if (priv->baudrate) {
213            DCB portState;
214            if (!GetCommState(priv->m_hGPSDevice, &portState)) {
215                MessageBox (NULL, TEXT ("GetCommState Error"), TEXT (""),
216                    MB_APPLMODAL|MB_OK);
217                priv->thread_up = 0;
218                return 0;
219            }
220            portState.BaudRate = priv->baudrate;
221            if (!SetCommState(priv->m_hGPSDevice, &portState)) {
222                MessageBox (NULL, TEXT ("SetCommState Error"), TEXT (""),
223                    MB_APPLMODAL|MB_OK);
224                priv->thread_up = 0;
225                return 0;
226            }
227        }
228           
229        }
230        else
231        {
232            dbg(0, "Open File\n");
233        priv->m_hGPSDevice = CreateFileW( A2W(priv->source),
234                        GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
235        if ( priv->m_hGPSDevice == INVALID_HANDLE_VALUE) {
236            dbg(0, "Could not open %s\n", priv->source);
237            return 0;
238        }
239        }
240        return 1;
241   
242}
243
244static int read_win32(struct vehicle_priv *priv, char *buffer, size_t size)
245{
246    int ret_size;
247
248    g_mutex_lock(&priv->lock);
249    ret_size = MIN(size,priv->read_buffer_pos);
250    priv->has_data = 0;
251    memcpy(buffer, priv->read_buffer, ret_size);
252   
253    memmove(priv->read_buffer, priv->read_buffer + ret_size, buffer_size - ret_size);
254    priv->read_buffer_pos -= ret_size;
255    g_mutex_unlock(&priv->lock);
256    return ret_size;
257}
258
259static DWORD WINAPI wince_reader_thread (LPVOID lParam)
260{
261        struct vehicle_priv *priv = lParam;
262        char chunk_buffer[3*82];
263        BOOL status;
264        DWORD bytes_read;
265        int waitcounter;
266       
267        dbg(0, "GPS Port:[%s]\n", priv->source);
268        priv->thread_up = 1;
269       
270    if ( !initDevice(priv) ) {
271                return -1;
272        }
273        while (priv->is_running)
274        {
275                dbg(1,"readfile\n");
276                waitcounter = 0;
277                status = ReadFile(priv->m_hGPSDevice,
278                        chunk_buffer, sizeof(chunk_buffer),
279                        &bytes_read, NULL);
280           
281            if ( !status )
282            {
283                dbg(0,"Error reading file/device. Try again.\n");
284                        initDevice(priv);
285                        continue;
286            }
287           
288            while ( priv->read_buffer_pos + bytes_read > buffer_size )
289            {
290/* TODO (rikky#1#): should use blocking */
291            if ( priv->file_type != file_type_file )
292            {
293                dbg(0, "GPS data comes too fast. Have to wait here\n");
294            }
295
296            Sleep(50);
297            waitcounter++;
298            if ( waitcounter % 8 == 0 )
299            {
300                dbg(0, "Remind them of the data\n");
301                event_call_callback(priv->priv_cbl);
302            }
303
304            }
305   
306        g_mutex_lock(&priv->lock);
307            memcpy(priv->read_buffer + priv->read_buffer_pos , chunk_buffer, bytes_read );
308           
309            priv->read_buffer_pos += bytes_read;
310           
311            if ( !priv->has_data )
312            {
313            event_call_callback(priv->priv_cbl);
314                priv->has_data = 1;
315            }
316           
317        g_mutex_unlock(&priv->lock);
318           
319        }
320    return TRUE;
321}
322
323static int
324vehicle_wince_available_ports(void)
325{
326        HKEY hkResult;
327        HKEY hkSubResult;
328        wchar_t keyname[20];
329        wchar_t devicename[100];
330        wchar_t devicetype[100];
331        int index = 0;
332        DWORD regkey_length = sizeof(keyname);
333        DWORD regdevtype_length = sizeof(devicetype);
334       
335        RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Drivers\\Active"), 0, 0, &hkResult);
336        while (RegEnumKeyEx( hkResult, index++, keyname, &regkey_length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS )
337        {
338                if (RegOpenKeyEx( hkResult, keyname, 0, 0, &hkSubResult) == ERROR_SUCCESS )
339                {
340                        regkey_length = sizeof(keyname);
341                        if ( RegQueryValueEx( hkSubResult,  L"Name", NULL, NULL, (LPBYTE)devicename, &regkey_length) == ERROR_SUCCESS )
342                        {
343                                regdevtype_length = sizeof(devicetype);
344                                if ( RegQueryValueEx( hkSubResult, L"Key", NULL, NULL, (LPBYTE)devicetype, &regdevtype_length) == ERROR_SUCCESS )
345                                {
346                                        dbg(0, "Found device '%s' (%s)\n", W2A(devicename), W2A(devicetype));
347                                }
348                                else
349                                {
350                                        dbg(0, "Found device '%s'\n", W2A(devicename));
351                                }
352                        }
353                        RegCloseKey(hkSubResult);
354                }
355                regkey_length = sizeof(keyname);
356        }
357
358        RegCloseKey(hkResult);
359        return 0;
360}
361
362
363static int
364vehicle_wince_open(struct vehicle_priv *priv)
365{
366    char* raw_setting_str;
367    char* strport;
368    char* strsettings;
369
370        dbg(1, "enter vehicle_wince_open, priv->source='%s'\n", priv->source);
371
372        if (priv->source ) {
373
374                if ( strcmp(priv->source, "list") == 0 )
375                {
376                        vehicle_wince_available_ports();
377                        return 0;
378                }
379
380                raw_setting_str = g_strdup( priv->source );
381                strport = strchr(raw_setting_str, ':' );
382                strsettings = strchr(raw_setting_str, ' ' );
383
384                if (raw_setting_str && strport&&strsettings ) {
385                        strport++;
386                        *strsettings = '\0';
387                        strsettings++;
388
389                        dbg(0, "serial('%s', '%s')\n", strport, strsettings );
390                }
391                if (raw_setting_str)
392                g_free( raw_setting_str );
393        }
394        return 1;
395}
396
397static void
398vehicle_wince_close(struct vehicle_priv *priv)
399{
400    dbg(1,"enter");
401}
402
403static int
404vehicle_wince_parse(struct vehicle_priv *priv, char *buffer)
405{
406        char *nmea_data_buf, *p, *item[32];
407        double lat, lng;
408        int i, j, bcsum;
409        int len = strlen(buffer);
410        unsigned char csum = 0;
411        int valid=0;
412        int ret = 0;
413
414        dbg(2, "enter: buffer='%s'\n", buffer);
415        for (;;) {
416                if (len < 4) {
417                        dbg(0, "'%s' too short\n", buffer);
418                        return ret;
419                }
420                if (buffer[len - 1] == '\r' || buffer[len - 1] == '\n') {
421                        buffer[--len] = '\0';
422            if (buffer[len - 1] == '\r')
423                buffer[--len] = '\0';
424        } else
425                        break;
426        }
427        if (buffer[0] != '$') {
428                dbg(0, "no leading $ in '%s'\n", buffer);
429                return ret;
430        }
431        if (buffer[len - 3] != '*') {
432                dbg(0, "no *XX in '%s'\n", buffer);
433                return ret;
434        }
435        for (i = 1; i < len - 3; i++) {
436                csum ^= (unsigned char) (buffer[i]);
437        }
438        if (!sscanf(buffer + len - 2, "%x", &bcsum) && priv->checksum_ignore != 2) {
439                dbg(0, "no checksum in '%s'\n", buffer);
440                return ret;
441        }
442        if (bcsum != csum && priv->checksum_ignore == 0) {
443                dbg(0, "wrong checksum in '%s'\n", buffer);
444                return ret;
445        }
446
447        if (!priv->nmea_data_buf || strlen(priv->nmea_data_buf) < 65536) {
448                nmea_data_buf=g_strconcat(priv->nmea_data_buf ? priv->nmea_data_buf : "", buffer, "\n", NULL);
449                g_free(priv->nmea_data_buf);
450                priv->nmea_data_buf=nmea_data_buf;
451        } else {
452                dbg(0, "nmea buffer overflow, discarding '%s'\n", buffer);
453        }
454        i = 0;
455        p = buffer;
456        while (i < 31) {
457                item[i++] = p;
458                while (*p && *p != ',')
459                        p++;
460                if (!*p)
461                        break;
462                *p++ = '\0';
463        }
464
465        if (!strncmp(buffer, "$GPGGA", 6)) {
466                /*                                                           1 1111
467                   0      1          2         3 4          5 6 7  8   9     0 1234
468                   $GPGGA,184424.505,4924.2811,N,01107.8846,E,1,05,2.5,408.6,M,,,,0000*0C
469                   UTC of Fix[1],Latitude[2],N/S[3],Longitude[4],E/W[5],Quality(0=inv,1=gps,2=dgps)[6],Satelites used[7],
470                   HDOP[8],Altitude[9],"M"[10],height of geoid[11], "M"[12], time since dgps update[13], dgps ref station [14]
471                 */
472                if (*item[2] && *item[3] && *item[4] && *item[5]) {
473                        lat = g_ascii_strtod(item[2], NULL);
474                        priv->geo.lat = floor(lat / 100);
475                        lat -= priv->geo.lat * 100;
476                        priv->geo.lat += lat / 60;
477
478                        if (!g_strcasecmp(item[3],"S"))
479                                priv->geo.lat=-priv->geo.lat;
480
481                        lng = g_ascii_strtod(item[4], NULL);
482                        priv->geo.lng = floor(lng / 100);
483                        lng -= priv->geo.lng * 100;
484                        priv->geo.lng += lng / 60;
485
486                        if (!g_strcasecmp(item[5],"W"))
487                                priv->geo.lng=-priv->geo.lng;
488                        priv->valid=attr_position_valid_valid;
489            dbg(2, "latitude '%2.4f' longitude %2.4f\n", priv->geo.lat, priv->geo.lng);
490
491                } else
492                        priv->valid=attr_position_valid_invalid;
493                if (*item[6]) {
494                        sscanf(item[6], "%d", &priv->status);
495                         /* check if a valid fix has been sent on NMEA port to allow callback */
496                        if (priv->status >= 1)
497                                ret = 1;
498                }
499                if (*item[7])
500                        sscanf(item[7], "%d", &priv->sats_used);
501                if (*item[8])
502                        sscanf(item[8], "%lf", &priv->hdop);
503                if (*item[1])
504                        strncpy(priv->fixtime, item[1], sizeof(priv->fixtime));
505                if (*item[9])
506                        sscanf(item[9], "%lf", &priv->height);
507
508                g_free(priv->nmea_data);
509                priv->nmea_data=priv->nmea_data_buf;
510                priv->nmea_data_buf=NULL;
511        }
512        if (!strncmp(buffer, "$GPVTG", 6)) {
513                /* 0      1      2 34 5    6 7   8
514                   $GPVTG,143.58,T,,M,0.26,N,0.5,K*6A
515                   Course Over Ground Degrees True[1],"T"[2],Course Over Ground Degrees Magnetic[3],"M"[4],
516                   Speed in Knots[5],"N"[6],"Speed in KM/H"[7],"K"[8]
517                 */
518                if (item[1] && item[7])
519                        valid = 1;
520                if (i >= 10 && (*item[9] == 'A' || *item[9] == 'D'))
521                        valid = 1;
522                if (valid) {
523                        priv->direction = g_ascii_strtod( item[1], NULL );
524                        priv->speed = g_ascii_strtod( item[7], NULL );
525                        dbg(2,"direction %lf, speed %2.1lf\n", priv->direction, priv->speed);
526                }
527        }
528        if (!strncmp(buffer, "$GPRMC", 6)) {
529                /*                                                           1     1
530                   0      1      2 3        4 5         6 7     8     9      0     1
531                   $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
532                   Time[1],Active/Void[2],lat[3],N/S[4],long[5],W/E[6],speed in knots[7],track angle[8],date[9],
533                   magnetic variation[10],magnetic variation direction[11]
534                 */
535                if (*item[2] == 'A')
536                        valid = 1;
537                if (i >= 13 && (*item[12] == 'A' || *item[12] == 'D'))
538                        valid = 1;
539                if (valid) {
540                        priv->direction = g_ascii_strtod( item[8], NULL );
541                        priv->speed = g_ascii_strtod( item[7], NULL );
542                        priv->speed *= 1.852;
543                        sscanf(item[9], "%02d%02d%02d",
544                                &priv->fixday,
545                                &priv->fixmonth,
546                                &priv->fixyear);
547                        priv->fixyear += 2000;
548                }
549                ret = 1;
550        }
551        if (!strncmp(buffer, "$GPGSV", 6) && i >= 4) {
552        /*
553                0 GSV      Satellites in view
554                1 2        Number of sentences for full data
555                2 1        sentence 1 of 2
556                3 08       Number of satellites in view
557
558                4 01       Satellite PRN number
559                5 40       Elevation, degrees
560                6 083      Azimuth, degrees
561                7 46       SNR - higher is better
562                           for up to 4 satellites per sentence
563                *75        the checksum data, always begins with *
564        */
565                if (item[3]) {
566                        sscanf(item[3], "%d", &priv->sats_visible);
567                }
568                j=4;
569                while (j+4 <= i && priv->current_count < 24) {
570                        struct gps_sat *sat=&priv->next[priv->next_count++];
571                        sat->prn=atoi(item[j]);
572                        sat->elevation=atoi(item[j+1]);
573                        sat->azimuth=atoi(item[j+2]);
574                        sat->snr=atoi(item[j+3]);
575                        j+=4;
576                }
577                if (!strcmp(item[1], item[2])) {
578                        priv->sats_signal=0;
579                        for (i = 0 ; i < priv->next_count ; i++) {
580                                priv->current[i]=priv->next[i];
581                                if (priv->current[i].snr)
582                                        priv->sats_signal++;
583                        }
584                        priv->current_count=priv->next_count;
585                        priv->next_count=0;
586                }
587        }
588        if (!strncmp(buffer, "$GPZDA", 6)) {
589        /*
590                0        1        2  3  4    5  6
591                $GPZDA,hhmmss.ss,dd,mm,yyyy,xx,yy*CC
592                        hhmmss    HrMinSec(UTC)
593                        dd,mm,yyy Day,Month,Year
594                        xx        local zone hours -13..13
595                        yy        local zone minutes 0..59
596        */
597                if (item[1] && item[2] && item[3] && item[4]) {
598                        strncpy(priv->fixtime, item[1], strlen(priv->fixtime));
599                        priv->fixday = atoi(item[2]);
600                        priv->fixmonth = atoi(item[3]);
601                        priv->fixyear = atoi(item[4]);
602                }
603        }
604        if (!strncmp(buffer, "$IISMD", 6)) {
605        /*
606                0      1   2     3      4
607                $IISMD,dir,press,height,temp*CC"
608                        dir       Direction (0-359)
609                        press     Pressure (hpa, i.e. 1032)
610                        height    Barometric height above ground (meter)
611                        temp      Temperature (Degree Celsius)
612        */
613                if (item[1]) {
614                        priv->magnetic_direction = g_ascii_strtod( item[1], NULL );
615                        dbg(1,"magnetic %d\n", priv->magnetic_direction);
616                }
617        }
618        return ret;
619}
620
621static void
622vehicle_wince_io(struct vehicle_priv *priv)
623{
624        int size, rc = 0;
625        char *str, *tok;
626
627        dbg(1, "vehicle_file_io : enter\n");
628
629        size = read_win32(priv, priv->buffer + priv->buffer_pos, buffer_size - priv->buffer_pos - 1);
630       
631        if (size <= 0) {
632                switch (priv->on_eof) {
633                case 0:
634                        vehicle_wince_close(priv);
635                        vehicle_wince_open(priv);
636                        break;
637                case 1:
638                        vehicle_wince_disable_watch(priv);
639                        break;
640                case 2:
641                        exit(0);
642                        break;
643                }
644                return;
645        }
646        priv->buffer_pos += size;
647        priv->buffer[priv->buffer_pos] = '\0';
648        dbg(1, "size=%d pos=%d buffer='%s'\n", size,
649            priv->buffer_pos, priv->buffer);
650        str = priv->buffer;
651        while ((tok = strchr(str, '\n'))) {
652                *tok++ = '\0';
653                dbg(1, "line='%s'\n", str);
654                rc +=vehicle_wince_parse(priv, str);
655                str = tok;
656                if (priv->file_type == file_type_file && rc)
657                        break;
658        }
659
660        if (str != priv->buffer) {
661                size = priv->buffer + priv->buffer_pos - str;
662                memmove(priv->buffer, str, size + 1);
663                priv->buffer_pos = size;
664                dbg(2, "now pos=%d buffer='%s'\n",
665                    priv->buffer_pos, priv->buffer);
666        } else if (priv->buffer_pos == buffer_size - 1) {
667                dbg(0,
668                    "Overflow. Most likely wrong baud rate or no nmea protocol\n");
669                priv->buffer_pos = 0;
670        }
671        if (rc)
672                callback_list_call_attr_0(priv->cbl, attr_position_coord_geo);
673}
674
675static void
676vehicle_wince_enable_watch(struct vehicle_priv *priv)
677{
678    dbg(1, "enter");
679        vehicle_wince_disable_watch(priv);
680        priv->is_running = 1;
681
682    InitializeCriticalSection(&priv->lock);
683    priv->m_hGPSThread = CreateThread(NULL, 0, wince_reader_thread,
684        priv, 0, &priv->m_dwGPSThread);
685
686        if (!priv->m_hGPSThread) {
687                priv->is_running = 0;
688                // error creating thread
689                MessageBox (NULL, TEXT ("Can not create GPS reader thread"), TEXT (""),
690                        MB_APPLMODAL|MB_OK);
691        }
692}
693
694static void
695vehicle_wince_disable_watch(struct vehicle_priv *priv)
696{
697        int wait = 5000;
698
699    dbg(1, "enter");
700
701        priv->is_running = 0;
702        while (wait-- > 0 && priv->thread_up) {
703                SwitchToThread();
704        }
705        if (priv->m_hGPSThread) {
706                // Terminate reader, sorry
707                TerminateThread(priv->m_hGPSThread, -1);
708        }
709}
710
711
712static void
713vehicle_wince_destroy(struct vehicle_priv *priv)
714{
715        vehicle_wince_disable_watch(priv);
716        vehicle_wince_close(priv);
717        if (priv->BthSetMode)
718        {
719                (void)priv->BthSetMode(0);
720                FreeLibrary(priv->hBthDll);
721        }
722        if (priv->source)
723                g_free(priv->source);
724        if (priv->buffer)
725                g_free(priv->buffer);
726        if (priv->read_buffer)
727                g_free(priv->read_buffer);
728        g_free(priv);
729}
730
731static int
732vehicle_wince_position_attr_get(struct vehicle_priv *priv,
733                               enum attr_type type, struct attr *attr)
734{
735        switch (type) {
736        case attr_position_fix_type:
737                attr->u.num = priv->status;
738                break;
739        case attr_position_height:
740                attr->u.numd = &priv->height;
741                break;
742        case attr_position_speed:
743                attr->u.numd = &priv->speed;
744                break;
745        case attr_position_direction:
746                attr->u.numd = &priv->direction;
747                break;
748        case attr_position_magnetic_direction:
749                attr->u.num = priv->magnetic_direction;
750                break;
751        case attr_position_hdop:
752                attr->u.numd = &priv->hdop;
753                break;
754        case attr_position_qual:
755                attr->u.num = priv->sats_visible;
756                break;
757        case attr_position_sats_signal:
758                attr->u.num = priv->sats_signal;
759                break;
760        case attr_position_sats_used:
761                attr->u.num = priv->sats_used;
762                break;
763        case attr_position_coord_geo:
764                attr->u.coord_geo = &priv->geo;
765                break;
766        case attr_position_nmea:
767                attr->u.str=priv->nmea_data;
768                if (! attr->u.str)
769                        return 0;
770                break;
771        case attr_position_time_iso8601:
772                if (!priv->fixyear || !priv->fixtime[0])
773                        return 0;
774                sprintf(priv->fixiso8601, "%04d-%02d-%02dT%.2s:%.2s:%sZ",
775                        priv->fixyear, priv->fixmonth, priv->fixday,
776                                                priv->fixtime, (priv->fixtime+2), (priv->fixtime+4));
777                attr->u.str=priv->fixiso8601;
778                break;
779        case attr_position_sat_item:
780                dbg(0,"at here\n");
781                priv->sat_item.id_lo++;
782                if (priv->sat_item.id_lo > priv->current_count) {
783                        priv->sat_item.id_lo=0;
784                        return 0;
785                }
786                attr->u.item=&priv->sat_item;
787                break;
788        case attr_position_valid:
789                attr->u.num=priv->valid;
790                break;
791        default:
792                return 0;
793        }
794        if (type != attr_position_sat_item)
795                priv->sat_item.id_lo=0;
796        attr->type = type;
797        return 1;
798}
799
800static int
801vehicle_wince_sat_attr_get(void *priv_data, enum attr_type type, struct attr *attr)
802{
803        struct vehicle_priv *priv=priv_data;
804    struct gps_sat *sat;
805
806        if (priv->sat_item.id_lo < 1)
807                return 0;
808        if (priv->sat_item.id_lo > priv->current_count)
809                return 0;
810        sat=&priv->current[priv->sat_item.id_lo-1];
811        switch (type) {
812        case attr_sat_prn:
813                attr->u.num=sat->prn;
814                break;
815        case attr_sat_elevation:
816                attr->u.num=sat->elevation;
817                break;
818        case attr_sat_azimuth:
819                attr->u.num=sat->azimuth;
820                break;
821        case attr_sat_snr:
822                attr->u.num=sat->snr;
823                break;
824        default:
825                return 0;
826        }
827        attr->type = type;
828        return 1;
829}
830
831static struct item_methods vehicle_wince_sat_methods = {
832        NULL,
833        NULL,
834        NULL,
835        vehicle_wince_sat_attr_get,
836        NULL,
837        NULL,
838        NULL,
839        NULL,
840};
841
842struct vehicle_methods vehicle_wince_methods = {
843        vehicle_wince_destroy,
844        vehicle_wince_position_attr_get,
845        NULL,
846};
847
848static struct vehicle_priv *
849vehicle_wince_new(struct vehicle_methods
850                      *meth, struct callback_list
851                      *cbl, struct attr **attrs)
852{
853        struct vehicle_priv *ret;
854        struct attr *source;
855        struct attr *time;
856        struct attr *on_eof;
857        struct attr *baudrate;
858        struct attr *checksum_ignore;
859        struct attr *handle_bluetooth;
860        char *cp;
861
862        dbg(1, "enter\n");
863        source = attr_search(attrs, NULL, attr_source);
864        ret = g_new0(struct vehicle_priv, 1);
865        ret->fd = -1;
866        ret->cbl = cbl;
867       
868        ret->file_type = file_type_device;
869        cp = strchr(source->u.str,':');
870        if (cp)
871        {
872            if ( strncmp(source->u.str, "file", 4) == 0 )
873                ret->file_type = file_type_file;
874                cp++;
875        }
876        else
877                cp = source->u.str;
878        ret->source = g_strdup(cp);
879        ret->buffer = g_malloc(buffer_size);
880        ret->time=1000;
881        ret->baudrate=0;        // do not change the rate if not configured
882
883        time = attr_search(attrs, NULL, attr_time);
884        if (time)
885                ret->time=time->u.num;
886        baudrate = attr_search(attrs, NULL, attr_baudrate);
887        if (baudrate) {
888                ret->baudrate = baudrate->u.num;
889        }
890        checksum_ignore = attr_search(attrs, NULL, attr_checksum_ignore);
891        if (checksum_ignore)
892                ret->checksum_ignore=checksum_ignore->u.num;
893        ret->attrs = attrs;
894        on_eof = attr_search(attrs, NULL, attr_on_eof);
895        if (on_eof && !g_strcasecmp(on_eof->u.str, "stop"))
896                ret->on_eof=1;
897        if (on_eof && !g_strcasecmp(on_eof->u.str, "exit"))
898                ret->on_eof=2;
899        dbg(0,"on_eof=%d\n", ret->on_eof);
900        *meth = vehicle_wince_methods;
901        ret->priv_cbl = callback_list_new();
902        callback_list_add(ret->priv_cbl, callback_new_1(callback_cast(vehicle_wince_io), ret));
903        ret->sat_item.type=type_position_sat;
904        ret->sat_item.id_hi=ret->sat_item.id_lo=0;
905        ret->sat_item.priv_data=ret;
906        ret->sat_item.meth=&vehicle_wince_sat_methods;
907
908    ret->read_buffer = g_malloc(buffer_size);
909
910        handle_bluetooth = attr_search(attrs, NULL, attr_bluetooth);
911        if ( handle_bluetooth && handle_bluetooth->u.num == 1 )
912                initBth(ret);
913
914        if (vehicle_wince_open(ret)) {
915                vehicle_wince_enable_watch(ret);
916                return ret;
917        }
918        dbg(0, "Failed to open '%s'\n", ret->source);
919        vehicle_wince_destroy(ret);
920        return NULL;
921}
922
923void
924plugin_init(void)
925{
926        dbg(1, "enter\n");
927        plugin_register_vehicle_type("wince", vehicle_wince_new);
928        plugin_register_vehicle_type("file", vehicle_wince_new);
929}