Windows Mobile下GPS管理软件NavsGo之GPS侦测功能的开发
2009-08-21 09:26
363 查看
简述
在上篇文章 Windows Mobile下GPS管理软件NavsGo之GPS监控功能的开发 概述了NavsGo项目以及讲述了GPS监控功能的开发,GPS.net控件的使用,这篇文章讲述侦测功能的开发。关于
所谓GPS侦测功能就是扫描手机上所有可用的GPS设备(available GPS devices),把各个设备运行状态展现给用户,如果发现问题,通过友善的方式提示用户如果解决设备连通性问题。这些建议包括启动GPS设备,修改GPS Intermediate Driver的配置,启动蓝牙GPS设备等等。实现
这个模块是GPS.net 作者jperson的一个demo程序,原程序可以到 GPS Diagnostics for .NET 下载。我做了少量修改加到NavsGo里面来了。发现/检测功能(Detection)
发现功能在上篇文章讲过,通过注册静态事件,然后回调相应的处理函数。
/* Hook into GPS device detection events. These events are static, allowing them to * be easily sunk by any other class or form. */ Devices.DeviceDetectionStarted += new EventHandler(Devices_DeviceDetectionStarted); Devices.DeviceDetectionCompleted += new EventHandler(Devices_DeviceDetectionCompleted); Devices.DeviceDetected += new EventHandler<DeviceEventArgs>(Devices_DeviceDetected); Devices.DeviceDetectionAttempted += new EventHandler<DeviceEventArgs>(Devices_DeviceDetectionAttempted); Devices.DeviceDetectionAttemptFailed += new EventHandler<DeviceDetectionExceptionEventArgs>(Devices_DeviceDetectionAttemptFailed);
由于GPS.net是开源的,我们这次钻到他的源代码看看Detection的实现逻辑。
启动发现功能是在 Devices.BeginDetection() 函数里面。
public static void BeginDetection() { // Start detection on another thread. if (_IsDetectionInProgress) return; // Signal that detection is in progress _IsDetectionInProgress = true; // Start a thread for managing detection _DetectionThread = new Thread(new ThreadStart(DetectionThreadProc)); _DetectionThread.Name = "GPS.NET Device Detector (http://www.geoframeworks.com)"; _DetectionThread.IsBackground = true; #if !PocketPC // Do detection in the background _DetectionThread.Priority = ThreadPriority.Lowest; #endif _DetectionThread.Start(); #if PocketPC // Signal that the thread is alive (no Thread.IsAlive on the CF :P) _IsDetectionThreadAlive = true; #endif }
启动发现过程,系统会启动一个线程调用DetectionThreadProc()进行发现。下面是DetectionThreadProc()函数。
private static void DetectionThreadProc() { try { // Signal that it started OnDeviceDetectionStarted(); // Monitor this thread up to the timeout, then quit ThreadPool.QueueUserWorkItem(new WaitCallback(DetectionThreadProcWatcher)); #if PocketPC // Are we using the GPS Intermediate Driver? GpsIntermediateDriver gpsid = GpsIntermediateDriver.Current; // Is the GPSID supported? if (gpsid != null) { // Yes. Test it to be sure gpsid.BeginDetection(); // Wait for one device to get detected. Was it confirmed? if (gpsid.WaitForDetection()) { // Yes. If we only need one device, exit if(_IsOnlyFirstDeviceDetected) return; } } #endif /* If we get here, the GPS Intermediate Driver is not responding! */ int count; #region Detect Bluetooth devices // Is Bluetooth supported and turned on? if (IsBluetoothSupported && IsBluetoothEnabled) { // Start bluetooth detection for each device count = _BluetoothDevices.Count; for (int index = 0; index < count; index++) _BluetoothDevices[index].BeginDetection(); } #endregion #region Detect serial GPS devices if (AllowSerialConnections) { count = SerialDevices.Count; for (int index = 0; index < count; index++) _SerialDevices[index].BeginDetection(); /* If we're performing "exhaustive" detection, ports are scanned * even if there's no evidence they actually exist. This can happen in rare * cases, such as when a PCMCIA GPS device is plugged in and fails to create * a registry entry. */ if (_AllowExhaustiveSerialPortScanning) { // Try all ports from COM0: up to the maximum port number for (int index = 0; index < _MaximumSerialPortNumber; index++) { // Is this port already being checked? bool alreadyBeingScanned = false; for (int existingIndex = 0; existingIndex < _SerialDevices.Count; existingIndex++) { if (_SerialDevices[existingIndex].PortNumber.Equals(index)) { // Yes. Don't test it again alreadyBeingScanned = true; break; } // If it's already being scanned, stop if (alreadyBeingScanned) break; } // If it's already being scanned, skip to the next port if (alreadyBeingScanned) continue; // This is a new device. Scan it SerialDevice exhaustivePort = new SerialDevice("COM" + index.ToString() + ":"); exhaustivePort.BeginDetection(); } } } #endregion #region Discover new Bluetooth devices // Is Bluetooth supported and turned on? if (IsBluetoothSupported && IsBluetoothEnabled) { /* NOTE: For mobile devices, only one connection is allowed at a time. * As a result, we use a static SyncRoot to ensure that connections * and discovery happens in serial. For this reason, we will not attempt * to discover devices until *after* trying to detect existing ones. */ #if PocketPC // Wait for existing devices to be tested count = _BluetoothDevices.Count; for (int index = 0; index < count; index++) { // Complete detection for this device _BluetoothDevices[index].WaitForDetection(); } #endif // Begin searching for brand new devices BluetoothDevice.DiscoverDevices(true); // Block until that search completes BluetoothDevice.DeviceDiscoveryThread.Join(); } #endregion #region Wait for all devices to finish detection /* A list holds the wait handles of devices being detected. When it is empty, * detection has finished on all threads. */ while (_CurrentlyDetectingWaitHandles.Count != 0) { try { ManualResetEvent handle = _CurrentlyDetectingWaitHandles[0]; #if !PocketPC if (!handle.SafeWaitHandle.IsClosed) #endif handle.WaitOne(); } catch (ObjectDisposedException) { /* In some rare cases a device will get disposed of and nulled out. * So, regardless of what happens we can remove the item. */ } finally { _CurrentlyDetectingWaitHandles.RemoveAt(0); } } #endregion #if PocketPC #region Reconfigure the GPS Intermediate Driver (if necessary) /* The GPS Intermediate Driver may not have the right "Program Port" (actual GPS port/baud rate) * settings. Now that detection has completed, let's see if the GPSID needs configuration. * If it is flagged as NOT being a GPS device, then it could not connect. In this case, let's * find the most reliable serial device and use it. */ if ( // Is the GPSID supported? gpsid != null // Are we allowed to configure it? && gpsid.IsAutomaticallyConfigured // Is it currently NOT identified as a GPS device? (connections failed) && !gpsid.IsGpsDevice) { // Look through each confirmed GPS device count = _GpsDevices.Count; for (int index = 0; index < count; index++) { // Is it a serial device? SerialDevice device = _GpsDevices[index] as SerialDevice; if (device == null) continue; // Yes. Use it! try { gpsid.HardwarePort = device; // The GPSID is now working Add(gpsid); } catch (Exception ex) { // Notify of the error gracefully OnDeviceDetectionAttemptFailed(new DeviceDetectionException(gpsid, ex)); } // That's the best device, so quit break; } } #endregion #endif // Signal completion OnDeviceDetectionCompleted(); } catch (ThreadAbortException) { #region Abort detection for all devices #if PocketPC // Stop detection for the GPSID if(GpsIntermediateDriver.Current != null) GpsIntermediateDriver.Current.CancelDetection(); #endif // Stop detection for each Bluetooth device for (int index = 0; index < _BluetoothDevices.Count; index++) _BluetoothDevices[index].CancelDetection(); // Stop detection for each serial device for (int index = 0; index < _SerialDevices.Count; index++) _SerialDevices[index].CancelDetection(); #endregion // Wait for all the threads to die. Just... sit and watch. And wait. while (_CurrentlyDetectingWaitHandles.Count != 0) { try { _CurrentlyDetectingWaitHandles[0].WaitOne(); } catch { } finally { _CurrentlyDetectingWaitHandles.RemoveAt(0); } } // Signal the cancellation if (DeviceDetectionCanceled != null) DeviceDetectionCanceled(null, EventArgs.Empty); } finally { // Detection is no longer in progress _DetectionCompleteWaitHandle.Set(); _CurrentlyDetectingWaitHandles.Clear(); // <-- Already empty? _IsDetectionInProgress = false; #if PocketPC // Signal that the thread is alive (no Thread.IsAlive on the CF :P) _IsDetectionThreadAlive = false; #endif } }
DetectionThreadProc()负责整个发现过程,是一个很长的函数,有必要重构一下,把它分离(split)成几个小函数。他的处理逻辑是,检测超时,一旦发现发现过程超时,就好中途停止所有的处理。然后按顺序检测设备。检测的设备包括GPS Intermediate Driver设备(GpsIntermediateDriver),串口设备(SerialDevice)和蓝牙设备(BluetoothDevice)。支持的设备类图如下:
所有设备都是继承于父类Device,这样可以通过容器类Devices类统一管理所有设备的对象,通过多态的方式去调用各个具体设备的处理函数来实现发现过程。对于每个独立的设备,他们统一发现流程是启动一个线程,然后试图打开该设备,如果超时,认为设备不可用,如果在超时之前读取到数据就分析输出数据,如果数据是标准的NMEA就认为这个是GPS设备。NMEA相关的可以参考.NET Compact Framework下的GPS NMEA data数据分析。
GPS Intermediate Driver设备的发现
发现过程首先检查的是GPS Intermediate Driver设备。在Windows Mobile 5+和Wince 6+的系统下一般都内嵌GPS Intermediate Driver,关于GPS Intermediate Driver的开发可以参考30 Days of .NET [Windows Mobile Applications] - Day 03: GPS Compass(GPS指南针) 。我计划增加 GPS Intermediate Driver管理功能到NavsGo里面,后续会把GPS Intermediate Driver管理的开发写下来。已经配对了的蓝牙设备的发现
检测完GPS Intermediate Driver设备,就开始检查已经配对了的蓝牙设备(Paired Bluetooth Devices),这些已经配对了的蓝牙设备保存在注册表HKEY_LOCAL_MACHINE\SOFTWARE\GeoFrameworks\GPS.NET\3.0\Devices\Bluetooth\中。关于蓝牙配对也可以参考一下 .NET Compact Framework下的Bluetooth设备的配对。软件意义上的串口设备的发现
检测完已经配对了的蓝牙设备后,就开始检查串口设备,这里的串口设备是指软件意义上的串口,不是仅仅只通过硬件串口线连接的设备。由于 NMEA 0183 的规范规定GPS设备的联通性通过波特率(Baud rate)为4800的串口设备。所以GPS设备厂商尽管使用其他联通方式,但是都可以转成软件上的串口设备。例如USB GPS设备可以通过驱动转成串口设备,蓝牙可以建立虚拟串口,关于虚拟串口可以参考 .NET Compact Framework下的Bluetooth开发 之 Bluetooth Virtual Serial Port。总的来说,这里软件意义上的串口,真实的设备可能是 真正的串口线,USB,PCMCIA,蓝牙,红外等。新蓝牙设备的发现
做完GPS Intermediate Driver设备,已经配对了的蓝牙设备和软件意义上的串口的发现流程后,进入了对新蓝牙设备的发现过程,这些蓝牙设备是不在已经配对了的蓝牙设备的范畴里面的,是手机周边新的蓝牙设备。由于手机对蓝牙的通信只能是一对一,也就是一个时间内一台手机只能和一个蓝牙设备进行通信,所以在发现新蓝牙设备之前,需要先等待已经配对了的蓝牙设备的发现过程的结束。关于蓝牙设备的开发和发现可以参考一下 .NET Compact Framework下的Bluetooth开发 之 Windows Embedded Source Tools for Bluetooth 和 .NET Compact Framework下的Bluetooth开发 之 32feet.NET。GPS Intermediate Driver设备配置
一般来说移动设备都是通过GPS Intermediate Driver设备来对外部GPS程序提供服务的,有时候尽管GPS Intermediate Driver设备存在,并在运行,但是由于配置不正确也会导致外部GPS程序未能正确连接和使用GPS设备。所以最后一步是检查GPS Intermediate Driver设备的配置情况。我计划也在NavsGo增加GPS Intermediate Driver设备的配置管理功能。最后的最后是清理所有资源,一个好的程序的习惯。
建议功能
发现功能实现了整个GPS诊断模块的核心,建议功能也就是呈现发现功能缓存的信息。建议功能实现在SummaryForm和DeviceForm两个类里面,SummaryForm提示建议,而DeviceForm现实某个设备的检查情况。
建议功能的流程是,判断GPS Intermediate Driver设备是否可用,如果不可用可能是硬件端口配置错误,建议把可用的串口端口配置为GPS Intermediate Driver的硬件端口,如果没有可用的串口端口,建议使用蓝牙设备。
日志功能
GPS.net提供日志发送功能,把设备发现和检查信息发送到服务器,方便开发者改进。这个功能很简单。
源码请看 Windows Mobile下GPS管理软件NavsGo之GPS监控功能的开发
相关文章推荐
- Windows Mobile下GPS管理软件NavsGo之GPS监控功能的开发
- Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向
- 配送平台软件开发|配送管理系统开发功能设计
- 一个项目经理对主流项目管理工具的对比:禅道VS华为软件开发云
- 一个项目经理对主流项目管理工具的对比:禅道VS华为软件开发云
- 广州手机App开发公司:服装管理App软件功能解析
- 【VS开发】visual studio 2015的NuGet Manager解决方案管理功能
- Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向
- C#软件开发实例.私人订制自己的屏幕截图工具(六)添加配置管理功能
- C#软件开发实例.私人订制自己的屏幕截图工具(六)添加配置管理功能
- 一个项目经理对主流项目管理工具的对比:禅道VS华为软件开发云
- C#软件开发实例.私人订制自己的屏幕截图工具(八)添加键盘操作截图的功能
- 软件开发行业中需求与设计的管理 – DevSpec
- Qml和C++开发的学生信息管理软件二
- 软件测试 VS 软件开发
- [转]《保力》-医院设备及耗材管理软件功能说明
- 仿OpenStack开发云计算管理软件
- 软件开发中项目管理五项基本原则
- Minitab软件是现代质量管理统计的领先者,全球六西格玛实施的共同语言,以无可比拟的强大功能和简易的可视化操作深受广大质量学者和统计专家的青睐。
- 小软件项目开发的管理