public void FinishMSDU(OpenSatelliteProject.GRB.MSDU msdu) { if (running) { if (packets.Count >= MAX_QUEUE_LENGTH) { OpenSatelliteProject.GRB.MSDU lmsdu; UIConsole.Warn("MSDU Manager Queue is full!!!! Some MSDU might be discarded!"); packets.TryDequeue(out lmsdu); } packets.Enqueue(msdu); } }
public void NewFile(Tuple <string, object> file) { if (running) { if (packets.Count >= MAX_QUEUE_LENGTH) { Tuple <string, object> f; UIConsole.Warn("File Handler Queue is full!!!! Files might be discarded!"); packets.TryDequeue(out f); } packets.Enqueue(file); } }
public void NewPacket(byte[] packet) { if (running) { if (packets.Count >= MAX_QUEUE_LENGTH) { byte[] drop; UIConsole.Warn("Channel Manager Queue is full!!!! Samples might be dropped."); packets.TryDequeue(out drop); } packets.Enqueue(packet); } }
public static byte[] ReadFileFromOSPAssembly(string filename) { byte[] buffer = null; Assembly xritAssembly = GetAssemblyByName("XRIT"); try { using (Stream stream = xritAssembly.GetManifestResourceStream(string.Format("OpenSatelliteProject.LUT.{0}", filename))) { int num2; buffer = new byte[stream.Length]; for (int i = 0; i < stream.Length; i += num2) { num2 = ((stream.Length - i) > 0x1000L) ? 0x1000 : (((int)stream.Length) - i); stream.Read(buffer, i, num2); } } } catch (Exception) { UIConsole.Warn(string.Format("Cannot load {0} from library.", filename)); } return(buffer); }
void HandleCADU(byte[] data) { long caduNumber = -1; if (data.Length == 2052) { byte[] counter = data.Take(4).ToArray(); data = data.Skip(4).ToArray(); caduNumber = BitConverter.ToUInt32(counter, 0); } if (lastCaduNumber != -1 && caduNumber != -1) { if (lastCaduNumber == caduNumber) { UIConsole.Warn("CADU Packet arrived duplicated! Dropping."); return; } if (lastCaduNumber > caduNumber) { UIConsole.Warn("CADU Packet arrived out of order! Dropping."); return; } if (lastCaduNumber + 1 != caduNumber) { long missingPackets = caduNumber - lastPacketNumber + 1; UIConsole.Warn($"Missing {missingPackets} CADU packets!"); } } if (FindSyncMark(data) != 0) { UIConsole.Error("Corrupted CADU data!"); return; } PostChannelData(data.Skip(4).ToArray()); }
void ThreadLoop() { UIConsole.Debug("MSDU Thread started"); while (running) { OpenSatelliteProject.GRB.MSDU msdu; if (packets.TryDequeue(out msdu)) { ProcessMSDU(msdu); } List <int> keys = msduCache.Keys.ToList(); keys.ForEach(k => { var minfo = msduCache[k]; if (minfo.Expired) { UIConsole.Warn($"Product {k:X3} expired. Dumping..."); string msduFile = Path.Combine(FileHandler.TemporaryFileFolder, minfo.FileName); string target = Path.Combine(FileHandler.TemporaryFileFolder, $"{k:X3}-{LLTools.TimestampMS()}-{Tools.RandomString(8)}"); File.Move(msduFile, target); if (EnumHelpers.APID2Type(k) == PayloadType.Generic) { fileHandleManager.NewFile(new Tuple <string, object>(target, minfo.GenericHeader)); } else { fileHandleManager.NewFile(new Tuple <string, object>(target, minfo.ImageHeader)); } msduCache.Remove(k); } }); // Thread.Yield(); // This might be better Thread.Sleep(2); } UIConsole.Debug("Channel Thread stopped"); }
void ChannelDataLoop() { try { UIConsole.Log("Channel Data Loop started"); byte[] buffer = new byte[2042]; IPHostEntry ipHostInfo = Dns.GetHostEntry(ChannelDataServerName); IPAddress ipAddress = new IPAddress(new byte[] { 127, 0, 0, 1 }); foreach (IPAddress ip in ipHostInfo.AddressList) { if (ip.AddressFamily != AddressFamily.InterNetworkV6) { ipAddress = ip; break; } } IPEndPoint remoteEP = new IPEndPoint(ipAddress, ChannelDataServerPort); Socket sender = null; while (channelDataThreadRunning) { bool isConnected = true; UIConsole.Log("Channel Data Thread connect"); try { sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { ReceiveTimeout = 5000 }; sender.Connect(remoteEP); isConnected = true; UIConsole.Log($"Socket connected to {sender.RemoteEndPoint}"); int nullReceive = 0; while (isConnected) { try { var receivedBytes = sender.Receive(buffer); if (receivedBytes < buffer.Length && receivedBytes != 0) { UIConsole.Error("Received less bytes than channel data!"); Thread.Sleep(200); nullReceive = 0; } else if (receivedBytes == 0) { nullReceive++; if (nullReceive == 5) { UIConsole.Error("Cannot reach server. Dropping connection!"); isConnected = false; sender.Shutdown(SocketShutdown.Both); sender.Disconnect(false); sender.Close(); } } else { nullReceive = 0; this.PostChannelData(buffer); } } catch (ArgumentNullException ane) { UIConsole.Error($"ArgumentNullException : {ane}"); isConnected = false; } catch (SocketException) { isConnected = false; } catch (Exception e) { UIConsole.Error($"Unexpected exception : {e}"); isConnected = false; } DataConnected = isConnected; if (!channelDataThreadRunning) { break; } } sender.Shutdown(SocketShutdown.Both); sender.Disconnect(false); sender.Close(); } catch (ArgumentNullException ane) { UIConsole.Error($"ArgumentNullException : {ane}"); } catch (SocketException se) { UIConsole.Error($"SocketException : {se}"); } catch (Exception e) { UIConsole.Error($"Unexpected exception : {e}"); } if (channelDataThreadRunning) { UIConsole.Warn("Socket closed. Waiting 1s before trying again."); Thread.Sleep(1000); } } UIConsole.Debug("Requested to close Channel Data Thread!"); try { if (sender != null) { sender.Shutdown(SocketShutdown.Both); sender.Disconnect(false); sender.Close(); } } catch (Exception e) { UIConsole.Debug($"Exception thrown when closing socket: {e} Ignoring."); } UIConsole.Log("Channel Data Thread closed."); } catch (Exception e) { CrashReport.Report(e); } }
void ProcessMSDU(OpenSatelliteProject.GRB.MSDU msdu) { try { if (msdu.APID == 2047) { // Skip fill packet return; } bool firstOrSinglePacket = msdu.Sequence == SequenceType.FIRST_SEGMENT || msdu.Sequence == SequenceType.SINGLE_DATA; Packets++; if (!msdu.Valid || !msdu.Full) { if (msdu.FrameLost) { UIConsole.Error($"Lost some frames on MSDU, the file will be corrupted. CRC Match: {msdu.Valid} - Size Match: {msdu.Full}"); } else { UIConsole.Error($"Corrupted MSDU. CRC Match: {msdu.Valid} - Size Match: {msdu.Full}"); } } if (!msdu.Valid) { CRCFails++; return; } var payloadType = EnumHelpers.APID2Type(msdu.APID); if (msdu.Sequence == SequenceType.FIRST_SEGMENT || msdu.Sequence == SequenceType.SINGLE_DATA) { if (msduCache.ContainsKey(msdu.APID)) { var minfo = msduCache[msdu.APID]; UIConsole.Warn($"Received First Segment for {msdu.APID:X3} but last data wasn't saved to disk yet! Forcing dump."); // This can only happen for multi-segment file. string msduFile = Path.Combine(FileHandler.TemporaryFileFolder, minfo.FileName); string target = Path.Combine(FileHandler.TemporaryFileFolder, $"{msdu.APID:X3}-{LLTools.TimestampMS()}-{Tools.RandomString(8)}"); File.Move(msduFile, target); if (payloadType == PayloadType.Generic) { fileHandleManager.NewFile(new Tuple <string, object>(target, minfo.GenericHeader)); } else { fileHandleManager.NewFile(new Tuple <string, object>(target, minfo.ImageHeader)); } msduCache.Remove(msdu.APID); } var msInfo = new MSDUInfo() { APID = msdu.APID, FileName = msdu.TemporaryFilename, GenericHeader = payloadType == PayloadType.Generic ? new GRBGenericHeader(msdu.APID, msdu.Data.Skip(8).Take(21).ToArray()) : null, ImageHeader = payloadType == PayloadType.ImageData ? new GRBImageHeader(msdu.APID, msdu.Data.Skip(8).Take(34).ToArray()) : null, }; msduCache.Add(msdu.APID, msInfo); } else if (msdu.Sequence == SequenceType.LAST_SEGMENT || msdu.Sequence == SequenceType.CONTINUED_SEGMENT) { if (!msduCache.ContainsKey(msdu.APID)) { UIConsole.Warn("Orphan Packet!"); return; } } var msduInfo = msduCache[msdu.APID]; msduInfo.Refresh(); string path = FileHandler.TemporaryFileFolder; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string filename = Path.Combine(FileHandler.TemporaryFileFolder, msduInfo.FileName); int totalOffset; if (firstOrSinglePacket) { totalOffset = 8; if (payloadType == PayloadType.Generic) { totalOffset += 21; } else { totalOffset += 34; } } else { totalOffset = 8; } byte[] dataToSave = msdu.Data.Skip(totalOffset).ToArray(); dataToSave = dataToSave.Take(dataToSave.Length - 4).ToArray(); // Remove CRC using (FileStream fs = new FileStream(filename, firstOrSinglePacket ? FileMode.Create : FileMode.Append, FileAccess.Write)) { using (BinaryWriter sw = new BinaryWriter(fs)) { sw.Write(dataToSave); sw.Flush(); } } if (msdu.Sequence == SequenceType.LAST_SEGMENT || msdu.Sequence == SequenceType.SINGLE_DATA) { string target = Path.Combine(FileHandler.TemporaryFileFolder, $"{msdu.APID:X3}-{LLTools.TimestampMS()}-{Tools.RandomString(8)}"); File.Move(filename, target); if (payloadType == PayloadType.Generic) { fileHandleManager.NewFile(new Tuple <string, object>(target, msduInfo.GenericHeader)); } else { fileHandleManager.NewFile(new Tuple <string, object>(target, msduInfo.ImageHeader)); } msduCache.Remove(msdu.APID); } } catch (Exception e) { UIConsole.Error(String.Format("Exception on FinishMSDU: {0}", e)); } }
public static List <XRITBaseHeader> GetHeaderData(byte[] data) { List <XRITBaseHeader> headers = new List <XRITBaseHeader>(); int maxLength = data.Length; // Initial Guess int c = 0; // Parse Primary Header for size int type = data[0]; if (type != (int)HeaderType.PrimaryHeader) { UIConsole.Error($"Expected PrimaryHeader({(int)HeaderType.PrimaryHeader} got {type}. File is corrupt."); return(headers); } byte[] tmp = data.Skip(1).Take(2).ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(tmp); } int size = BitConverter.ToUInt16(tmp, 0); tmp = data.Take(size).ToArray(); PrimaryRecord fh = LLTools.ByteArrayToStruct <PrimaryRecord>(tmp); fh = LLTools.StructToSystemEndian(fh); maxLength = (int)fh.HeaderLength; // Set the correct size byte[] headerData = data.Take(maxLength).ToArray(); data = data.Skip(maxLength).ToArray(); // Parse Secondary Headers while (c < maxLength) { type = headerData[0]; tmp = headerData.Skip(1).Take(2).ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(tmp); } size = BitConverter.ToUInt16(tmp, 0); tmp = headerData.Take(size).ToArray(); if (tmp.Length < size) { UIConsole.Warn($"Not enough data for unpack header: Expected {size} got {tmp.Length} - Header Type: {type} - File might be corrupted."); if (c + size > maxLength) { UIConsole.Debug($"c + size > maxLength: {c} + {size} > {maxLength}"); size = maxLength - c - 1; c = maxLength; } } else { c += size; } headerData = headerData.Skip(size).ToArray(); XRITBaseHeader h; switch (type) { case (int)HeaderType.PrimaryHeader: fh = LLTools.ByteArrayToStruct <PrimaryRecord>(tmp); fh = LLTools.StructToSystemEndian(fh); h = new PrimaryHeader(fh); maxLength = (int)fh.HeaderLength; // Set the correct size break; case (int)HeaderType.ImageStructureRecord: ImageStructureRecord isr = LLTools.ByteArrayToStruct <ImageStructureRecord>(tmp); isr = LLTools.StructToSystemEndian(isr); h = new ImageStructureHeader(isr); break; case (int)HeaderType.ImageNavigationRecord: ImageNavigationRecord inr = LLTools.ByteArrayToStruct <ImageNavigationRecord>(tmp); inr = LLTools.StructToSystemEndian(inr); h = new ImageNavigationHeader(inr); break; case (int)HeaderType.ImageDataFunctionRecord: // Cannot marshable due variable length //ImageDataFunctionRecord idfr = LLTools.ByteArrayToStruct<ImageDataFunctionRecord>(tmp); //idfr = LLTools.StructToSystemEndian(idfr); ImageDataFunctionRecord idfr = new ImageDataFunctionRecord(); idfr.Data = System.Text.Encoding.UTF8.GetString(tmp.Skip(3).ToArray()); h = new ImageDataFunctionHeader(idfr); break; case (int)HeaderType.AnnotationRecord: // Cannot be marshalled due variable length //AnnotationRecord ar = LLTools.ByteArrayToStruct<AnnotationRecord>(tmp); //ar = LLTools.StructToSystemEndian(ar); AnnotationRecord ar = new AnnotationRecord(); ar.Filename = System.Text.Encoding.UTF8.GetString(tmp.Skip(3).ToArray()); h = new AnnotationHeader(ar); break; case (int)HeaderType.TimestampRecord: TimestampRecord tr = LLTools.ByteArrayToStruct <TimestampRecord>(tmp); tr = LLTools.StructToSystemEndian(tr); h = new TimestampHeader(tr); break; case (int)HeaderType.AncillaryTextRecord: // Cannot be marshalled due variable length. // AncillaryText at = LLTools.ByteArrayToStruct<AncillaryText>(tmp); //at = LLTools.StructToSystemEndian(at); AncillaryText at = new AncillaryText(); at.Data = System.Text.Encoding.UTF8.GetString(tmp.Skip(3).ToArray()); h = new AncillaryHeader(at); break; case (int)HeaderType.KeyRecord: h = new XRITBaseHeader(HeaderType.KeyRecord, tmp); break; case (int)HeaderType.SegmentIdentificationRecord: SegmentIdentificationRecord sir = LLTools.ByteArrayToStruct <SegmentIdentificationRecord>(tmp); sir = LLTools.StructToSystemEndian(sir); h = new SegmentIdentificationHeader(sir); break; case (int)HeaderType.NOAASpecificHeader: NOAASpecificRecord nsr = LLTools.ByteArrayToStruct <NOAASpecificRecord>(tmp); nsr = LLTools.StructToSystemEndian(nsr); h = new NOAASpecificHeader(nsr); break; case (int)HeaderType.HeaderStructuredRecord: // Cannot be marshalled due variable length //HeaderStructuredRecord hsr = LLTools.ByteArrayToStruct<HeaderStructuredRecord>(tmp); //hsr = LLTools.StructToSystemEndian(hsr); // Header Structured Record doesn't have endianess dependant fields HeaderStructuredRecord hsr = new HeaderStructuredRecord(); hsr.Data = System.Text.Encoding.UTF8.GetString(tmp.Skip(3).ToArray()); h = new HeaderStructuredHeader(hsr); break; case (int)HeaderType.RiceCompressionRecord: RiceCompressionRecord rcr = LLTools.ByteArrayToStruct <RiceCompressionRecord>(tmp); rcr = LLTools.StructToSystemEndian(rcr); h = new RiceCompressionHeader(rcr); break; case (int)HeaderType.DCSFileNameRecord: // Cannot be marshalled due variable length //DCSFilenameRecord dfr = LLTools.ByteArrayToStruct<DCSFilenameRecord>(tmp); //dfr = LLTools.StructToSystemEndian(dfr); // DCS Filename Record doesn't have endianess dependant fields DCSFilenameRecord dfr = new DCSFilenameRecord(); dfr.Filename = System.Text.Encoding.UTF8.GetString(tmp.Skip(3).ToArray()); h = new DCSFilenameHeader(dfr); break; case (int)HeaderType.Head9: Head9 h9 = new Head9(); h9.Data = tmp.Skip(3).ToArray(); h = new Head9Header(h9); ((Head9Header)h).FileName = $"buggy_file_{LLTools.TimestampMS()}.lrit"; tmp.Skip(3).ToArray().Separate(new byte[] { 0x00 }).ToList().ForEach((barr) => { if (barr.Length > 0 && barr[0] == 0x1F) { ((Head9Header)h).FileName = System.Text.Encoding.UTF8.GetString(barr.Skip(1).ToArray()); ((Head9Header)h).FileName = LLTools.StripNonPrintable(((Head9Header)h).FileName); } }); UIConsole.Debug($"Got Head9 which may be a bug. Filename: {((Head9Header)h).FileName}"); break; default: h = new XRITBaseHeader(); h.Type = HeaderType.Unknown; break; } h.RawData = tmp; headers.Add(h); } return(headers); }
void HandleBBFrame(byte[] data) { long counter = -1; if (data.Length == 5384 || data.Length == 7278) { // Ayecka Packet Count is broken byte[] countData = data.Take(4).ToArray(); data = data.Skip(4).ToArray(); if (countData[0] == 0xB8) // DVB-S2 Layer 3 Adaptation Header { counter = countData[3]; } else { UIConsole.Warn("Looks like not a ayecka output"); } } bool QPSK = data.Length == 7274; if (lastPacketNumber != -1 && counter != -1 && lastPacketNumber != 255) { if (lastPacketNumber == counter) { UIConsole.Warn("Packet arrived duplicated! Dropping."); return; } if (lastPacketNumber > counter) { UIConsole.Warn($"Packet arrived out of order! - Last: {lastPacketNumber}, Current: {counter}"); // return; } if (lastPacketNumber + 1 != counter) { long missingPackets = counter - lastPacketNumber + 1; UIConsole.Warn($"Missing {missingPackets} packets! - Last: {lastPacketNumber}, Current: {counter}"); } } lastPacketNumber = counter; byte[] bbHeader = data.Take(10).ToArray(); data = data.Skip(10).ToArray(); // TODO: Maybe parse BB Header? lastData = lastData.Concat(data).ToArray(); if (!lastFrame.Any()) { while (lastData.Length > 0) { int pos = FindSyncMark(lastData); if (pos == -1) { return; } lastData = lastData.Skip(pos).ToArray(); byte[] frameData = lastData.Length > 2048 ? lastData.Take(2048).ToArray() : lastData; lastData = lastData.Skip(frameData.Length).ToArray(); lastFrame.AddRange(frameData); if (lastFrame.Count() == 2048) { HandleCADU(lastFrame.ToArray()); lastFrame.Clear(); } } } else { int remainingBytes = 2048 - lastFrame.Count(); byte[] frameData = lastData.Length > remainingBytes?lastData.Take(remainingBytes).ToArray() : lastData; lastData = lastData.Length > remainingBytes?lastData.Skip(remainingBytes).ToArray() : new byte[0]; lastFrame.AddRange(frameData); if (lastFrame.Count() == 2048) { HandleCADU(lastFrame.ToArray()); lastFrame.Clear(); } } }
public void ParseBytes(byte[] data) { uint counter; bool replayFlag; bool ovfVcnt; bool ovfVcntProblem; bool frameJump; if (data.Length < FRAMESIZE) { throw new Exception(String.Format("Not enough data. Expected {0} and got {1}", FRAMESIZE, data.Length)); } channelId = (data[1] & 0x3F); byte[] cb = data.Skip(2).Take(4).ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(cb); } cb[0] = 0x00; counter = BitConverter.ToUInt32(cb, 0); //counter &= 0xFFFFFF00; counter >>= 8; replayFlag = (data[5] & 0x80) > 0; if (replayFlag) { UIConsole.Debug("Replay Flag set. Skipping packet."); return; } if (counter - lastFrame - 1 == -1) { UIConsole.Warn("Last packet same ID as the current one but no replay bit set! Skipping packet."); return; } frameJump = lastFrame > counter; ovfVcnt = frameJump && counter == 0; ovfVcntProblem = ovfVcnt && (0xFFFFFF - lastFrame) + counter - 1 > 0; if (frameJump && !ovfVcnt) { UIConsole.Warn($"Frame Jump occured. Current Frame: {counter} Last Frame: {lastFrame}"); if (lastAPID != -1) { temporaryStorage[lastAPID].FrameLost = true; } } else if (lastFrame != -1 && lastFrame + 1 != counter && !ovfVcnt) { UIConsole.Error(String.Format("Lost {0} frames. Last Frame #{1} - Current Frame #{2} on VCID {3}", counter - lastFrame - 1, lastFrame, counter, channelId)); if (lastAPID != -1) { temporaryStorage[lastAPID].FrameLost = true; } } else if (!IgnoreCounterJump && lastFrame != -1 && ovfVcntProblem) { UIConsole.Error(String.Format("Lost {0} frames. Last Frame #{1} - Current Frame #{2} on VCID {3}", (0xFFFFFF - lastFrame) + counter - 1, lastFrame, counter, channelId)); if (lastAPID != -1) { temporaryStorage[lastAPID].FrameLost = true; } } if (ovfVcntProblem && IgnoreCounterJump || frameJump && IgnoreCounterJump) { UIConsole.Warn($"Frame Jump detected from {lastFrame} to {counter} on VCID {channelId} but IgnoreCounterJump is set to true. Ignoring..."); } if (lastFrame != -1) { if (frameJump && !ovfVcnt) { // manager.FrameLoss++; } else if (!IgnoreCounterJump && ovfVcnt) { int losses = (int)Math.Abs((0xFFFFFF - lastFrame) + counter - 1); if (losses < MAX_ACCOUTABLE_LOSSES) { FrameLoss += losses; } else { UIConsole.Warn($"Frame Lost ({losses}) in this section is higher than max accountable losses. Not accounting for it (probably corrupt frame)."); } } else if (!ovfVcnt) { int losses = (int)Math.Abs(counter - lastFrame - 1); if (losses < MAX_ACCOUTABLE_LOSSES) { FrameLoss += losses; } else { UIConsole.Warn($"Frame Lost ({losses}) in this section is higher than max accountable losses. Not accounting for it (probably corrupt frame)."); } } } if (frameJump && !ovfVcnt) { FrameJumps++; } if (lastFrame < counter || ovfVcnt || frameJump) { lastFrame = (int)counter; } else { UIConsole.Warn($"LastFrame is bigger than currentFrame ({lastFrame} > {counter}). Not changing current number..."); } cb = data.Skip(6).Take(2).ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(cb); } int fhp = BitConverter.ToUInt16(cb, 0) & 0x7FF; data = data.Skip(8).ToArray(); // Data is now TP_PDU var p = Tuple.Create(0, new byte[0]); if (fhp != 2047) // Has a packet start { if (lastAPID == -1 && buffer.Length > 0) { // There was not enough data to packetize last time. So lets fill the buffer until the fhp and create packet. if (fhp > 0) { buffer = buffer.Concat(data.Take(fhp)).ToArray(); data = data.Skip(fhp).ToArray(); fhp = 0; } p = CreatePacket(buffer); lastAPID = p.Item1; buffer = p.Item2; } if (lastAPID != -1) { if (fhp > 0) { temporaryStorage[lastAPID].AddDataBytes(buffer.Concat(data.Take(fhp)).ToArray()); data = data.Skip(fhp).ToArray(); fhp = 0; } if (!temporaryStorage[lastAPID].Full && !temporaryStorage[lastAPID].FrameLost && lastAPID != 2047) { Bugs++; StackFrame callStack = new StackFrame(0, true); UIConsole.Debug(String.Format("Problem at line {0} in file {1}! Not full! Check code for bugs!", callStack.GetFileLineNumber(), callStack.GetFileName())); } msduManager.FinishMSDU(temporaryStorage[lastAPID]); temporaryStorage.Remove(lastAPID); lastAPID = -1; } buffer = buffer.Concat(data.Skip(fhp)).ToArray(); p = CreatePacket(buffer); lastAPID = p.Item1; buffer = p.Item2; } else { if (buffer.Length > 0 && lastAPID != -1) { buffer = buffer.Concat(data).ToArray(); p = CreatePacket(buffer); lastAPID = p.Item1; buffer = p.Item2; } else if (lastAPID == -1) { buffer = buffer.Concat(data).ToArray(); p = CreatePacket(buffer); lastAPID = p.Item1; buffer = p.Item2; } else if (buffer.Length > 0) { UIConsole.Error("EDGE CASE! PLEASE REPORT THIS MESSAGE"); } else { temporaryStorage[lastAPID].AddDataBytes(data); } } }