http://www8.garmin.com/support/commProtocol.html
This is a translation from the C sample program to PB.
I just bought a Garmin Forerunner and I'm investigating how to connect to it to exctract data.
Don't ask me questions on that because still I don't know anything ! Just downloaded the IOSDK.zip and started to convert the sample program to see what that would mean.
I'll look into the documentation in the future and hopefully will develop a complete sw layer to communicate with it.
Thought to share the sample code to help anyone else interested on the subject.
Bye!
Code: Select all
; Ported to PB by Luis on Oct, 5 2009
; Compile as a CONSOLE application.
; Tested with a Garmin Forerunner 205 and PB 4.31 x86.
; On my unit it prints: "Forerunner205 Software Version 2.90"
; This is a 1:1 conversion from the original C code.
; The original C program with the PDF documentation can be found
; here: http://www8.garmin.com/support/commProtocol.html
; ORIGINAL DISCLAIMER
; This file contains sample code to help application developers
; interface with Garmin USB units. This should not be viewed as a
; full implementation of PC to unit communication. It does not include
; error checking and other elements of a full implementation.
; Also, there are notes in the code suggesting other elements that
; might be necessary.
EnableExplicit
Global gHandle
Global gUSBPacketSize
Prototype p_SetupDiGetClassDevs (*ClassGuid, *Enumerator, hwndParent, flags.l)
Global _SetupDiGetClassDevs.p_SetupDiGetClassDevs
Prototype p_SetupDiEnumDeviceInterfaces (DeviceInfoSet, *DeviceInfoData, *InterfaceClassGuid, MemberIndex.l, *DeviceInterfaceData)
Global _SetupDiEnumDeviceInterfaces.p_SetupDiEnumDeviceInterfaces
Prototype p_SetupDiGetDeviceInterfaceDetail (DeviceInfoSet, *DeviceInterfaceData, *DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize.l, *RequiredSize, *DeviceInfoData)
Global _SetupDiGetDeviceInterfaceDetail.p_SetupDiGetDeviceInterfaceDetail
; from WINIOCTL.H
#FILE_DEVICE_UNKNOWN = $00000022
#FILE_ANY_ACCESS = $0
#METHOD_BUFFERED = $0
#MAX_BUFFER_SIZE = 4096
#ASYNC_DATA_SIZE = 64
Macro CTL_CODE(DeviceType, Function, Method, Access) ; from WINIOCTL.H
(((DeviceType)<<16)|((Access)<<14)|((Function)<<2)|(Method))
EndMacro
#IOCTL_ASYNC_IN = CTL_CODE (#FILE_DEVICE_UNKNOWN, $850, #METHOD_BUFFERED, #FILE_ANY_ACCESS)
#IOCTL_USB_PACKET_SIZE = CTL_CODE (#FILE_DEVICE_UNKNOWN, $851, #METHOD_BUFFERED, #FILE_ANY_ACCESS)
DataSection
GUID_DEVINTERFACE_GRMNUSB:
Data.l $2c9c45c2
Data.w $8e7d, $4c08
Data.b $a1, $2d, $81, $6b, $ba, $e7, $22, $c0
EndDataSection
Structure SP_INTERFACE_DEVICE_DETAIL_DATA ; from SETUPAPI.H
cbSize.l
DevicePath.c[#ANYSIZE_ARRAY]
EndStructure
Structure SP_DEVINFO_DATA ; from SETUPAPI.H
cbSize.l
ClassGuid.GUID
DevInst.l
*Reserved
EndStructure
Structure Packet_t
mPacketType.c
mReserved1.c
mReserved2.w
mPacketId.w
mReserved3.w
mDataSize.l
mData.c[1]
EndStructure
Procedure SendPacket (*aPacket.Packet_t)
Protected theBytesToWrite = SizeOf(Packet_t) - 1 + *aPacket\mDataSize
Protected theBytesReturned.l ; dword
WriteFile_(gHandle, *aPacket, theBytesToWrite, @theBytesReturned, 0)
; If the packet size was an exact multiple of the USB packet
; size, we must make a final write call with no Data
If (theBytesToWrite % gUSBPacketSize) = 0
WriteFile_ (gHandle, 0, 0, @theBytesReturned, 0)
EndIf
EndProcedure
;-----------------------------------------------------------------------------
; Gets a single packet. Since packets may come simultaneously through
; asynchrous reads and normal (ReadFile) reads, a full implementation
; may require a packet queue and multiple threads.
;-----------------------------------------------------------------------------
Procedure.i GetPacket()
Protected *thePacket.Packet_t
Protected theBufferSize.l ; DWORD
Protected theBytesReturned.l ; DWORD
Protected *theBuffer, *theNewBuffer
Protected *theTempBuffer = AllocateMemory(#ASYNC_DATA_SIZE)
Repeat
; Read async data until the driver returns less than the
; max async data size, which signifies the end of a packet
*theNewBuffer = 0;
theBytesReturned = 0;
DeviceIoControl_(gHandle, #IOCTL_ASYNC_IN, 0, 0, *theTempBuffer, #ASYNC_DATA_SIZE, @theBytesReturned, 0)
theBufferSize + #ASYNC_DATA_SIZE
*theNewBuffer = AllocateMemory(theBufferSize)
If *theBuffer
CopyMemory(*theBuffer, *theNewBuffer, theBufferSize - #ASYNC_DATA_SIZE)
EndIf
CopyMemory(*theTempBuffer, *theNewBuffer + theBufferSize - #ASYNC_DATA_SIZE, #ASYNC_DATA_SIZE)
If *theBuffer
FreeMemory(*theBuffer) : *theBuffer = 0
EndIf
*theBuffer = *theNewBuffer
If theBytesReturned <> #ASYNC_DATA_SIZE
*thePacket = *theBuffer
Break
EndIf
ForEver
FreeMemory(*theTempBuffer)
; If this was a small "signal" packet, read a real
; packet using ReadFile
If (*thePacket\mPacketType = 0 And *thePacket\mPacketId = 2)
*theNewBuffer = AllocateMemory(#MAX_BUFFER_SIZE)
theBytesReturned = 0
FreeMemory(*thePacket)
; A full implementation would keep reading (and queueing)
; packets until the driver returns a 0 size buffer.
ReadFile_ (gHandle, *theNewBuffer, #MAX_BUFFER_SIZE, @theBytesReturned, 0)
ProcedureReturn *theNewBuffer
Else
ProcedureReturn *thePacket
EndIf
EndProcedure
Procedure Initialize()
Protected hDll
Protected theBytesReturned.l ; DWORD
Protected *theDevDetailData.SP_INTERFACE_DEVICE_DETAIL_DATA
Protected *thePacket.Packet_t
Protected theDevInfoData.SP_DEVINFO_DATA
Protected theInterfaceData.SP_DEVICE_INTERFACE_DATA
Protected theStartSessionPacket.Packet_t
Protected theDevInfo
theDevInfoData\cbSize = SizeOf(SP_DEVINFO_DATA)
theInterfaceData\cbSize = SizeOf(SP_DEVICE_INTERFACE_DATA)
theStartSessionPacket\mPacketId = 5 ; id
hDll = OpenLibrary(#PB_Any, "Setupapi.dll")
If hDll = 0
Debug "Setupapi.dll failed."
End
EndIf
_SetupDiGetClassDevs = GetFunction(hDll, "SetupDiGetClassDevsA")
If _SetupDiGetClassDevs = 0
Debug "SetupDiGetClassDevsA failed."
End
EndIf
_SetupDiEnumDeviceInterfaces = GetFunction(hDll, "SetupDiEnumDeviceInterfaces")
If _SetupDiEnumDeviceInterfaces = 0
Debug "SetupDiEnumDeviceInterfaces failed."
End
EndIf
_SetupDiGetDeviceInterfaceDetail = GetFunction(hDll, "SetupDiGetDeviceInterfaceDetailA")
If _SetupDiGetDeviceInterfaceDetail = 0
Debug "SetupDiGetDeviceInterfaceDetail failed."
End
EndIf
theDevInfo = _SetupDiGetClassDevs (?GUID_DEVINTERFACE_GRMNUSB, 0, 0, #DIGCF_PRESENT | #DIGCF_DEVICEINTERFACE)
If _SetupDiEnumDeviceInterfaces (theDevInfo, 0, ?GUID_DEVINTERFACE_GRMNUSB, 0, @theInterfaceData) = 0
If GetLastError_() = #ERROR_NO_MORE_ITEMS
gHandle = 0
ProcedureReturn
EndIf
EndIf
_SetupDiGetDeviceInterfaceDetail(theDevInfo, @theInterfaceData, 0, 0, @theBytesReturned, 0)
*theDevDetailData = AllocateMemory(theBytesReturned);
*theDevDetailData\cbSize = SizeOf(SP_INTERFACE_DEVICE_DETAIL_DATA)
_SetupDiGetDeviceInterfaceDetail(theDevInfo, @theInterfaceData, *theDevDetailData, theBytesReturned, 0, @theDevInfoData)
gHandle = CreateFile_(@*theDevDetailData\DevicePath, #GENERIC_READ | #GENERIC_WRITE, 0, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0)
FreeMemory(*theDevDetailData)
; Get the USB packet size, which we need for sending packets
DeviceIoControl_(gHandle, #IOCTL_USB_PACKET_SIZE, 0, 0, @gUSBPacketSize, SizeOf(gUSBPacketSize), @theBytesReturned, 0)
; Tell the device that we are starting a session.
SendPacket(@theStartSessionPacket)
; Wait until the device is ready to the start the session
Repeat
*thePacket = GetPacket()
If (*thePacket\mPacketType = 0 And *thePacket\mPacketId = 6)
Break
EndIf
FreeMemory(*thePacket) : *thePacket = 0
ForEver
If *thePacket
FreeMemory(*thePacket)
EndIf
CloseLibrary(hDll)
EndProcedure
Procedure Main()
Protected *thePacket.Packet_t
Protected theProductDataPacket.Packet_t
theProductDataPacket\mPacketType = 20
theProductDataPacket\mPacketId = 254
OpenConsole()
Initialize()
If gHandle = 0
PrintN("No device")
EndIf
; Tell the device to send product data
SendPacket (@theProductDataPacket)
; Get the product data packet
Repeat
*thePacket = GetPacket();
If (*thePacket\mPacketType = 20 And *thePacket\mPacketId = 255)
Break
EndIf
FreeMemory(*thePacket)
ForEver
; Print out the product description
PrintN(PeekS(@*thePacket\mData + 4))
FreeMemory(*thePacket)
CloseConsole()
EndProcedure
Main()