Recent

Author Topic: GPSID (Intermediate Driver) - a proper way to use it, once and for all!  (Read 10361 times)

Barvinok

  • Newbie
  • Posts: 6
    • SciLog forum
This article explains how to use GPSID (GPS Intermediate Driver) interface provided in Windows Mobile 5 and 6, using FreePascal. Source code and pictures of a real device in the field is included.

STEP 1 - Configure the registry
This step is not necessary if your firmware have GPSID settings configured properly by default. I was not that lucky since I used third-party WM6 firmware package made by local enthusiasts.

Check out this MSDN page dealing with GPSID registry settings, and, using any registry editor you like (I used TotalCommander) make sure the registry settings is consistent (at least, CommPort and Baud are set according to what is configured in the Control Panel => External GPS on your device).

STEP 2 - Compile source code
For simplicity reasons, this source code generates console application, so, in order to see its output, you need to install Console subsystem for Windows Mobile. Of course, you don't need to install console if you use the code just as reference.

Unit containing GPSID interface class
Code: [Select]
unit bccGPSID;

interface

uses GPSAPI;

TYPE TGPSEvents = (evLocData = 0, evDevState = 1);

     TOnPosition = procedure(Sender : TObject) of object;

TYPE

{ TGPS }

TGPS = class
      constructor Create;
      destructor Destroy; override;
     private
      Events : array [TGPSEvents] of THandle;
      hGPS : THandle;
      FPosition,FPrevPos : GPS_POSITION;
      FPosBuffer : Pointer;
      FMovementFilter : LongBool;
      RealSizeOf : Cardinal;
      EOnPosition : TOnPosition;
      procedure DirtyHack_FindSize;
      procedure CopyAndInvoke;
     public
      function Start : LongBool;
      procedure Stop;
      procedure ProcessMessages;
      function CheckValidity(const Validity : Cardinal) : LongBool;
      property Position : GPS_POSITION read FPosition;
      property MovementFilter : LongBool read FMovementFilter write FMovementFilter;
      property OnPosition : TOnPosition read EOnPosition write EOnPosition;
     end;

implementation

uses Windows;

CONST DefaultAge = 60*1000; // milliseconds

constructor TGPS.Create;
begin
 inherited Create;
 Events[evLocData]:=CreateEvent(nil,False,False,nil);
 Events[evDevState]:=CreateEvent(nil,False,False,nil);
 hGPS:=0;
 RealSizeOf:=SizeOf(GPS_POSITION);
 DirtyHack_FindSize;
 FPosBuffer:=HeapAlloc(GetProcessHeap,HEAP_ZERO_MEMORY,RealSizeOf);
 FillChar(FPrevPos,SizeOf(GPS_POSITION),$00);
 FMovementFilter:=True;
end;

destructor TGPS.Destroy;
begin
 Stop;
 CloseHandle(Events[evDevState]);
 CloseHandle(Events[evLocData]);
 HeapFree(GetProcessHeap,0,FPosBuffer);
 inherited Destroy;
end;

procedure TGPS.DirtyHack_FindSize;
const HackRange = $100;
var i : Cardinal;
begin
 FillChar(FPosition,SizeOf(GPS_POSITION),$00);
 FPosition.dwVersion:=GPS_VERSION_CURRENT;
 for i:=SizeOf(GPS_POSITION) to SizeOf(GPS_POSITION)+HackRange do
  begin
   FPosition.dwSize:=i;
   if (GPSGetPosition(0,@FPosition,0,0)=ERROR_SUCCESS) then
    begin
     RealSizeOf:=i;
     Break;
    end;
  end;
end;

procedure TGPS.CopyAndInvoke;
begin
 memmove(@FPrevPos,@FPosition,SizeOf(GPS_POSITION));
 if Assigned(EOnPosition) then EOnPosition(Self);
end;

function TGPS.Start : LongBool;
begin
 Result:=False;
 if (hGPS=0) then
  begin
   hGPS:=GPSOpenDevice(Events[evLocData],Events[evDevState],nil,0);
   Result:=(hGPS<>0);
  end;
end;

procedure TGPS.Stop;
begin
 if (hGPS<>0) then
  if (GPSCloseDevice(hGPS)=ERROR_SUCCESS) then hGPS:=0;
end;

procedure TGPS.ProcessMessages;
var WFOR : Cardinal;
begin
 WFOR:=WaitForMultipleObjects(2,@Events,False,0);
 case WFOR of
  WAIT_OBJECT_0 : begin
                   // retrieve position
                   FillChar(FPosBuffer^,RealSizeOf,$00);
                   GPS_POSITION(FPosBuffer^).dwVersion:=GPS_VERSION_CURRENT;
                   GPS_POSITION(FPosBuffer^).dwSize:=RealSizeOf;
                   if (GPSGetPosition(hGPS,FPosBuffer,DefaultAge,0)=ERROR_SUCCESS) then
                    begin
                     // copy retrieved data to property field
                     memmove(@FPosition,FPosBuffer,SizeOf(GPS_POSITION));
                     // check against movement filter, and apply if necessary
                     if (FMovementFilter) then
                      begin
                       if not (
                               (FPosition.dblLongitude=FPrevPos.dblLongitude) and
                               (FPosition.dblLatitude=FPrevPos.dblLatitude) and
                               (FPosition.flAltitudeWRTEllipsoid=FPrevPos.flAltitudeWRTEllipsoid) and
                               (FPosition.flAltitudeWRTSeaLevel=FPrevPos.flAltitudeWRTSeaLevel)
                               ) then CopyAndInvoke;
                      end
                       else CopyAndInvoke;
                    end;
                  end;
  WAIT_OBJECT_0+1 : {I wonder what should happen?};
 end;
end;

function TGPS.CheckValidity(const Validity : Cardinal) : LongBool;
begin
 Result:=(FPosition.dwValidFields and Validity)=Validity;
end;

end.

Example program using unit above
Code: [Select]
{$APPTYPE CONSOLE}
program GPSIDemo;

uses Windows, GPSAPI, bccGPSID;

TYPE TMyGPS = class(TGPS)
      procedure Handler_OnPosition(Sender : TObject);
     end;

procedure TMyGPS.Handler_OnPosition(Sender : TObject);
begin
 Writeln;
 with Position do
  begin
   if CheckValidity(GPS_VALID_LATITUDE or GPS_VALID_LONGITUDE) then Writeln('Coordinates = ',dblLatitude : 3 : 5,' : ',dblLongitude : 3 : 5);
   if CheckValidity(GPS_VALID_SPEED or GPS_VALID_HEADING) then      Writeln('Speed & Hdg = ',flSpeed : 3 : 1,' & ',flHeading : 3 : 1);
   if CheckValidity(GPS_VALID_ALTITUDE_WRT_SEA_LEVEL) then          Writeln('Elevation   = ',flAltitudeWRTSeaLevel : 4 : 1);
  end;
end;

var i : Cardinal;

begin
 with TMyGPS.Create do
  begin
   OnPosition:=Handler_OnPosition();
   if Start then
    begin
     Writeln('GPS started');
     for i:=$00 to $FF do // use whatever bounds you want
      begin
       Write('.');
       ProcessMessages;
       Sleep(1000); // check every one second
      end;
     Stop;
    end
     else Writeln('GPS failed to start');
   Free;
  end;
end.

STEP 3 - Compile and run it for your device. Don't forget to specify target OS and CPU family.
For my testing purposes I used ETEN Glofiish X650, which is running Windows Mobile 6 on ARM CPU. Go outside and run it, enjoy:
http://pic.ipicture.ru/uploads/090731/X45V2RRJtf.jpg
 8-)
« Last Edit: July 31, 2009, 02:18:09 pm by Barvinok »
Unlike reality, stupidity is inescapable

 

TinyPortal © 2005-2018