private static void DataReceviedHandler(object sender,
SerialDataReceivedEventArgs e)
{
try
{
SerialPort sp = (SerialPort)sender;
int bytesToRead = sp.BytesToRead;
for (int i = 0; i < bytesToRead; i++)
{
byte[] theByte = new byte[1];
theByte[0] = (byte)sp.ReadByte();
if (theByte[0] == 0x0a)
{
String tempStr = BufferedString.ToString();
String[] NMEASentence = tempStr.Split(new char[]{','});
if (NMEASentence == null) { BufferedString = new StringBuilder(); break; }
switch (NMEASentence[0])
{
case "$GPVTG" :
GPVTG = tempStr.TrimEnd();
if (NMEASentence.Length > 8)
{
GPS_NMEA_GPVTG.CourseTrue = Convert.ToDouble(NMEASentence[1]);
GPS_NMEA_GPVTG.ReferenceTrue = Encoding.UTF8.GetBytes(NMEASentence[2])[0];
if (NMEASentence[3] == "")
{
GPS_NMEA_GPVTG.CourseMagnetic = -0.0D;
}
else
{
GPS_NMEA_GPVTG.CourseMagnetic = Convert.ToDouble(NMEASentence[3]);
}
GPS_NMEA_GPVTG.ReferenceMagnetic = Encoding.UTF8.GetBytes(NMEASentence[4])[0];
GPS_NMEA_GPVTG.Speed = Convert.ToDouble(NMEASentence[5]);
GPS_NMEA_GPVTG.SpeedUnits = Encoding.UTF8.GetBytes(NMEASentence[6])[0];
GPS_NMEA_GPVTG.Mode = (VTGMode)Convert.ToInt32(Encoding.UTF8.GetBytes(NMEASentence[7])[0].ToString());
Debug.Print("Course (True) : " + GPS_NMEA_GPVTG.CourseTrue.ToString("N2") +
" " + new String(Convert.ToChar(GPS_NMEA_GPVTG.ReferenceTrue), 1));
Debug.Print("Course (Mag) : " + GPS_NMEA_GPVTG.CourseMagnetic.ToString("N2") +
" " + new String(Convert.ToChar(GPS_NMEA_GPVTG.ReferenceMagnetic), 1));
Debug.Print("Speed : " + GPS_NMEA_GPVTG.Speed.ToString("N2") +
" " + new String(Convert.ToChar(GPS_NMEA_GPVTG.SpeedUnits), 1));
Debug.Print("Mode : " + GetVTGModeText(GPS_NMEA_GPVTG.Mode));
}
break;
case "$GPGGA":
GPGGA = tempStr.TrimEnd();
if (NMEASentence.Length > 12)
{
GPS_NMEA_GPGGA.GPS_Time.hour = Convert.ToByte(NMEASentence[1].Substring(0, 2));
GPS_NMEA_GPGGA.GPS_Time.minute = Convert.ToByte(NMEASentence[1].Substring(2, 2));
GPS_NMEA_GPGGA.GPS_Time.second = Convert.ToByte(NMEASentence[1].Substring(4, 2));
GPS_NMEA_GPGGA.LatitudeStr = NMEASentence[2];
GPS_NMEA_GPGGA.IsLatitudeNorth = NMEASentence[3] == "N" ? true : false;
GPS_NMEA_GPGGA.LongitudeStr = NMEASentence[4];
GPS_NMEA_GPGGA.IsLongitudeWest = NMEASentence[5] == "W" ? true : false;
GPS_NMEA_GPGGA.PositionFixIndicator = (PositionFix)Convert.ToInt32(NMEASentence[6]);
GPS_NMEA_GPGGA.SatellitesUsed = Convert.ToByte(NMEASentence[7]);
GPS_NMEA_GPGGA.HorizontalDilutionOfPrecision = Convert.ToDouble(NMEASentence[8]);
GPS_NMEA_GPGGA.MSLAltitude = Convert.ToDouble(NMEASentence[9]);
GPS_NMEA_GPGGA.MSLUnits = Encoding.UTF8.GetBytes(NMEASentence[10])[0];
GPS_NMEA_GPGGA.GeoidSeparation = Convert.ToDouble(NMEASentence[11]);
GPS_NMEA_GPGGA.GeoidSeparationUnits = Encoding.UTF8.GetBytes(NMEASentence[12])[0];
}
if (NMEASentence.Length > 13)
{
//Debug.Print(NMEASentence[13]);
//GPS_NMEA_GPGGA.AgeOfDifferentialCorrection = Convert.ToInt32(NMEASentence[13]);
if (NMEASentence.Length >= 14)
{
//Debug.Print(NMEASentence[14]);
//GPS_NMEA_GPGGA.DifferentialReferenceStationID = Convert.ToInt32(NMEASentence[14]);
}
}
Debug.Print("GPS Time => " + GPS_NMEA_GPGGA.GPS_Time.MakeString());
//Debug.Print("Latitude : " + GPS_NMEA_GPGGA.Latitude().MakeString() +
// (GPS_NMEA_GPGGA.IsLatitudeNorth ? "N" : "S"));
//Debug.Print("Longitude : " + GPS_NMEA_GPGGA.Longitude().MakeString() +
// (GPS_NMEA_GPGGA.IsLongitudeWest ? "W" : "E"));
Debug.Print("Latitude : " + GPS_NMEA_GPGGA.LatitudeAsDecimal("N6") +
(GPS_NMEA_GPGGA.IsLatitudeNorth ? "N" : "S"));
Debug.Print("Longitude : " + GPS_NMEA_GPGGA.LongitudeAsDecimal("N6") +
(GPS_NMEA_GPGGA.IsLongitudeWest ? "W" : "E"));
Debug.Print("Position Fix Indicator : " + GetFixIndicatorText(GPS_NMEA_GPGGA.PositionFixIndicator));
Debug.Print("Satellites Used : " + GPS_NMEA_GPGGA.SatellitesUsed.ToString());
Debug.Print("Horizontal Dilution of Precision : " + GPS_NMEA_GPGGA.HorizontalDilutionOfPrecision.ToString("N1"));
Debug.Print("MSL Altitude : " + GPS_NMEA_GPGGA.MSLAltitude.ToString("N1") + " " +
new String(Convert.ToChar(GPS_NMEA_GPGGA.MSLUnits), 1));
break;
//
case "$GPGSA":
GPGSA = tempStr.TrimEnd();
//Debug.Print(GPGSA);
break;
case "$GPRMC":
GPRMC = tempStr.TrimEnd();
if (NMEASentence.Length > 13)
{
GPS_NMEA_GPRMC.GPSTime.hour = Convert.ToByte(NMEASentence[1].Substring(0, 2));
GPS_NMEA_GPRMC.GPSTime.minute = Convert.ToByte(NMEASentence[1].Substring(2, 2));
GPS_NMEA_GPRMC.GPSTime.second = Convert.ToByte(NMEASentence[1].Substring(4, 2));
GPS_NMEA_GPRMC.Status = Encoding.UTF8.GetBytes(NMEASentence[2])[0];
GPS_NMEA_GPRMC.LatitudeStr = NMEASentence[3];
GPS_NMEA_GPRMC.NorS = Encoding.UTF8.GetBytes(NMEASentence[4])[0];
GPS_NMEA_GPRMC.LatitudeStr = NMEASentence[5];
GPS_NMEA_GPRMC.EorW = Encoding.UTF8.GetBytes(NMEASentence[6])[0];
GPS_NMEA_GPRMC.SpeedOverGround = Convert.ToDouble(NMEASentence[7] != "" ? NMEASentence[7] : "0.0");
GPS_NMEA_GPRMC.CourseOverGround = Convert.ToDouble(NMEASentence[8] != "" ? NMEASentence[8] : "0.0");
GPS_NMEA_GPRMC.GPSDateStr = NMEASentence[9];
Debug.Print("Speed Over Ground : " + GPS_NMEA_GPRMC.SpeedOverGround.ToString("N2") +
" knots");
Debug.Print("Course over ground : " + GPS_NMEA_GPRMC.CourseOverGround.ToString("N2"));
}
break;
default:
break;
}
BufferedString = new StringBuilder();
}
else
{
if (theByte[0] > 127)
{
Debug.Print("Value out of ASCII range. MSB set.");
}
else
{
try
{
BufferedString.Append(Encoding.UTF8.GetChars(theByte, 0, 1));
}
catch (Exception ex)
{
Debug.Print("Alpha Station Operations caught an exception\n" + ex.ToString());
}
}
}
}
}
catch (Exception ex)
{
Debug.Print("Alpha Station operations caught an exception : \n" + ex.Message);
Debug.Print(ex.StackTrace);
}
}
It doesn't so much create a separate thread as it places your event handler in the thread that handles the com port. It is a distinction with little difference, but...you do not need any of the normal "while(true)" type of polling, here. The event gets raised by the hardware, regardless of where the main thread of execution or any other threads are in terms of their independent execution.
Most serial devices use text as the transport encoding and usually they terminate a transmission with a line feed, or carriage return line feed pair. (Binary information is usually length-limited, or uses a particular character to determine end of transmission. EOT/ETX). The .NET SerialPort class is quite flexible with respect to serial comms.
So, just write it to take one character at a time and evaluate that. If you store them off in a buffer each time and evaluate them when necessary, it will work fine and last a long time. The StringBuilder class is your friend when the comms are ASCII style. (Actually, use UTF8 encodings).
This is a long snippet -- I am still writing it, but -- it uses a StringBuilder to hole the received characters and evaluates each character. I am not sure, but -- I don't think that Netduino 3 can use the line oriented capablilities of .NET SerialPort. I hope I am wrong about that, actually....