public static void OnDeviceDataReceieved(object sender, FrameReceivedEventArgs e) { N2kFrame n2kFrame = (N2kFrame)e.ReceivedFrame; CANStreamer stream = sender as CANStreamer; CANDevice dev = UpdateAddDevice(n2kFrame, stream.Name); }
private bool SetProductInformation(N2kFrame n2kFrame) { bool changed = false; lock (Lock) { if (!EqualBytesLongUnrolled(PiData, n2kFrame.Data)) { // We pass here field description and use NMEA2000 definition N2kVersion = BitConverter.ToUInt16(n2kFrame.Data, 0); ProductCode = BitConverter.ToUInt16(n2kFrame.Data, 2); ModelID = N2kASCIIField.ReadString(n2kFrame.Data, 4, 32); SwCode = N2kASCIIField.ReadString(n2kFrame.Data, 36, 32); ModelVersion = N2kASCIIField.ReadString(n2kFrame.Data, 68, 32); ModelSerialCode = N2kASCIIField.ReadString(n2kFrame.Data, 100, 32); CertificationLevel = n2kFrame.Data[132]; LoadEquivalency = n2kFrame.Data[133]; PiData = n2kFrame.Data.ToArray(); changed = true; } } return(changed); }
private bool SetDeviceInformation(N2kFrame n2kFrame) { bool changed = false; lock (Lock) { UInt64 _ID = BitConverter.ToUInt64(n2kFrame.Data, 0); if (ID != _ID) { ID = _ID; // We pass here field description and use NMEA2000 definition UInt32 UnicAndMCode = BitConverter.ToUInt32(n2kFrame.Data, 0); UniqueNumber = UnicAndMCode & 0x1FFFFF; ManufacturerCode = (UnicAndMCode >> 21) & 0x7ff; DeviceFunction = n2kFrame.Data[5]; DeviceClass = (UInt32)((n2kFrame.Data[6] >> 1) & 0x7f); IndustryGroup = (n2kFrame.Data[7] >> 4) & 0x7; changed = true; } } return(changed); }
private static void UpdateDevice(CANDevice dev, N2kFrame n2kFrame) { var e = DeviceListChange; if (dev.UpdateDevice(n2kFrame) && e != null) { e(); } }
public override int ProcessBytes(byte[] bytes, int offset, int size) { N2kHeader n2kHeader = new N2kHeader(bytes[0], bytes[1], bytes[2], bytes[3]); byte[] n2kData = new byte[size - 4]; Array.Copy(bytes, 4, n2kData, 0, size - 4); N2kFrame n2kFrame = new N2kFrame(n2kHeader, n2kData, DateTime.Now); OnFrameCreated(n2kFrame); return(size); }
private static CANDevice AddDevice(N2kFrame n2kFrame, string streamName) { CANDevice dev = null; int Source; if (Int32.TryParse(n2kFrame.Header.Source, out Source)) { dev = new CANDevice(Source, streamName); lock (Lock) { dev.Source = Source; _Devices.Add(Source, dev); } UpdateDevice(dev, n2kFrame); } return(dev); }
// Given a (possibly partially) completed PGN message, // described by a PGN number, and the apparent 'byte length' // for the message (which is only relevant if the message is a // multiple packet message), return the // PGNDefn that allows this message to be decoded public PGNDefn GetPGNDefn(N2kFrame msg) { uint PGN = (uint)msg.Header.PGN; int pgnIndex; if (!PGNDictionary.TryGetValue(PGN, out pgnIndex)) { // No matching PGN definition; return UnknownPGNDefn return(UnknownPGNDefn); } else { PGNDefn pgn = PGNDefns[pgnIndex]; // Is this a multiple definition PGN? (If so, it must be a fast packet PGN?) if (!pgn.HasMultipleDefinitions) { // Only one matching definition available; return it // int iBytesTransmitted = pgn.ByteLength <= 8 ? msg.Data.Length : msg.Data[1]; return(PGNDefns[pgnIndex]); } else { // Find the matching definition while ((pgnIndex < PGNDefns.Length) && (PGNDefns[pgnIndex].PGN == pgn.PGN)) { if (PGNDefns[pgnIndex].ByteLength == msg.Data[1]) { return(PGNDefns[pgnIndex]); } else { // Find any PGN that is not too long, just on case we cannot find any with an exact match if (pgn.ByteLength < msg.Data[1]) { pgn = PGNDefns[pgnIndex]; } pgnIndex++; } } return(pgn); } } }
public override byte[] GetBytes(Frame frame) { N2kFrame n2kFrame = frame as N2kFrame; if (frame == null) { ReportHandler.LogWarning("Attempt to send non-N2k frame as N2k datagram"); return(null); } byte[] datagram = new byte[4 + n2kFrame.Data.Length]; datagram[0] = n2kFrame.Header.Byte0; datagram[1] = n2kFrame.Header.Byte1; datagram[2] = n2kFrame.Header.Byte2; datagram[3] = n2kFrame.Header.Byte3; Array.Copy(n2kFrame.Data, 0, datagram, 4, n2kFrame.Data.Length); return(datagram); }
public bool UpdateDevice(N2kFrame n2kFrame) { bool changed = false; switch (n2kFrame.Header.PGN) { case 60928: changed = SetDeviceInformation(n2kFrame); break; case 126996: changed = SetProductInformation(n2kFrame); break; case 126998: changed = SetConfigurationInformation(n2kFrame); break; } return(changed); }
public override byte[] GetBytes(Frame frame) { N0183Frame n0183Frame = frame as N0183Frame; if (n0183Frame != null) { return(Encoding.ASCII.GetBytes(n0183Frame.FullMessage + "\r\n")); } N2kFrame n2kFrame = frame as N2kFrame; if (n2kFrame != null) { return(Encoding.ASCII.GetBytes(FrameConversion.PackN2k(n2kFrame).FullMessage + "\r\n")); } AISFrame aisFrame = frame as AISFrame; if (aisFrame != null) { // TODO : Breaking up message if too long int padbits = 6 * aisFrame.AISData.AISString.Length - 8 * aisFrame.AISData.AISBytes.Length; // [0, 5] string message = "!AIVDM,1,1,,A," + aisFrame.AISData.AISString + "," + padbits; // Add checksum byte checksum = 0; for (int i = 1; i < message.Length; i++) { checksum ^= Convert.ToByte(message[i]); } message += "*" + checksum.ToString("X2"); return(Encoding.ASCII.GetBytes(message + "\r\n")); } throw new Exception("Attempt to send unknown frame type: '" + frame.GetType().Name + "'"); }
private bool SetConfigurationInformation(N2kFrame n2kFrame) { bool changed = false; lock (Lock) { if (!EqualBytesLongUnrolled(CiData, n2kFrame.Data)) { // We pass here field description and use NMEA2000 definition int ByteOffset = 0; int ByteLength = 0; InstallationDescription1 = N2kStringField.ReadString(n2kFrame.Data, ByteOffset, ref ByteLength); ByteOffset += ByteLength; ByteLength = 0; InstallationDescription2 = N2kStringField.ReadString(n2kFrame.Data, ByteOffset, ref ByteLength); ByteOffset += ByteLength; ByteLength = 0; Manufacturer = N2kStringField.ReadString(n2kFrame.Data, ByteOffset, ref ByteLength); CiData = n2kFrame.Data.ToArray(); changed = true; } } return(changed); }
// Private methods private void ProcessN2kMessage(ActisenseMessage msg) { /* This N2kDataReceived message goes: * [0] Priority * [1] PGN LSB=Least Significant Byte * [2] PGN Middle Byte * [3] PGN MSB=MostSignificant Byte * [4] Destination * [5] Source * [6,7,8,9] Time stamp, LSB...MSB * [10] N2k payload length * [11, 12, ...] N2k payload (always 8 bytes in data seen so far) */ byte[] payload = msg.MessagePayload; byte Priority = payload[0]; int PGN = payload[1] + (payload[2] << 8) + (payload[3] << 16); byte Destination = payload[4]; byte Source = payload[5]; uint ms = BitConverter.ToUInt32(payload, 6); // TODO: Work out what the Actisense is transmitting in its time-stamp field // as the number of milliseconds appears to go down as well as up (according to a user report) // Note that the Actisense clock appears to be reset when the unit is reset by software, /* as indicated by the following R(read)/W(rite) sequence of commands * Clock 4 bytes * W: 10 2 A1 1 13 4B 10 3 * R: 10 2 93 13 2 2 FD 1 FF 3A 66 9F 0 0 8 FF 3 3 69 0 FA FF FF AC 10 3 * R: 10 2 A0 0E 13 1 0E 0 FA A4 1 0 0 0 0 0 0 1 90 10 3 * W: 10 2 A1 3 13 0 0 49 10 3 * R: 10 2 A0 0E 13 1 0E 0 FA A4 1 0 0 0 0 0 0 0 91 10 3 * W: 10 2 A1 1 10 10 4E 10 3 * R: 10 2 93 13 2 12 F1 1 FF 3A 98 9F 0 0 8 FF 0 0 FF 7F FF 7F FD E4 10 3 * R: 10 2 A0 22 10 10 1 0E 0 FA A4 1 0 0 0 0 0 6D 0 3C 9C 25 93 67 8 3C 9C 2A 93 67 0 BB AF 0 0 3 0 0 0 AB 10 3 * W: 10 2 A1 2 4C 2 0F 10 3 <- some sort of reset? * R: 10 2 A0 0D 4C 1 0E 0 FA A4 1 0 0 0 0 0 2 57 10 3 * W: 10 2 A1 1 13 4B 10 3 <- some sort of reset? * R: 10 2 A0 0F F0 1 0E 0 FA A4 1 0 0 0 0 0 67 8 0 44 10 3 * R: 10 2 93 13 2 12 F1 1 FF 3A 2D 0 0 0 8 FF 0 0 FF 7F FF 7F FD EE 10 3 */ // For now, we just use the computer's clock (and so don't get millisecond accuracy) DateTime thisTime; thisTime = DateTime.Now; //if (firstArrived) //{ // // Check for rollover. // if (ms < lastMs) // baseTime = baseTime.AddMilliseconds(uint.MaxValue); // being 8.1715 years // thisTime = baseTime.AddMilliseconds(ms); //} //else //{ // firstArrived = true; // thisTime = DateTime.Now; // baseTime = thisTime.AddMilliseconds(-ms); //} //lastMs = ms; int N2kDataLength = payload[10]; byte[] N2kData = new byte[N2kDataLength]; Array.Copy(payload, 11, N2kData, 0, N2kDataLength); N2kHeader Header = new N2kHeader(Priority, PGN, Destination, Source); N2kFrame frame = new N2kFrame(Header, N2kData, thisTime); OnFrameCreated(frame); }
// Public methods public static int PackFrame(N2kFrame n2kFrame, byte[] buffer) { /* [0] Message Protocol: 0x93 = N2kDataReceived * [1] Message body length (number of bytes 2, 3, ..., up to last byte before CRC) * [2] Priority * [3] PGN LSB=Least Significant Byte * [4] PGN Middle Byte * [5] PGN MSB=MostSignificant Byte * [6] Destination * [7] Source * [8,9,10,11] Time stamp, LSB...MSB * [12] N2k payload length * [13, 14, ..., 13+[12]=20 ] N2k payload (always 8 bytes in data seen so far) * [21] CRC byte, chosen so that the sum over all bytes is 0 (mod 256). */ // TODO : Test sending // - confirm CRC is generated correctly N2kHeader n2kHeader = n2kFrame.Header; buffer[0] = Escape; buffer[1] = StartOfText; buffer[2] = N2kDataReceived; // TODO : What should this be ? int pgn = n2kHeader.PGN; byte pgnLSB = (byte)(pgn & 0xFF); pgn >>= 8; byte pgnMDB = (byte)(pgn & 0xFF); pgn >>= 8; byte pgnMSB = (byte)(pgn & 0xFF); buffer[4] = n2kHeader.PGNPriority; buffer[5] = pgnLSB; buffer[6] = pgnMDB; buffer[7] = pgnMSB; buffer[8] = n2kHeader.PGNDestination; buffer[9] = n2kHeader.PGNSource; // Set timestamp bytes [10, 11, 12, 13] Array.Copy(BitConverter.GetBytes(DateTime.Now.Millisecond), 0, buffer, 10, 4); // Byte 14 : Length of n2k data buffer[14] = (byte)n2kFrame.Data.Length; // N2k data length : Bytes [15, CRCbyte) byte msgIdx = 15; for (int i = 0; i < n2kFrame.Data.Length; i++) { if (n2kFrame.Data[i] == Escape) { buffer[msgIdx++] = Escape; buffer[msgIdx++] = Escape; } else { buffer[msgIdx++] = n2kFrame.Data[i]; } } int byteSum = 0; for (int i = 2; i < msgIdx; i++) { byteSum += buffer[i]; } byteSum %= 256; buffer[msgIdx++] = (byte)((byteSum == 0) ? 0 : (256 - byteSum)); buffer[3] = (byte)(msgIdx - 5); // Message length : Bytes [4, CRCbyte) buffer[msgIdx++] = Escape; buffer[msgIdx++] = EndOfText; return(msgIdx); }
private static CANDevice UpdateAddDevice(N2kFrame n2kFrame, string streamName) { CANDevice dev = null; int Source; if (Int32.TryParse(n2kFrame.Header.Source, out Source)) { lock (Lock) { // First try to find device with source _Devices.TryGetValue(Source, out dev); if (dev != null) // If we found device, just update it { UpdateDevice(dev, n2kFrame); } else { // If device does not exist, check is it on different source. // Source may change due to address claiming. if (n2kFrame.Header.PGN == 60928) { UInt64 ID = BitConverter.ToUInt64(n2kFrame.Data, 0); int Key = FindDeviceKeyByID(ID); if (Key != -1) // We found device, so register it with new key. { dev = _Devices[Key]; _Devices.Remove(Key); _Devices.Remove(Source); _Devices.Add(Source, dev); lock (dev.Lock) { dev.Source = Source; } // Notify that device address has been changed var e = SourceChange; if (e != null) { e(); } e = DeviceListChange; if (e != null) { e(); } } else { dev = AddDevice(n2kFrame, streamName); var e = SourceChange; if (e != null) { e(); } } } else { // We did not find the device, but we can not add it, since message was // not ISO Address claim PGN 60928 } } // device was null } } return(dev); }