private void ParserOnParserError(NmeaSinkAndSource source, string message, NmeaError errorCode) { if (errorCode == NmeaError.PortClosed) { Task t = Task.Run(() => { lock (_lock) { _activeParsers.Remove(source); } // Can't do this synchronously, as it would cause a deadlock source.StopDecode(); }); _serverTasks.Enqueue(t); _serverControlEvent.Set(); } FireOnParserError(message, errorCode); }
/// <summary> /// Reads NMEA0183 talker sentence from provided string /// </summary> /// <param name="sentence">NMEA0183 talker sentence</param> /// <param name="expectedTalkerId">If this is not TalkerId.Any, only messages with this talker id are parsed, /// all others are ignored. This reduces workload if a source acts as repeater, but the repeated messages are not needed.</param> /// <param name="errorCode">Returns an error code, if the parsing failed</param> /// <returns>TalkerSentence instance, or null in case of an error</returns> /// <remarks><paramref name="sentence"/> does not include new line characters</remarks> public static TalkerSentence?FromSentenceString(string sentence, TalkerId expectedTalkerId, out NmeaError errorCode) { // $XXY, ... const int sentenceHeaderMinLength = 4; // http://www.tronico.fi/OH6NT/docs/NMEA0183.pdf page 2 // defines this as 80 + 1 (for $), but we don't really care if it is something within a reasonable limit. const int MaxSentenceLength = 256; if (sentence == null) { throw new ArgumentNullException(nameof(sentence)); } if (sentence.Length < sentenceHeaderMinLength) { errorCode = NmeaError.MessageToShort; return(null); } if (sentence.Length > MaxSentenceLength) { errorCode = NmeaError.MessageToLong; return(null); } if (sentence[0] != '$' && sentence[0] != '!') { // Valid sentences start with $ or ! (for the AIS sentences) errorCode = NmeaError.NoSyncByte; return(null); } TalkerId talkerId = new TalkerId(sentence[1], sentence[2]); if (expectedTalkerId != TalkerId.Any && expectedTalkerId != talkerId) { errorCode = NmeaError.None; return(null); } int firstComma = sentence.IndexOf(',', 1); if (firstComma == -1) { errorCode = NmeaError.MessageToShort; return(null); } string sentenceIdString = sentence.Substring(3, firstComma - 3); SentenceId sentenceId = new SentenceId(sentenceIdString); string[] fields = sentence.Substring(firstComma + 1).Split(','); int lastFieldIdx = fields.Length - 1; // This returns null as the checksum if there was none, or a very big number if the checksum couldn't be parsed (int?checksum, string lastField) = GetChecksumAndLastField(fields[lastFieldIdx]); fields[lastFieldIdx] = lastField; TalkerSentence result = new TalkerSentence(talkerId, sentenceId, fields); if (checksum.HasValue) { byte realChecksum = CalculateChecksumFromSentenceString(sentence.AsSpan()); if (realChecksum != checksum.Value) { errorCode = NmeaError.InvalidChecksum; return(null); } } errorCode = NmeaError.None; return(result); }
/// <summary> /// Reads NMEA0183 talker sentence from provided string /// </summary> /// <param name="sentence">NMEA0183 talker sentence</param> /// <param name="errorCode">Returns an error code, if the parsing failed</param> /// <returns>TalkerSentence instance, or null in case of an error</returns> /// <remarks><paramref name="sentence"/> does not include new line characters</remarks> public static TalkerSentence?FromSentenceString(string sentence, out NmeaError errorCode) { return(FromSentenceString(sentence, TalkerId.Any, out errorCode)); }
/// <summary> /// Fire an event informing about parser errors /// </summary> /// <param name="message">The message to write</param> /// <param name="error">The kind of error seen</param> protected void FireOnParserError(string message, NmeaError error) { OnParserError?.Invoke(this, message, error); }
private void ParserOnParserError(NmeaSinkAndSource source, string message, NmeaError errorCode) { FireOnParserError(message, errorCode); }