/// <summary> /// Parse a depth sentence with this structure: /// DPT,d.d,o.o /// d.d: depth, meters /// o.o: offset from transducer /// </summary> /// <param name="talkerId"></param> /// <param name="sentence"></param> private void ParseDepth(string talkerId, string[] words, string sentence) { if (words.Length < 2) { DebugLog.WriteLine("Invalid DPT sentence: " + sentence); return; } double depth; try { depth = Double.Parse(words[1]); } catch (Exception e) { DebugLog.WriteLine("Could not parse double: " + sentence + " e:" + e.ToString()); return; } DebugLog.WriteLine("depth update: depth=" + depth); if (DepthEvent != null) { var args = new NmeaDepthEventArgs(depth, 0); DepthEvent(this, args); } }
/// <summary> /// Parse a magnetic heading sentence with this structure: /// HDM,x.x,M /// x.x: Heading Degrees, magnetic /// M: magnetic /// </summary> /// <param name="talkerId"></param> /// <param name="sentence"></param> private void ParseHeadingMagnetic(string talkerId, string[] words, string sentence) { if (words.Length != 3) { DebugLog.WriteLine("Invalid HDM sentence: " + sentence); return; } double heading; try { heading = Double.Parse(words[1]); if (heading < 0 || heading > 360) { DebugLog.WriteLine("Invalid heading: " + sentence); return; } } catch (Exception e) { DebugLog.WriteLine("Could not parse double: " + sentence + " e:" + e.ToString()); return; } DebugLog.WriteLine("magnetic heading update: " + heading); if (HeadingEvent != null) { var args = new NmeaHeadingEventArgs(heading); HeadingEvent(this, args); } }
/// <summary> /// Write a NMEA sentence to the serial port. This function prefixes the supplied sentence with a /// talker ID and postfixes it with a checksum. /// </summary> /// <exception cref="IOException">IOException is thrown when the write fails</exception> /// <param name="sentence">The sentence to write</param> private void WriteSentence(string sentence) { // prefix the talkerId string fulldata = talkerId + sentence; // the checksum byte checksum = 0; // compute checksum for (int i = 0; i < fulldata.Length; i++) { var c = (byte)fulldata[i]; checksum ^= c; } // append checksum string outputdata = "$" + fulldata + "*" + checksum.ToString("x2"); byte[] outputbytes = Encoding.UTF8.GetBytes(outputdata + "\r\n"); lock (this) { DebugLog.WriteLine("sending:" + outputdata); this.m_serialPort.Write(outputbytes, 0, outputbytes.Length); } }
public void Go() { // turn of Netduino devices that we don't need PowerManagement.SetPeripheralState(Peripheral.Ethernet, false); PowerManagement.SetPeripheralState(Peripheral.PowerLED, false); PowerManagement.SetPeripheralState(Peripheral.SDCard, false); // initalize the serial ports m_serialPort = new SerialPort("COM1", 38400, Parity.None, 8, StopBits.One); m_serialPort.Open(); m_nmeaInputPort = new NmeaInputPort(m_serialPort); m_oled = new Newhaven25664OledDriver( chipSelect: Pins.GPIO_PIN_D10, reset: Pins.GPIO_PIN_D9, dc: Pins.GPIO_PIN_D8); m_oled.Initialize(); m_oled.ClearDisplay(); m_oled.TestPattern(); Thread.Sleep(1000); m_oled.ClearDisplay(); InputPort leftButton = new InputPort(Pins.GPIO_PIN_D7, false, Port.ResistorMode.PullUp); if (!leftButton.Read()) { // debug mode //m_nmeaInputPort.RawDataDebugEvent += new NmeaInputDebugEventHandler(m_nmeaInputPort_RawDataDebugEvent); m_nmeaInputPort.ParsedDataDebugEvent += new NmeaInputParsedDebugEventHandler(m_nmeaInputPort_ParsedDataDebugEvent); m_debugFont = new OledFont(SailboatComputer.Properties.Resources.BinaryResources.fixed5x7); m_nmeaInputPort.Initialize(); while (true) { Thread.Sleep(Int16.MaxValue); } } else { leftButton.Dispose(); leftButton = null; DebugLog.WriteLine("free memory (before fonts) = " + Microsoft.SPOT.Debug.GC(true)); m_ui = new SimpleUserInterface(m_oled, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D6); DebugLog.WriteLine("free memory (after fonts) = " + Microsoft.SPOT.Debug.GC(true)); // hook up NMEA events m_nmeaInputPort.WindEvent += new NmeaWindEventHandler(m_nmeaInputPort_WindEvent); m_nmeaInputPort.COGSOGEvent += new NmeaCOGSOGEventHandler(m_nmeaInputPort_CogSogEvent); m_nmeaInputPort.DepthEvent += new NmeaDepthEventHandler(m_nmeaInputPort_DepthEvent); m_nmeaInputPort.Initialize(); while (true) { Thread.Sleep(Int16.MaxValue); } } }
/// Output a Wind Heading and velocity sentence with this format: /// MWV,x.x,R,v.v,M,A /// x.x = relative heading of the wind /// R = relative /// v.v = the wind velocity in MPH /// M/N/K = mph, knots, kph private void ParseWindSpeedAndVelocity(string talkerId, string[] words, string sentence) { if (words.Length != 6) { DebugLog.WriteLine("invalid MWV sentence: " + sentence); return; } int relativeHeading; double velocity; try { int period = words[1].IndexOf('.'); if (period > 0) { relativeHeading = Int32.Parse(words[1].Substring(0, period)); } else { relativeHeading = Int32.Parse(words[1]); } velocity = Double.Parse(words[3]); } catch (Exception e) { DebugLog.WriteLine("Could not parse: " + sentence + " e:" + e.ToString()); return; } // convert velocity to knots switch (words[4]) { case "M": velocity *= 0.868976242; break; case "K": velocity *= 0.539956803; break; case "N": // velocity is already in knots break; default: DebugLog.WriteLine("Invalid wind speed: " + sentence); return; } DebugLog.WriteLine("Wind velocity update: h=" + relativeHeading + " v=" + velocity); if (WindEvent != null) { var args = new NmeaWindEventArgs(relativeHeading, velocity); WindEvent(this, args); } }
/// <summary> /// Parse VTG verb with this structure: /// VTG,t.t,T,m.m,M,s.s,N,k.k,K,m /// t.t: true heading /// m.m: mag heading /// s.s: speed knots /// k.k: speed k/mh /// </summary> /// <param name="talkerId"></param> /// <param name="words"></param> /// <param name="sentence"></param> private void ParseCOGandSOG(string talkerId, string[] words, string sentence) { double cogT; double cogM; double sog; if (words.Length < 6) { DebugLog.WriteLine("Invalid VTG sentence: " + sentence); return; } try { cogT = Double.Parse(words[1]); if (cogT < 0 || cogT > 360) { DebugLog.WriteLine("Invalid heading: " + sentence); return; } cogM = Double.Parse(words[3]); if (cogM < 0 || cogM > 360) { DebugLog.WriteLine("Invalid heading: " + sentence); return; } sog = Double.Parse(words[5]); } catch { DebugLog.WriteLine("Invalid VTG sentence: " + sentence); return; } if (COGSOGEvent != null) { var args = new NmeaCOGSOGEventArgs(cogT, cogM, sog); COGSOGEvent(this, args); } }
/// <summary> /// Parse a complete NMEA sentence /// </summary> /// <param name="sentence">The sentence to parse</param> private void ParseNmeaSentence(string sentence) { DebugLog.WriteLine("NmeaInputPort: " + sentence); // shortest legal would be: // $xxVVV.*xx if (sentence.Length < 10) { DebugLog.WriteLine("invalid sentence, too short:" + sentence); return; } // pull off the global structure of the sentence string verb = sentence.Substring(3, 3); // see if we have a parser for this verb. If not we'll jump out now SentenceParser parser = (SentenceParser)m_sentenceParsers[verb]; if (parser == null) { DebugLog.WriteLine("skipped unknown verb: " + sentence); long processingTime = DateTime.Now.Ticks - m_startProcessing; if (this.ParsedDataDebugEvent != null) { this.ParsedDataDebugEvent(this, new NmeaInputParsedDebugEventArgs(sentence, processingTime)); } return; } // must start with $ if (sentence[0] != '$') { DebugLog.WriteLine("invalid sentence, no prefix: " + sentence); return; } string talkerId = sentence.Substring(1, 2); string checksumSuffix = sentence.Substring(sentence.Length - 3); // the checksum is the last 3 characters and starts with * if (checksumSuffix[0] != '*') { DebugLog.WriteLine("Invalid NMEA, weird checksum: " + sentence); return; } // the digits in the checksum are hex, convert them to a byte byte checksum; try { checksum = (byte)Convert.ToInt32(checksumSuffix.Substring(1), 16); } catch (Exception e) { DebugLog.WriteLine("Invalid NMEA, bad checksum: " + sentence + " e:" + e.ToString()); return; } // compute the checksum and see if it matches byte computedChecksum = 0; string checkedString = sentence.Substring(1, sentence.Length - 4); for (int i = 0; i < checkedString.Length; i++) { var c = (byte)checkedString[i]; computedChecksum ^= c; } if (checksum != computedChecksum) { DebugLog.WriteLine("Checksum failed: " + sentence); return; } // we send the sentence without the prefix and suffix to verb parsers string usefulSentence = sentence.Substring(3, sentence.Length - 6); // call the parser parser(talkerId, usefulSentence.Split(','), sentence); if (this.ParsedDataDebugEvent != null) { long processingTime = DateTime.Now.Ticks - m_startProcessing; this.ParsedDataDebugEvent(this, new NmeaInputParsedDebugEventArgs(sentence, processingTime)); } }