private void DumpMessage() { if (Address != 0) { string message = "A: " + Address.ToString("0000000") + " M: " + Mode; if (MessageBits.Count > 0) { bool[] reorderedNumBits = ReorderBits((bool[])MessageBits.ToArray(typeof(bool)), 4); bool[] reorderedMsgBits = ReorderBits((bool[])MessageBits.ToArray(typeof(bool)), 7); byte[] NumBytes = ByteUtil.BitsToBytes(reorderedNumBits, 4); byte[] msgBytes = ByteUtil.BitsToBytes(reorderedMsgBits, 7); byte[] rawBytes = ByteUtil.BitsToBytes((bool[])MessageBits.ToArray(typeof(bool))); string textMessage = new ASCIIEncoding().GetString(msgBytes); string numMessage = GetNumeric(NumBytes); if (IsPrintable(textMessage)) { message += " (TEXT) " + textMessage; } else { message += " (NUM) " + numMessage; message += " (DATA) "; foreach (byte msgByte in rawBytes) { message += msgByte.ToString("x2") + " "; } } } else { message += " (BEEP)"; } Log.AddMessage(message); Address = 0; } MessageBits.Clear(); }
public void WriteRawBurst(bool[] burstBits) { bool dummyBurst = false; bool skippable = true; BurstCount++; lock (this) { /* if there is no file opened, return */ if (DumpFile == null || Parameters.State != eGSMState.Lock) { return; } long deltaSlots = (Parameters.FN - FN) * 8 + (Parameters.TN - TN); if (deltaSlots != 1) { /* hmm maybe demodulator resynchronized. force an entry. */ FN = -1; TN = -1; ARFCN = -1; skippable = false; } OutputBuilder.Length = 0; OutputBuilder.Append("<b d=\""); /* convert bits to bytes for writing into output */ ByteUtil.BitsToBytes(burstBits, BurstBufferD, 8, 0, 148); dummyBurst = BurstBufferD.SequenceEqual(DummyData); /* dummy bursts are skipped */ if (!dummyBurst) { skippable = false; for (int pos = 0; pos < BurstBufferD.Length; pos++) { OutputBuilder.AppendFormat("{0:X02}", BurstBufferD[pos]); } } OutputBuilder.Append("\""); /* output ARFCN if it has changed */ if (!StripOutput || (ARFCN != Parameters.ARFCN)) { skippable = false; OutputBuilder.AppendFormat(" a=\"{0}\"", Parameters.ARFCN); } /* * output FN if a) it has changed and b) it is not an obvious FN change due to TN overflow. * c) also output FN every 10 frames for better debug-ability. */ bool updatedFN = (FN != Parameters.FN); bool obviousFNchange = ((FN + 1) == Parameters.FN) && (TN > Parameters.TN); bool cyclicFNOutput = (((Parameters.FN % 10) == 0) && Parameters.TN == 0); if (!StripOutput || (updatedFN && (!obviousFNchange || cyclicFNOutput))) { skippable = false; OutputBuilder.AppendFormat(" f=\"{0}\"", Parameters.FN); } else if (SkippedBursts > 7) { /* in case there were skipped more than 7 bursts, append FN on the next bursts. (will not happen due to TN=0 check below) */ OutputBuilder.AppendFormat(" f=\"{0}\"", Parameters.FN); } /* output TN if is not a simple increase. we will output TN=0 always */ if (!StripOutput || ((TN + 1) != Parameters.TN)) { skippable = false; OutputBuilder.AppendFormat(" t=\"{0}\"", Parameters.TN); } else if (SkippedBursts > 0) { /* if there were bursts skipped previously, append TN */ OutputBuilder.AppendFormat(" t=\"{0}\"", Parameters.TN); } /* remember the last burst parameters */ ARFCN = Parameters.ARFCN; FN = Parameters.FN; TN = Parameters.TN; if (!StripOutput || !skippable) { /* only write time tag if the burst isnt skipped */ DateTime now = DateTime.Now; bool updatedTime = ((now - LastTaggedTime).TotalSeconds > TimeTagEvery); if (updatedTime) { LastTaggedTime = now; OutputBuilder.AppendFormat(" time=\"{0}\"", LastTaggedTime.ToString()); } OutputBuilder.Append("/>"); BurstEntries++; SkippedBursts = 0; DumpFile.WriteLine(OutputBuilder); } else { SkippedBursts++; } } }
public override eSuccessState ParseData(GSMParameters param, bool[] decodedBurst, int sequence) { eSuccessState success = eSuccessState.Unknown; if (IsDummy(decodedBurst)) { State = eBurstState.Idle; DummyBursts++; //CloseFiles(); /* don't treat TCHs as a reliable source for end-of-connection detection */ //DummyBurstReceived(param); if (DumpRawData) { StatusMessage = "Dummy Burst"; } return(eSuccessState.Succeeded); } EncryptionType = AssociatedSACCH.EncryptionType; ChannelEncrypted = AssociatedSACCH.ChannelEncrypted; StoreBurstContext(param, decodedBurst, TCHSeq); /* GSM 05.03 Ch 2.1 */ /* when we got 8 TCH bursts */ if (++TCHSeq == 8) { TCHSeq = 0; /* try to decrypt buffer if this is enabled, but do not try to crack the key */ if (!HandleEncryption(param, false)) { State = eBurstState.CryptedTraffic; /* encrypted but no decryptor available, silently return */ return(eSuccessState.Unknown); } /* deinterleave the 8 TCH bursts. the result is a 456 bit block. i[] to c[] */ Deinterleave(); /* * GSM-05.03 4.2.5 * was this burst stolen for a FACCH? hl(B) (in e[]) is set for the last 4 bursts */ if (IsHL(decodedBurst)) { /* pass encryption information to FACCH */ FACCH.A5Algorithm = A5Algorithm; FACCH.A5CipherKey = A5CipherKey; FACCH.ChannelEncrypted = ChannelEncrypted; /* pass c[] to FACCH handler */ success = FACCH.ParseFACCHData(param, BurstBufferC); StatusMessage = FACCH.StatusMessage; ErrorMessage = FACCH.ErrorMessage; FACCH.StatusMessage = null; FACCH.ErrorMessage = null; } else { /* TCH speech/data (data not supported yet) */ /* split up the class 1... */ Array.Copy(BurstBufferC, Class1DataConv, Class1DataConv.Length); /* ... and class 2 bits */ Array.Copy(BurstBufferC, 378, GSMFrameBufferD, 182, 78); /* use an own convolutional coder buffer for these 188 bits */ if (ConvolutionalCoder.Decode(Class1DataConv, ref Class1Data) == 0) { bool[] parityBits = new bool[53]; for (int pos = 0; pos < 91; pos++) { GSMFrameBufferD[2 * pos] = Class1Data[pos]; GSMFrameBufferD[2 * pos + 1] = Class1Data[184 - pos]; } /* calculate parity */ Array.Copy(GSMFrameBufferD, 0, parityBits, 0, 50); Array.Copy(Class1Data, 91, parityBits, 50, 3); bool[] crc = CRC.Calc(parityBits, 0, 53, CRC.PolynomialTCHFR); if (CRC.Matches(crc)) { DataBursts++; success = eSuccessState.Succeeded; if (ChannelEncrypted) { State = eBurstState.DecryptedTraffic; } else { State = eBurstState.PlainTraffic; } #if false #region Microsoft WAV49 GSM Format if (WAV49First) { BitMapping.Unmap(GSMFrameBufferD, 0, WAV49FrameBool, 0, BitMapping.g610BitOrder); } else { /* directly unmap into boolean WAV49 frame buffer */ BitMapping.Unmap(GSMFrameBufferD, 0, WAV49FrameBool, 260, BitMapping.g610BitOrder); /* convert that WAV49 frame to byte[] */ ByteUtil.BitsToBytes(WAV49FrameBool, WAV49FrameByte); try { if (OutFile == null) { string name = ("GSM_" + Name + "_" + param.FN + ".wav").Replace("/", "_"); OutFile = new FileStream(name, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); WriteHeader(OutFile); } /* and write it */ WriteBuffer(OutFile, WAV49FrameByte); WriteHeader(OutFile); StatusMessage = "GSM 06.10 Voice data (" + OutFile.Name + ")"; } catch (Exception e) { StatusMessage = "GSM 06.10 Voice data (Writing file failed, " + e.GetType() + ")"; } } WAV49First = !WAV49First; #endregion #endif if (ChannelMode != 33) { #region write audio dump in RTP A/V Format /* GSM frame magic */ RTPFrameBool[0] = true; RTPFrameBool[1] = true; RTPFrameBool[2] = false; RTPFrameBool[3] = true; /* directly unmap into boolean RTP frame buffer */ BitMapping.Unmap(GSMFrameBufferD, 0, RTPFrameBool, 4, BitMapping.g610BitOrder); /* convert that RTP frame to byte[] */ ByteUtil.BitsToBytes(RTPFrameBool, RTPFrameByte); StatusMessage = ""; if (ChannelEncrypted) { StatusMessage += "======= encrypted =======" + Environment.NewLine; } try { if (OutFile == null) { string name = ("GSM_" + Name + "_" + param.FN).Replace("/", "_"); OutFile = new FileStream(name + ".gsm", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); //OutFileRaw = new FileStream(name + ".raw", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); StatusMessage += "Created file: '" + name + "'" + Environment.NewLine; } /* and write it */ OutFile.Write(RTPFrameByte, 0, RTPFrameByte.Length); OutFile.Flush(); /* * Array.Copy(GSMFrameBufferD, 0, RTPFrameBool, 4, GSMFrameBufferD.Length); * RTPFrameBool[0] = false; * RTPFrameBool[1] = false; * RTPFrameBool[2] = false; * RTPFrameBool[3] = false; * ByteUtil.BitsToBytes(RTPFrameBool, RTPFrameByte); * OutFileRaw.Write(RTPFrameByte, 0, RTPFrameByte.Length); */ StatusMessage += "GSM 06.10 Voice data (" + OutFile.Name + ")"; } catch (Exception e) { StatusMessage += "GSM 06.10 Voice data (Writing file failed, " + e.GetType() + ")"; } #endregion } else { #region write audio dump in AMR Format (assume 12.2kbit/s) UnmapDToW(); UnmapWToS(); /* convert that AMR frame to byte[] */ ByteUtil.BitsToBytes(BurstBufferSpeechBits, RTPFrameByte); StatusMessage = ""; if (ChannelEncrypted) { StatusMessage += "======= encrypted =======" + Environment.NewLine; } try { if (OutFile == null) { byte[] fileHeader = new byte[] { 0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A }; string name = ("GSM_" + Name + "_" + param.FN).Replace("/", "_"); OutFile = new FileStream(name + ".amr", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); OutFile.Write(fileHeader, 0, fileHeader.Length); } /* and write it */ OutFile.WriteByte(0x3C); OutFile.Write(RTPFrameByte, 0, 31); OutFile.Flush(); StatusMessage += "GSM 06.90 Voice data (" + OutFile.Name + ")"; } catch (Exception e) { StatusMessage += "GSM 06.90 Voice data (Writing file failed, " + e.GetType() + ")"; } #endregion } } else { State = eBurstState.Failed; CryptedFrames++; ErrorMessage = "(TCH/F Class Ia: CRC Error)"; } } else { State = eBurstState.Failed; CryptedFrames++; ErrorMessage = "(TCH/F Class I: Error in ConvolutionalCoder)"; } } /* trick: * first use the last 8 bursts until one block was successfully decoded. * then use the last 4 bursts as we normally would do. * this will help in finding the correct alignment within the 4 frames. */ if (success == eSuccessState.Succeeded) { BurstShiftCount = 4; } else { BurstShiftCount = 7; } /* save the last n bursts for the next block */ for (int pos = 0; pos < BurstShiftCount; pos++) { BurstData src = BurstBlock[(8 - BurstShiftCount) + pos]; BurstData dst = BurstBlock[pos]; dst.FN = src.FN; dst.Count = src.Count; Array.Copy(src.BurstBufferI, 0, dst.BurstBufferI, 0, dst.BurstBufferI.Length); Array.Copy(src.BurstBufferE, 0, dst.BurstBufferE, 0, dst.BurstBufferE.Length); } /* and continue at position n (so we will read another 8-n bursts) */ TCHSeq = BurstShiftCount; /* only when in sync, return error flag */ if (BurstShiftCount == 4) { return(success); } } return(eSuccessState.Unknown); }