using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; using System.Windows.Interop; using InABox.Core; using NPOI.HPSF; using NPOI.SS.Formula.Functions; using PRSServer; namespace InABox.DigitalMatter { public static class DMFactory { private static readonly Dictionary _devices = new(); private static readonly Dictionary _messages = new(); private static readonly Dictionary> _fields = new(); private static readonly Dictionary _bluetoothtags = new(); private static DumpFormat _dumpFormat; private static string _dumpFile; public static void Initialise(DumpFormat dumpFormat, string dumpFile) { _dumpFormat = dumpFormat; _dumpFile = dumpFile; RegisterMessage(0x00); RegisterMessage(0x01); RegisterMessage(0x04); RegisterMessage(0x05); RegisterMessage(0x06); RegisterField(0x00, "GPS Data"); RegisterField(0x02, "Digital Data"); RegisterField(0x03, "Operator Info"); RegisterField(0x06, "Analogue Data"); RegisterField(0x0F, "Trip Data"); RegisterField(0x1D, "BT Tag List"); RegisterField(0x1E, "BT Tag Data"); // Current DMT Devices RegisterDevice(0x4B, "Bolt"); RegisterDevice(0x44, "Dart2"); RegisterDevice(0x4E, "Eagle"); RegisterDevice(0x4A, "Falcon"); RegisterDevice(0x43, "G62 Cellular"); RegisterDevice(0x4F, "G120"); RegisterDevice(0x4D, "Oyster2 Cellular"); RegisterDevice(0x3E, "Remora2"); RegisterDevice(0x49, "Yabby GPS"); RegisterDevice(0x48, "Yabby WiFi Cellular"); RegisterDevice(0x72, "Manta Fusion"); RegisterDevice(0x73, "G70"); //Obsolete DMT Devices RegisterDevice(0x22, "Dart"); RegisterDevice(0x1E, "Flexi1"); RegisterDevice(0x11, "G52 Solar"); RegisterDevice(0x17, "G60"); RegisterDevice(0x1C, "G100"); RegisterDevice(0x21, "Remora"); RegisterDevice(0x3A, "Oyster Cellular(v1)"); RegisterDevice(0x34, "Sting"); RegisterBluetoothTag(0x00); RegisterBluetoothTag(0x01); RegisterBluetoothTag(0x02); RegisterBluetoothTag(0x03); RegisterBluetoothTag(0x04); RegisterBluetoothTag(0x05); RegisterBluetoothTag(0x06); RegisterBluetoothTag(0x07); RegisterBluetoothTag(0x08); RegisterBluetoothTag(0x09); RegisterBluetoothTag(0x0A); RegisterBluetoothTag(0xFF); } public static void RegisterDevice(byte identifier, string name) { _devices[identifier] = name; } public static string GetDeviceName(byte identifier) { if (_devices.ContainsKey(identifier)) return _devices[identifier]; return string.Format("Unknown Device (0x{0})", BitConverter.ToString(new[] { identifier })); } public static void RegisterMessage(byte identifier) where TMessage : DMMessage { _messages[identifier] = typeof(TMessage); } public static int PeekPayloadLength(IList data) { if(data.Count < 5) { return 0; } return BitConverter.ToUInt16(new byte[] { data[3], data[4] }, 0); } private static DMMessage ParseMessage(IDMReadBuffer buffer) { if (buffer.BufferSize < 3) throw new Exception("Invalid Packet Length"); var magicnumber = buffer.PeekBytes(0, 2); if (magicnumber[0] != 0x02 || magicnumber[1] != 0x55) throw new Exception("Invalid Header"); var messagetype = buffer.PeekByte(2); if (!_messages.ContainsKey(messagetype)) throw new Exception(string.Format("Invalid Message Type({0})", messagetype)); var payloadlength = buffer.PeekUInt16(3); if (buffer.BufferSize - payloadlength < 5) throw new Exception(string.Format("Payload Length Mismatch - Expected: {0} Actual {1}", payloadlength, buffer.BufferSize - 5)); var message = (Activator.CreateInstance(_messages[messagetype]) as DMMessage)!; try { message.Decode(buffer); } catch (Exception e) { Logger.Send( LogType.Error, Environment.CurrentManagedThreadId.ToString(), string.Format("Unable to Parse Message: {0} Data=({1})", e.Message, BitConverter.ToString(buffer.PeekBytes(0, payloadlength + 3))) ); } return message; } private static void DumpMessageBytes(byte[] data, DMMessage message) { switch (_dumpFormat) { case DumpFormat.Raw: using (var stream = DumpStream()) { stream.Write(data); // Write data stream.WriteByte(0x0a); // Newline } break; case DumpFormat.SemiParsed: using (var stream = DumpStream()) { stream.Write(message.Dump()); // Write message dump stream.WriteByte(0x0a); // Newline } break; } } private static void DumpMessageBytes(List data, DMMessage message) { switch (_dumpFormat) { case DumpFormat.Raw: using (var stream = DumpStream()) { stream.Write(data.ToArray()); // Write data stream.WriteByte(0x0a); // Newline } break; case DumpFormat.SemiParsed: using (var stream = DumpStream()) { stream.Write(message.Dump()); // Write message dump stream.WriteByte(0x0a); // Newline } break; } } public static DMMessage ParseMessage(byte[] data) { var buffer = new DMArrayReadBuffer(data); var message = ParseMessage(buffer); DumpMessageBytes(data, message); return message; } public static DMMessage ParseMessage(List data) { var buffer = new DMListReadBuffer(data); var message = ParseMessage(buffer); DumpMessageBytes(data, message); return message; } public static void RegisterField(byte identifier, string name) where TField : DMField { _fields[identifier] = new Tuple(typeof(TField), name); } public static string GetFieldName(byte identifier) { if (_fields.ContainsKey(identifier)) return _fields[identifier].Item2; return string.Format("Unknown Field (0x{0})", BitConverter.ToString(new[] { identifier })); } public static DMField ParseField(IDMReadBuffer buffer) { if (buffer.BufferSize < 2) throw new Exception("Invalid Field Length"); var type = buffer.PeekByte(0); if (!_fields.ContainsKey(type)) throw new Exception(string.Format("Invalid Field Type ({0})", type)); var field = Activator.CreateInstance(_fields[type].Item1) as DMField; field.Decode(buffer); return field; } public static void RegisterBluetoothTag(byte identifier) where TTagType : DMBluetoothTag { _bluetoothtags[identifier] = typeof(TTagType); } public static DMBluetoothTag ParseBluetoothTag(byte type, byte[] data) { if (!_bluetoothtags.ContainsKey(type)) throw new Exception(string.Format("Invalid Bluetooth Tag Type ({0})", type)); var tag = Activator.CreateInstance(_bluetoothtags[type]) as DMBluetoothTag; tag.DataLength = (byte)data.Length; tag.Decode(data); return tag; } private static Stream DumpStream() { return new FileStream(_dumpFile, FileMode.Append); } private static void DumpData(byte[] data) { try { using (var stream = new FileStream(_dumpFile, FileMode.Append)) { stream.Write(data); } } catch (Exception e) { Logger.Send(LogType.Error, "", $"Error while dumping data: {CoreUtils.FormatException(e)}"); } } } }