using System; using Microsoft.SPOT; using System.Text; //using SWModules; namespace GPSParser { public class Program { private const byte dPoint = (byte)'.'; private const byte comma = (byte)','; private const byte nullByte = (byte)'\0'; private const byte north = (byte)'N'; private const byte south = (byte)'S'; private const byte east = (byte)'E'; private const byte west = (byte)'W'; public const char tabChar = '\t'; public const char spaceChar = ' '; public const string spaceString = " "; public static readonly byte[] spaceBytes = { 0x20 }; public const char commaChar = ','; public const string crlfString = "\r\n"; public static readonly byte[] crlfBytes = { 0xD, 0xA }; public static readonly byte[] lfBytes = { 0xA }; public static readonly byte[] dollarSignBytes = { 0x24 }; public const string nanString = "NaN"; public struct GPSPosition { public StringBuilder latSB; public StringBuilder lonSB; public int numSats; public StringBuilder gpsTimeOfFix; public DateTime cpfDateOfFix; public TimeSpan gpsTTFF; public StringBuilder rawMessage; } public GPSPosition latestPosition; public static void Main() { GPSPosition gpsPosition = new GPSPosition(); gpsPosition.latSB = new StringBuilder(); gpsPosition.lonSB = new StringBuilder(); gpsPosition.numSats = -1; gpsPosition.gpsTimeOfFix = new StringBuilder(); gpsPosition.cpfDateOfFix = new DateTime(); gpsPosition.gpsTTFF = new TimeSpan(0, 0, 0); gpsPosition.rawMessage = new StringBuilder(); StringBuilder pubxMsg = new StringBuilder("UBX,00,150208.00,3646.21831,N,12152.28182,W,0.000,D3,2.6,4.6,2.582,208.67,-0.041,,0.78,1.18,0.74,12,0,0*6A"); parsePUBX00(UTF8Encoding.UTF8.GetBytes(pubxMsg.ToString()), ref gpsPosition); updateLatLon(gpsPosition); Debug.Print(gpsPositionSB.ToString()); } static StringBuilder gpsPositionSB = new StringBuilder(); static void updateLatLon(GPSPosition position) { double lat = double.NaN; double lon = double.NaN; gpsPositionSB.Clear(); gpsPositionSB.Append("# GPS fix obtained in (seconds) \t"); gpsPositionSB.Append(position.gpsTTFF.ToString()); gpsPositionSB.Append(crlfString); gpsPositionSB.Append("#Fix: \tLon\tLat\tmm/dd/yyyy\tHH:mm:sss\tnumSats\tnmeaLon\t\tnmeaLat\t\tgpsTimeOfFix"); gpsPositionSB.Append(crlfString); gpsPositionSB.Append("Fix:"); gpsPositionSB.Append(tabChar); lon = convertLonToDecDeg(position.lonSB.ToString()); gpsPositionSB.Append(lon.ToString("f8")); gpsPositionSB.Append(tabChar); lat = convertLatToDecDeg(position.latSB.ToString()); gpsPositionSB.Append(lat.ToString("f8")); gpsPositionSB.Append(tabChar); gpsPositionSB.Append(position.cpfDateOfFix.ToString("MM/dd/yyyy\tHH:mm:ss")); gpsPositionSB.Append(tabChar); gpsPositionSB.Append(position.numSats.ToString()); gpsPositionSB.Append(tabChar); gpsPositionSB.Append(position.lonSB); gpsPositionSB.Append(tabChar); gpsPositionSB.Append(position.latSB); gpsPositionSB.Append(tabChar); gpsPositionSB.Append(position.gpsTimeOfFix); } static public void parsePUBX00(byte[] inBytes, ref GPSPosition position) { byte[] latBytes = new byte[16]; byte[] lonBytes = new byte[16]; byte[] numSatsBytes = new byte[16]; byte[] fieldBytes = new byte[16]; byte[] decMinBytes = new byte[16]; byte[] degMinBytes = new byte[16]; StringBuilder sbTemp = new StringBuilder(128); StringBuilder positionSB = new StringBuilder(64); try { Array.Clear(fieldBytes, 0, fieldBytes.Length); getField(inBytes, comma, 2, ref fieldBytes); position.gpsTimeOfFix.Clear(); position.gpsTimeOfFix.Append(GetChars(fieldBytes)); position.cpfDateOfFix = DateTime.Now; Array.Clear(fieldBytes, 0, fieldBytes.Length); getField(inBytes, comma, 3, ref fieldBytes); position.latSB.Clear(); position.latSB.Append(GetChars(fieldBytes)); position.latSB.Append(tabChar); Array.Clear(fieldBytes, 0, fieldBytes.Length); getField(inBytes, comma, 4, ref fieldBytes); position.latSB.Append(GetChars(fieldBytes)); Array.Clear(fieldBytes, 0, fieldBytes.Length); getField(inBytes, comma, 5, ref fieldBytes); position.lonSB.Clear(); position.lonSB.Append(GetChars(fieldBytes)); position.lonSB.Append(tabChar); Array.Clear(fieldBytes, 0, fieldBytes.Length); getField(inBytes, comma, 6, ref fieldBytes); position.lonSB.Append(GetChars(fieldBytes)); Array.Clear(fieldBytes, 0, fieldBytes.Length); getField(inBytes, comma, 18, ref fieldBytes); position.numSats = bytesToInt32(fieldBytes); position.rawMessage.Clear(); position.rawMessage.Append(GetChars(inBytes)); } catch { // EngrLogger.writeToColumns("[ERROR] parsing GPS PUBX00 message"); position.latSB.Clear(); position.latSB.Append(nanString); position.lonSB.Clear(); position.lonSB.Append(nanString); position.numSats = -1; position.rawMessage.Clear(); //position.rawMessage.Append(GetChars(inBytes, 0, latestPosition.rawMessage.Capacity)); } } private static double convertLatToDecDeg(string sLat) { int decPtIndex = 0; double lat = double.NaN; double deg; double min; //TODO P1 need to make sure pubx always has 2 digits of minutes try { decPtIndex = sLat.IndexOf('.'); min = double.Parse(sLat.Substring(decPtIndex - 2, sLat.Length - decPtIndex)); deg = double.Parse(sLat.Substring(0, decPtIndex - 2)); lat = deg + min / 60.0; if (sLat.Substring(sLat.Length - 1, 1) == "S") lat = -1 * lat; } catch { lat = double.NaN; } return lat; } private static double convertLonToDecDeg(string sLon) { int decPtIndex = 0; double lon = double.NaN; double deg; double min; //TODO P1 need to make sure pubx always has 2 digits of minutes try { decPtIndex = sLon.IndexOf('.'); min = double.Parse(sLon.Substring(decPtIndex - 2, sLon.Length - decPtIndex)); deg = double.Parse(sLon.Substring(0, decPtIndex - 2)); lon = deg + min / 60.0; if (sLon.Substring(sLon.Length - 1, 1) == "W") lon = -1 * lon; } catch { lon = double.NaN; } return lon; } public static int getField(byte[] inBytes, byte token, int desiredField, ref byte[] returnField) { int currentField = 0; int returnFieldIndex = 0; bool inDesiredField; //TODO P2 I don't think we need this block and it doesn't look like returnFieldIndex means anything if (desiredField == 0) inDesiredField = true; else inDesiredField = false; Array.Clear(returnField, 0, returnField.Length); for (int i = 0; i < inBytes.Length; i++) { if ((inBytes[i] == token) && !inDesiredField) currentField++; else if (currentField == desiredField) { inDesiredField = true; if ((inBytes[i] == token) || (inBytes[i] == 10) || (inBytes[i] == 13)) return (returnFieldIndex); returnField[returnFieldIndex++] = inBytes[i]; if (returnFieldIndex >= returnField.Length) return returnFieldIndex; } } return (0); } public static int getField(StringBuilder inSB, char token, int desiredField, ref StringBuilder returnField) { int currentField = 0; int returnFieldIndex = 0; bool inDesiredField; //TODO P2 I don't think we need this block and it doesn't look like returnFieldIndex means anything if (desiredField == 0) inDesiredField = true; else inDesiredField = false; returnField.Clear(); for (int i = 0; i < inSB.Length; i++) { if ((inSB[i] == token) && !inDesiredField) currentField++; else if (currentField == desiredField) { inDesiredField = true; if ((inSB[i] == token) || (inSB[i] == 10) || (inSB[i] == 13)) return (returnFieldIndex); returnField.Append(inSB[i]); if (returnFieldIndex >= returnField.Length) return returnFieldIndex; } } return (0); } private const byte Nonprintreplacement = 13; public static char[] GetChars(byte[] bytes) { for (var i = 0; i < bytes.Length; i++) if (bytes[i] > 127) bytes[i] = Nonprintreplacement; try { return UTF8Encoding.UTF8.GetChars(bytes); } catch { return null; } } static int bytesToInt32(byte[] inBytes) { int returnValue = 0; double power = 1; int numBytes = 1; bool didOneCalc = false; if (Array.IndexOf(inBytes, 0) > 3) numBytes = 4; else numBytes = Array.IndexOf(inBytes, 0); for (int i = numBytes - 1; i > -1; i--) { if ((inBytes[i] >= 48) && (inBytes[i] <= 57)) { returnValue = returnValue + (int)((inBytes[i] - 48) * power); power = power * 10; didOneCalc = true; } } if (didOneCalc) return (returnValue); else return (-1); } } }