Ticket #699: vehicle_wince.c

File vehicle_wince.c, 23.4 KB (added by gregoire verlut, 10 years ago)

force re-init of the wince port if no data are received for more than 3 cycles (after suspend/resume)

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                {
186#ifndef IOCTL_SERVICE_REFRESH
187#define IOCTL_SERVICE_REFRESH 0x4100000C
188#endif
189                        DeviceIoControl(hGPS,IOCTL_SERVICE_REFRESH,0,0,0,0,0,0);
190#ifndef IOCTL_SERVICE_START
191#define IOCTL_SERVICE_START 0x41000004
192#endif
193                      DeviceIoControl(hGPS,IOCTL_SERVICE_START,0,0,0,0,0,0);
194                      CloseHandle(hGPS);
195                }
196
197                while (priv->is_running &&
198                        (priv->m_hGPSDevice = CreateFile(A2W(priv->source),
199                                GENERIC_READ, 0,
200                                NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
201                {
202                        Sleep(1000);
203                        dbg(0, "Waiting to connect to %s\n", priv->source);
204                }
205                GetCommTimeouts (priv->m_hGPSDevice, &commTiming);
206                commTiming.ReadIntervalTimeout = 20;
207                commTiming.ReadTotalTimeoutMultiplier = 0;
208                commTiming.ReadTotalTimeoutConstant = 200;
209
210                commTiming.WriteTotalTimeoutMultiplier=5;
211                commTiming.WriteTotalTimeoutConstant=5;
212                SetCommTimeouts (priv->m_hGPSDevice, &commTiming);
213
214                if (priv->baudrate)
215                {
216                        DCB portState;
217                        if (!GetCommState(priv->m_hGPSDevice, &portState))
218                        {
219                                MessageBox (NULL, TEXT ("GetCommState Error"), TEXT (""),
220                                        MB_APPLMODAL|MB_OK);
221                                priv->thread_up = 0;
222                                return 0;
223                        }
224                        portState.BaudRate = priv->baudrate;
225                        if (!SetCommState(priv->m_hGPSDevice, &portState))
226                        {
227                                MessageBox (NULL, TEXT ("SetCommState Error"), TEXT (""),
228                                        MB_APPLMODAL|MB_OK);
229                                priv->thread_up = 0;
230                                return 0;
231                        }
232                }
233           
234        }
235        else
236        {
237                dbg(0, "Open File\n");
238                priv->m_hGPSDevice = CreateFileW( A2W(priv->source),
239                          GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
240                if ( priv->m_hGPSDevice == INVALID_HANDLE_VALUE)
241                {
242                        dbg(0, "Could not open %s\n", priv->source);
243                        return 0;
244                }
245        }
246        return 1;
247   
248}
249
250static int read_win32(struct vehicle_priv *priv, char *buffer, size_t size)
251{
252    int ret_size;
253
254    g_mutex_lock(&priv->lock);
255    ret_size = MIN(size,priv->read_buffer_pos);
256    priv->has_data = 0;
257    memcpy(buffer, priv->read_buffer, ret_size);
258   
259    memmove(priv->read_buffer, priv->read_buffer + ret_size, buffer_size - ret_size);
260    priv->read_buffer_pos -= ret_size;
261    g_mutex_unlock(&priv->lock);
262    return ret_size;
263}
264
265static DWORD WINAPI wince_reader_thread (LPVOID lParam)
266{
267        struct vehicle_priv *priv = lParam;
268        char chunk_buffer[3*82];
269        BOOL status;
270        DWORD bytes_read;
271        int waitcounter;
272        int nullcounter;
273 
274 
275        dbg(0, "GPS Port:[%s]\n", priv->source);
276        priv->thread_up = 1;
277 
278        if ( !initDevice(priv) ) {
279                return -1;
280        }
281        nullcounter = 0;
282       
283        while (priv->is_running)
284        {
285//              dbg(1,"readfile");
286                waitcounter = 0;
287                status = ReadFile(priv->m_hGPSDevice,
288                        chunk_buffer, sizeof(chunk_buffer),
289                        &bytes_read, NULL);
290                dbg(1,"readfile %d\n", bytes_read);
291               
292                if ( !status )
293                {
294                        dbg(0,"Error reading file/device. Try again.\n");
295                        initDevice(priv);
296                        continue;
297                } else
298                {
299                        if ( !bytes_read )
300                        {
301                                nullcounter++;
302                                if (nullcounter >= 3)
303                                {
304                                        dbg(0,"Nmea port muted.\n");
305                                        initDevice(priv);
306                                        nullcounter = 0;
307                                        continue;
308                                       
309                                }
310                        } else
311                        {
312                          nullcounter = 0;
313                        }
314               
315                }
316   
317                while ( priv->read_buffer_pos + bytes_read > buffer_size )
318                {
319     
320                        /* TODO (rikky#1#): should use blocking */
321                        if ( priv->file_type != file_type_file )
322                        {
323                                dbg(0, "GPS data comes too fast. Have to wait here %d\n", priv->read_buffer_pos + bytes_read - buffer_size);
324                        }
325     
326                        Sleep(50);
327                        waitcounter++;
328                        if ( waitcounter % 8 == 0 )
329                        {
330                                dbg(0, "Remind them of the data\n");
331                                event_call_callback(priv->priv_cbl);
332                        }
333     
334                }
335   
336                g_mutex_lock(&priv->lock);
337                memcpy(priv->read_buffer + priv->read_buffer_pos , chunk_buffer, bytes_read );
338   
339                priv->read_buffer_pos += bytes_read;
340   
341                if ( !priv->has_data )
342                {
343                        event_call_callback(priv->priv_cbl);
344                        priv->has_data = 1;
345                }
346   
347                g_mutex_unlock(&priv->lock);
348   
349        }
350        return TRUE;
351}
352
353static int
354vehicle_wince_available_ports(void)
355{
356        HKEY hkResult;
357        HKEY hkSubResult;
358        wchar_t keyname[20];
359        wchar_t devicename[100];
360        wchar_t devicetype[100];
361        int index = 0;
362        DWORD regkey_length = sizeof(keyname);
363        DWORD regdevtype_length = sizeof(devicetype);
364       
365        RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Drivers\\Active"), 0, 0, &hkResult);
366        while (RegEnumKeyEx( hkResult, index++, keyname, &regkey_length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS )
367        {
368                if (RegOpenKeyEx( hkResult, keyname, 0, 0, &hkSubResult) == ERROR_SUCCESS )
369                {
370                        regkey_length = sizeof(keyname);
371                        if ( RegQueryValueEx( hkSubResult,  L"Name", NULL, NULL, (LPBYTE)devicename, &regkey_length) == ERROR_SUCCESS )
372                        {
373                                regdevtype_length = sizeof(devicetype);
374                                if ( RegQueryValueEx( hkSubResult, L"Key", NULL, NULL, (LPBYTE)devicetype, &regdevtype_length) == ERROR_SUCCESS )
375                                {
376                                        dbg(0, "Found device '%s' (%s)\n", W2A(devicename), W2A(devicetype));
377                                }
378                                else
379                                {
380                                        dbg(0, "Found device '%s'\n", W2A(devicename));
381                                }
382                        }
383                        RegCloseKey(hkSubResult);
384                }
385                regkey_length = sizeof(keyname);
386        }
387
388        RegCloseKey(hkResult);
389        return 0;
390}
391
392
393static int
394vehicle_wince_open(struct vehicle_priv *priv)
395{
396    char* raw_setting_str;
397    char* strport;
398    char* strsettings;
399
400        dbg(1, "enter vehicle_wince_open, priv->source='%s'\n", priv->source);
401
402        if (priv->source ) {
403
404                if ( strcmp(priv->source, "list") == 0 )
405                {
406                        vehicle_wince_available_ports();
407                        return 0;
408                }
409
410                raw_setting_str = g_strdup( priv->source );
411                strport = strchr(raw_setting_str, ':' );
412                strsettings = strchr(raw_setting_str, ' ' );
413
414                if (raw_setting_str && strport&&strsettings ) {
415                        strport++;
416                        *strsettings = '\0';
417                        strsettings++;
418
419                        dbg(0, "serial('%s', '%s')\n", strport, strsettings );
420                }
421                if (raw_setting_str)
422                g_free( raw_setting_str );
423        }
424        return 1;
425}
426
427static void
428vehicle_wince_close(struct vehicle_priv *priv)
429{
430    dbg(1,"enter");
431}
432
433static int
434vehicle_wince_parse(struct vehicle_priv *priv, char *buffer)
435{
436        char *nmea_data_buf, *p, *item[32];
437        double lat, lng;
438        int i, j, bcsum;
439        int len = strlen(buffer);
440        unsigned char csum = 0;
441        int valid=0;
442        int ret = 0;
443
444        dbg(2, "enter: buffer='%s'\n", buffer);
445        for (;;) {
446                if (len < 4) {
447                        dbg(0, "'%s' too short\n", buffer);
448                        return ret;
449                }
450                if (buffer[len - 1] == '\r' || buffer[len - 1] == '\n') {
451                        buffer[--len] = '\0';
452            if (buffer[len - 1] == '\r')
453                buffer[--len] = '\0';
454        } else
455                        break;
456        }
457        if (buffer[0] != '$') {
458                dbg(0, "no leading $ in '%s'\n", buffer);
459                return ret;
460        }
461        if (buffer[len - 3] != '*') {
462                dbg(0, "no *XX in '%s'\n", buffer);
463                return ret;
464        }
465        for (i = 1; i < len - 3; i++) {
466                csum ^= (unsigned char) (buffer[i]);
467        }
468        if (!sscanf(buffer + len - 2, "%x", &bcsum) && priv->checksum_ignore != 2) {
469                dbg(0, "no checksum in '%s'\n", buffer);
470                return ret;
471        }
472        if (bcsum != csum && priv->checksum_ignore == 0) {
473                dbg(0, "wrong checksum in '%s'\n", buffer);
474                return ret;
475        }
476
477        if (!priv->nmea_data_buf || strlen(priv->nmea_data_buf) < 65536) {
478                nmea_data_buf=g_strconcat(priv->nmea_data_buf ? priv->nmea_data_buf : "", buffer, "\n", NULL);
479                g_free(priv->nmea_data_buf);
480                priv->nmea_data_buf=nmea_data_buf;
481        } else {
482                dbg(0, "nmea buffer overflow, discarding '%s'\n", buffer);
483        }
484        i = 0;
485        p = buffer;
486        while (i < 31) {
487                item[i++] = p;
488                while (*p && *p != ',')
489                        p++;
490                if (!*p)
491                        break;
492                *p++ = '\0';
493        }
494
495        if (!strncmp(buffer, "$GPGGA", 6)) {
496                /*                                                           1 1111
497                   0      1          2         3 4          5 6 7  8   9     0 1234
498                   $GPGGA,184424.505,4924.2811,N,01107.8846,E,1,05,2.5,408.6,M,,,,0000*0C
499                   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],
500                   HDOP[8],Altitude[9],"M"[10],height of geoid[11], "M"[12], time since dgps update[13], dgps ref station [14]
501                 */
502                if (*item[2] && *item[3] && *item[4] && *item[5]) {
503                        lat = g_ascii_strtod(item[2], NULL);
504                        priv->geo.lat = floor(lat / 100);
505                        lat -= priv->geo.lat * 100;
506                        priv->geo.lat += lat / 60;
507
508                        if (!g_strcasecmp(item[3],"S"))
509                                priv->geo.lat=-priv->geo.lat;
510
511                        lng = g_ascii_strtod(item[4], NULL);
512                        priv->geo.lng = floor(lng / 100);
513                        lng -= priv->geo.lng * 100;
514                        priv->geo.lng += lng / 60;
515
516                        if (!g_strcasecmp(item[5],"W"))
517                                priv->geo.lng=-priv->geo.lng;
518                        priv->valid=attr_position_valid_valid;
519            dbg(2, "latitude '%2.4f' longitude %2.4f\n", priv->geo.lat, priv->geo.lng);
520
521                } else
522                        priv->valid=attr_position_valid_invalid;
523                if (*item[6]) {
524                        sscanf(item[6], "%d", &priv->status);
525                         /* check if a valid fix has been sent on NMEA port to allow callback */
526                        if (priv->status >= 1)
527                                ret = 1;
528                }
529                if (*item[7])
530                        sscanf(item[7], "%d", &priv->sats_used);
531                if (*item[8])
532                        sscanf(item[8], "%lf", &priv->hdop);
533                if (*item[1])
534                        strncpy(priv->fixtime, item[1], sizeof(priv->fixtime));
535                if (*item[9])
536                        sscanf(item[9], "%lf", &priv->height);
537
538                g_free(priv->nmea_data);
539                priv->nmea_data=priv->nmea_data_buf;
540                priv->nmea_data_buf=NULL;
541        }
542        if (!strncmp(buffer, "$GPVTG", 6)) {
543                /* 0      1      2 34 5    6 7   8
544                   $GPVTG,143.58,T,,M,0.26,N,0.5,K*6A
545                   Course Over Ground Degrees True[1],"T"[2],Course Over Ground Degrees Magnetic[3],"M"[4],
546                   Speed in Knots[5],"N"[6],"Speed in KM/H"[7],"K"[8]
547                 */
548                if (item[1] && item[7])
549                        valid = 1;
550                if (i >= 10 && (*item[9] == 'A' || *item[9] == 'D'))
551                        valid = 1;
552                if (valid) {
553                        priv->direction = g_ascii_strtod( item[1], NULL );
554                        priv->speed = g_ascii_strtod( item[7], NULL );
555                        dbg(2,"direction %lf, speed %2.1lf\n", priv->direction, priv->speed);
556                }
557        }
558        if (!strncmp(buffer, "$GPRMC", 6)) {
559                /*                                                           1     1
560                   0      1      2 3        4 5         6 7     8     9      0     1
561                   $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
562                   Time[1],Active/Void[2],lat[3],N/S[4],long[5],W/E[6],speed in knots[7],track angle[8],date[9],
563                   magnetic variation[10],magnetic variation direction[11]
564                 */
565                if (*item[2] == 'A')
566                        valid = 1;
567                if (i >= 13 && (*item[12] == 'A' || *item[12] == 'D'))
568                        valid = 1;
569                if (valid) {
570                        priv->direction = g_ascii_strtod( item[8], NULL );
571                        priv->speed = g_ascii_strtod( item[7], NULL );
572                        priv->speed *= 1.852;
573                        sscanf(item[9], "%02d%02d%02d",
574                                &priv->fixday,
575                                &priv->fixmonth,
576                                &priv->fixyear);
577                        priv->fixyear += 2000;
578                }
579                ret = 1;
580        }
581        if (!strncmp(buffer, "$GPGSV", 6) && i >= 4) {
582        /*
583                0 GSV      Satellites in view
584                1 2        Number of sentences for full data
585                2 1        sentence 1 of 2
586                3 08       Number of satellites in view
587
588                4 01       Satellite PRN number
589                5 40       Elevation, degrees
590                6 083      Azimuth, degrees
591                7 46       SNR - higher is better
592                           for up to 4 satellites per sentence
593                *75        the checksum data, always begins with *
594        */
595                if (item[3]) {
596                        sscanf(item[3], "%d", &priv->sats_visible);
597                }
598                j=4;
599                while (j+4 <= i && priv->current_count < 24) {
600                        struct gps_sat *sat=&priv->next[priv->next_count++];
601                        sat->prn=atoi(item[j]);
602                        sat->elevation=atoi(item[j+1]);
603                        sat->azimuth=atoi(item[j+2]);
604                        sat->snr=atoi(item[j+3]);
605                        j+=4;
606                }
607                if (!strcmp(item[1], item[2])) {
608                        priv->sats_signal=0;
609                        for (i = 0 ; i < priv->next_count ; i++) {
610                                priv->current[i]=priv->next[i];
611                                if (priv->current[i].snr)
612                                        priv->sats_signal++;
613                        }
614                        priv->current_count=priv->next_count;
615                        priv->next_count=0;
616                }
617        }
618        if (!strncmp(buffer, "$GPZDA", 6)) {
619        /*
620                0        1        2  3  4    5  6
621                $GPZDA,hhmmss.ss,dd,mm,yyyy,xx,yy*CC
622                        hhmmss    HrMinSec(UTC)
623                        dd,mm,yyy Day,Month,Year
624                        xx        local zone hours -13..13
625                        yy        local zone minutes 0..59
626        */
627                if (item[1] && item[2] && item[3] && item[4]) {
628                        strncpy(priv->fixtime, item[1], strlen(priv->fixtime));
629                        priv->fixday = atoi(item[2]);
630                        priv->fixmonth = atoi(item[3]);
631                        priv->fixyear = atoi(item[4]);
632                }
633        }
634        if (!strncmp(buffer, "$IISMD", 6)) {
635        /*
636                0      1   2     3      4
637                $IISMD,dir,press,height,temp*CC"
638                        dir       Direction (0-359)
639                        press     Pressure (hpa, i.e. 1032)
640                        height    Barometric height above ground (meter)
641                        temp      Temperature (Degree Celsius)
642        */
643                if (item[1]) {
644                        priv->magnetic_direction = g_ascii_strtod( item[1], NULL );
645                        dbg(1,"magnetic %d\n", priv->magnetic_direction);
646                }
647        }
648        return ret;
649}
650
651static void
652vehicle_wince_io(struct vehicle_priv *priv)
653{
654        int size, rc = 0;
655        char *str, *tok;
656
657        dbg(1, "vehicle_file_io : enter\n");
658
659        size = read_win32(priv, priv->buffer + priv->buffer_pos, buffer_size - priv->buffer_pos - 1);
660       
661        if (size <= 0) {
662                switch (priv->on_eof) {
663                case 0:
664                        vehicle_wince_close(priv);
665                        vehicle_wince_open(priv);
666                        break;
667                case 1:
668                        vehicle_wince_disable_watch(priv);
669                        break;
670                case 2:
671                        exit(0);
672                        break;
673                }
674                return;
675        }
676        priv->buffer_pos += size;
677        priv->buffer[priv->buffer_pos] = '\0';
678        dbg(1, "size=%d pos=%d buffer='%s'\n", size,
679            priv->buffer_pos, priv->buffer);
680        str = priv->buffer;
681        while ((tok = strchr(str, '\n'))) {
682                *tok++ = '\0';
683                dbg(1, "line='%s'\n", str);
684                rc +=vehicle_wince_parse(priv, str);
685                str = tok;
686                if (priv->file_type == file_type_file && rc)
687                        break;
688        }
689
690        if (str != priv->buffer) {
691                size = priv->buffer + priv->buffer_pos - str;
692                memmove(priv->buffer, str, size + 1);
693                priv->buffer_pos = size;
694                dbg(2, "now pos=%d buffer='%s'\n",
695                    priv->buffer_pos, priv->buffer);
696        } else if (priv->buffer_pos == buffer_size - 1) {
697                dbg(0,
698                    "Overflow. Most likely wrong baud rate or no nmea protocol\n");
699                priv->buffer_pos = 0;
700        }
701        if (rc)
702                callback_list_call_attr_0(priv->cbl, attr_position_coord_geo);
703}
704
705static void
706vehicle_wince_enable_watch(struct vehicle_priv *priv)
707{
708    dbg(1, "enter");
709        vehicle_wince_disable_watch(priv);
710        priv->is_running = 1;
711
712    InitializeCriticalSection(&priv->lock);
713    priv->m_hGPSThread = CreateThread(NULL, 0, wince_reader_thread,
714        priv, 0, &priv->m_dwGPSThread);
715
716        if (!priv->m_hGPSThread) {
717                priv->is_running = 0;
718                // error creating thread
719                MessageBox (NULL, TEXT ("Can not create GPS reader thread"), TEXT (""),
720                        MB_APPLMODAL|MB_OK);
721        }
722}
723
724static void
725vehicle_wince_disable_watch(struct vehicle_priv *priv)
726{
727        int wait = 5000;
728
729    dbg(1, "enter");
730
731        priv->is_running = 0;
732        while (wait-- > 0 && priv->thread_up) {
733                SwitchToThread();
734        }
735        if (priv->m_hGPSThread) {
736                // Terminate reader, sorry
737                TerminateThread(priv->m_hGPSThread, -1);
738        }
739}
740
741
742static void
743vehicle_wince_destroy(struct vehicle_priv *priv)
744{
745        vehicle_wince_disable_watch(priv);
746        vehicle_wince_close(priv);
747        if (priv->BthSetMode)
748        {
749                (void)priv->BthSetMode(0);
750                FreeLibrary(priv->hBthDll);
751        }
752        if (priv->source)
753                g_free(priv->source);
754        if (priv->buffer)
755                g_free(priv->buffer);
756        if (priv->read_buffer)
757                g_free(priv->read_buffer);
758        g_free(priv);
759}
760
761static int
762vehicle_wince_position_attr_get(struct vehicle_priv *priv,
763                               enum attr_type type, struct attr *attr)
764{
765        switch (type) {
766        case attr_position_fix_type:
767                attr->u.num = priv->status;
768                break;
769        case attr_position_height:
770                attr->u.numd = &priv->height;
771                break;
772        case attr_position_speed:
773                attr->u.numd = &priv->speed;
774                break;
775        case attr_position_direction:
776                attr->u.numd = &priv->direction;
777                break;
778        case attr_position_magnetic_direction:
779                attr->u.num = priv->magnetic_direction;
780                break;
781        case attr_position_hdop:
782                attr->u.numd = &priv->hdop;
783                break;
784        case attr_position_qual:
785                attr->u.num = priv->sats_visible;
786                break;
787        case attr_position_sats_signal:
788                attr->u.num = priv->sats_signal;
789                break;
790        case attr_position_sats_used:
791                attr->u.num = priv->sats_used;
792                break;
793        case attr_position_coord_geo:
794                attr->u.coord_geo = &priv->geo;
795                break;
796        case attr_position_nmea:
797                attr->u.str=priv->nmea_data;
798                if (! attr->u.str)
799                        return 0;
800                break;
801        case attr_position_time_iso8601:
802                if (!priv->fixyear || !priv->fixtime[0])
803                        return 0;
804                sprintf(priv->fixiso8601, "%04d-%02d-%02dT%.2s:%.2s:%sZ",
805                        priv->fixyear, priv->fixmonth, priv->fixday,
806                                                priv->fixtime, (priv->fixtime+2), (priv->fixtime+4));
807                attr->u.str=priv->fixiso8601;
808                break;
809        case attr_position_sat_item:
810                dbg(0,"at here\n");
811                priv->sat_item.id_lo++;
812                if (priv->sat_item.id_lo > priv->current_count) {
813                        priv->sat_item.id_lo=0;
814                        return 0;
815                }
816                attr->u.item=&priv->sat_item;
817                break;
818        case attr_position_valid:
819                attr->u.num=priv->valid;
820                break;
821        default:
822                return 0;
823        }
824        if (type != attr_position_sat_item)
825                priv->sat_item.id_lo=0;
826        attr->type = type;
827        return 1;
828}
829
830static int
831vehicle_wince_sat_attr_get(void *priv_data, enum attr_type type, struct attr *attr)
832{
833        struct vehicle_priv *priv=priv_data;
834    struct gps_sat *sat;
835
836        if (priv->sat_item.id_lo < 1)
837                return 0;
838        if (priv->sat_item.id_lo > priv->current_count)
839                return 0;
840        sat=&priv->current[priv->sat_item.id_lo-1];
841        switch (type) {
842        case attr_sat_prn:
843                attr->u.num=sat->prn;
844                break;
845        case attr_sat_elevation:
846                attr->u.num=sat->elevation;
847                break;
848        case attr_sat_azimuth:
849                attr->u.num=sat->azimuth;
850                break;
851        case attr_sat_snr:
852                attr->u.num=sat->snr;
853                break;
854        default:
855                return 0;
856        }
857        attr->type = type;
858        return 1;
859}
860
861static struct item_methods vehicle_wince_sat_methods = {
862        NULL,
863        NULL,
864        NULL,
865        vehicle_wince_sat_attr_get,
866        NULL,
867        NULL,
868        NULL,
869        NULL,
870};
871
872struct vehicle_methods vehicle_wince_methods = {
873        vehicle_wince_destroy,
874        vehicle_wince_position_attr_get,
875        NULL,
876};
877
878static struct vehicle_priv *
879vehicle_wince_new(struct vehicle_methods
880                      *meth, struct callback_list
881                      *cbl, struct attr **attrs)
882{
883        struct vehicle_priv *ret;
884        struct attr *source;
885        struct attr *time;
886        struct attr *on_eof;
887        struct attr *baudrate;
888        struct attr *checksum_ignore;
889        struct attr *handle_bluetooth;
890        char *cp;
891
892        dbg(1, "enter\n");
893        source = attr_search(attrs, NULL, attr_source);
894        ret = g_new0(struct vehicle_priv, 1);
895        ret->fd = -1;
896        ret->cbl = cbl;
897       
898        ret->file_type = file_type_device;
899        cp = strchr(source->u.str,':');
900        if (cp)
901        {
902            if ( strncmp(source->u.str, "file", 4) == 0 )
903                ret->file_type = file_type_file;
904                cp++;
905        }
906        else
907                cp = source->u.str;
908        ret->source = g_strdup(cp);
909        ret->buffer = g_malloc(buffer_size);
910        ret->time=1000;
911        ret->baudrate=0;        // do not change the rate if not configured
912
913        time = attr_search(attrs, NULL, attr_time);
914        if (time)
915                ret->time=time->u.num;
916        baudrate = attr_search(attrs, NULL, attr_baudrate);
917        if (baudrate) {
918                ret->baudrate = baudrate->u.num;
919        }
920        checksum_ignore = attr_search(attrs, NULL, attr_checksum_ignore);
921        if (checksum_ignore)
922                ret->checksum_ignore=checksum_ignore->u.num;
923        ret->attrs = attrs;
924        on_eof = attr_search(attrs, NULL, attr_on_eof);
925        if (on_eof && !g_strcasecmp(on_eof->u.str, "stop"))
926                ret->on_eof=1;
927        if (on_eof && !g_strcasecmp(on_eof->u.str, "exit"))
928                ret->on_eof=2;
929        dbg(0,"on_eof=%d\n", ret->on_eof);
930        *meth = vehicle_wince_methods;
931        ret->priv_cbl = callback_list_new();
932        callback_list_add(ret->priv_cbl, callback_new_1(callback_cast(vehicle_wince_io), ret));
933        ret->sat_item.type=type_position_sat;
934        ret->sat_item.id_hi=ret->sat_item.id_lo=0;
935        ret->sat_item.priv_data=ret;
936        ret->sat_item.meth=&vehicle_wince_sat_methods;
937
938    ret->read_buffer = g_malloc(buffer_size);
939
940        handle_bluetooth = attr_search(attrs, NULL, attr_bluetooth);
941        if ( handle_bluetooth && handle_bluetooth->u.num == 1 )
942                initBth(ret);
943
944        if (vehicle_wince_open(ret)) {
945                vehicle_wince_enable_watch(ret);
946                return ret;
947        }
948        dbg(0, "Failed to open '%s'\n", ret->source);
949        vehicle_wince_destroy(ret);
950        return NULL;
951}
952
953void
954plugin_init(void)
955{
956        dbg(1, "enter\n");
957        plugin_register_vehicle_type("wince", vehicle_wince_new);
958        plugin_register_vehicle_type("file", vehicle_wince_new);
959}