Last active
August 15, 2017 11:01
-
-
Save ChiiAyano/63c9288a21641ef265d8016b27c916a4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Windows.Devices.Enumeration; | |
using Windows.Devices.Geolocation; | |
using Windows.Devices.SerialCommunication; | |
namespace Mikaboshi.Iot.LocationPost | |
{ | |
public class GpsClient | |
{ | |
DeviceInformation device; | |
SerialDevice serialPort; | |
Stream readStream; | |
public BasicGeoposition Position { get; private set; } | |
public DateTimeOffset PositionSourceTime { get; private set; } | |
public double Heading { get; private set; } | |
public bool Succeeded { get; private set; } | |
public int Count { get; private set; } | |
public event EventHandler LoggingStarted; | |
public event EventHandler<GpsPositionEventArgs> PositionChanged; | |
public async Task InitializeAsync() | |
{ | |
// シリアルポートの初期化 | |
var selector = SerialDevice.GetDeviceSelector(); | |
var devices = await DeviceInformation.FindAllAsync(selector); | |
this.device = devices.FirstOrDefault(); | |
} | |
public async Task OpenPort() | |
{ | |
if (this.device == null) return; | |
this.serialPort = await SerialDevice.FromIdAsync(this.device.Id); | |
this.serialPort.BaudRate = 9600; | |
this.readStream = this.serialPort.InputStream.AsStreamForRead(0); | |
} | |
public async void Listen() | |
{ | |
try | |
{ | |
if (this.serialPort == null) return; | |
while (true) | |
{ | |
await ReadAsync(); | |
} | |
} | |
catch (Exception ex) | |
{ | |
} | |
finally | |
{ | |
if (this.readStream != null) | |
{ | |
this.readStream.Dispose(); | |
this.readStream = null; | |
} | |
} | |
} | |
private async Task ReadAsync() | |
{ | |
var buf = new StringBuilder(); | |
var readStart = false; | |
var carriageReturn = false; | |
while (true) | |
{ | |
var c = (char)this.readStream.ReadByte(); | |
if (c < 0) break; | |
if (c == '$') | |
{ | |
if (readStart) | |
{ | |
// リード中に $ がきたら異常と見なしてリセットする | |
buf.Clear(); | |
readStart = false; | |
continue; | |
} | |
readStart = true; | |
} | |
if (!readStart) | |
{ | |
continue; | |
} | |
buf.Append(c); | |
if (c == '\r') | |
{ | |
carriageReturn = true; | |
} | |
else if (c == '\n' && carriageReturn) | |
{ | |
break; | |
} | |
else | |
{ | |
carriageReturn = false; | |
} | |
} | |
var str = buf.ToString(); | |
Debug.WriteLine(str); | |
await ParseAsync(str); | |
} | |
private async Task ParseAsync(string message) | |
{ | |
using (var sr = new StringReader(message)) | |
{ | |
while (sr.Peek() > -1) | |
{ | |
var d = await sr.ReadLineAsync(); | |
var s = d.Split(','); | |
if (s.Length < 0) return; | |
switch (s[0]) | |
{ | |
case "$GPRMC": | |
Gprmc(s); | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// 緯度・経度・進行方位・速度のデータ | |
/// </summary> | |
/// <param name="data"></param> | |
private void Gprmc(string[] data) | |
{ | |
if (data.Length < 12) return; | |
// R は Raw | |
// UTC 時刻。 hhmmss.fff | |
var timeR = data[1]; | |
// ステータス。 V = 警告 / A = 有効 | |
var statusR = data[2]; | |
// 緯度。 dddmm.mmmm | |
var latitudeR = data[3]; | |
// N = 北緯 / S = 南緯 | |
var latitudePollR = data[4]; | |
// 経度。 dddmm.mmmm | |
var longitudeR = data[5]; | |
// E = 東経 / W = 西経 | |
var longitudePollR = data[6]; | |
// 移動速度。 knot | |
var speedR = data[7]; | |
// 移動方位。 | |
var directionR = data[8]; | |
// UTC 日付。 ddmmyy | |
var dateR = data[9]; | |
// 磁北と真北の差。 | |
var mDirectR = data[10]; | |
// 磁北と真北の差の方向。 E = 東 | |
var mDirectPollR = data[11]; | |
// モード。 | |
var modeR = data[12]; | |
// 時間 | |
var date = ParseDateTime(dateR, timeR).ToLocalTime(); | |
if (statusR != "A") | |
{ | |
this.Succeeded = false; | |
return; | |
} | |
// 緯度 | |
var latitude1 = double.Parse(latitudeR) / 100; | |
var latitude2 = (int)Math.Floor(latitude1); | |
var latitude3 = (latitude1 % 1.0) * 100; | |
var latitude = latitude2 + latitude3 / 60; | |
if (latitudePollR == "S") latitude *= -1; | |
// 経度 | |
var longitude1 = double.Parse(longitudeR) / 100; | |
var longitude2 = (int)Math.Floor(longitude1); | |
var longitude3 = (longitude1 % 1.0) * 100; | |
var longitude = longitude2 + longitude3 / 60; | |
if (longitudePollR == "W") longitude *= -1; | |
// 移動速度 | |
const double knotToKph = 1.852; | |
var kph = double.Parse(speedR) * knotToKph; | |
this.Succeeded = true; | |
this.Position = new BasicGeoposition { Latitude = latitude, Longitude = longitude }; | |
this.PositionSourceTime = date; | |
this.Count++; | |
if (this.Count == 1) | |
{ | |
this.LoggingStarted?.Invoke(this, EventArgs.Empty); | |
} | |
var heading = 0d; | |
double.TryParse(directionR, out heading); | |
this.Heading = heading; | |
this.PositionChanged?.Invoke(this, new GpsPositionEventArgs(this.Position, this.PositionSourceTime, this.Heading, this.Succeeded, this.Count)); | |
} | |
/// <summary> | |
/// 日付と時刻を <see cref="DateTimeOffset"/> として変換します。時刻は <see cref="DateTimeOffset.UtcNow"/> で示されるタイムゾーンで返します。 | |
/// </summary> | |
/// <param name="date"></param> | |
/// <param name="time"></param> | |
/// <returns></returns> | |
private static DateTimeOffset ParseDateTime(string date, string time) | |
{ | |
var year = int.Parse("20" + date.Substring(4, 2)); | |
var month = int.Parse(date.Substring(2, 2)); | |
var day = int.Parse(date.Substring(0, 2)); | |
var hour = int.Parse(time.Substring(0, 2)); | |
var minute = int.Parse(time.Substring(2, 2)); | |
var second = int.Parse(time.Substring(4, 2)); | |
var mSecond = double.Parse("0" + time.Substring(6)); | |
var result = new DateTimeOffset(year, month, day, hour, minute, second, (int)(mSecond * 1000), DateTimeOffset.UtcNow.Offset); | |
result = result.ToLocalTime(); | |
return result; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Windows.Devices.Geolocation; | |
namespace Mikaboshi.Iot.LocationPost | |
{ | |
public class GpsPositionEventArgs : EventArgs | |
{ | |
public BasicGeoposition Position { get; } | |
public DateTimeOffset PositionSourceTime { get; } | |
public double Heading { get; } | |
public bool Succeeded { get; } | |
public int Count { get; } | |
public GpsPositionEventArgs(BasicGeoposition position, DateTimeOffset sourceTime, double heading, bool succeeded, int count) | |
{ | |
this.Position = position; | |
this.PositionSourceTime = sourceTime; | |
this.Heading = heading; | |
this.Succeeded = succeeded; | |
this.Count = count; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment