public unsafe void ExtractSBChannels(Burst burst, byte *sb1Buffer) { var offset = 2; offset += nts3_pre_Length + phaseAdjust_Length + freqCorrection_Length; BlockCopy(burst.Ptr, offset, sb1Buffer, 0, sb_Length); }
public unsafe Burst ParseTrainingSequence(float *inBuffer, int length) { Burst burst = new Burst() { Type = BurstType.None, Length = BurstLength, Ptr = this._outBufferPtr }; this.ConvertAngleToDiBits(burst.Ptr, inBuffer, length); return(burst); }
public int Process(Burst burst, float *audioOut) { var trafficChannel = 0; BurstReceived = (burst.Type != BurstType.None); _timeCounter++; Ber = _averageBer; if (_timeCounter > 100) { Mer = (_badBurstCounter / _timeCounter) * 100.0f; _timeCounter = 0; _badBurstCounter = 0; } _networkTime.AddTimeSlot(); if (burst.Type == BurstType.None) { _haveErrors = true; if (TetraMode == Mode.TMO) { _badBurstCounter++; //Debug.WriteLine("burst err"); //Debug.Write(string.Format("ts:{0:0} fr:{1:00} Burst_Err", _networkTime.TimeSlot, _networkTime.Frame)); } return(trafficChannel); } _haveErrors = false; //Debug.WriteLine(""); //Debug.Write(string.Format("ts:{0:0} fr:{1:00}", _networkTime.TimeSlot, _networkTime.Frame)); //Debug.Write(" " + burst.Type.ToString()); _parse.ResetAACH(); _data.Clear(); _syncInfo.Clear(); #region Sync burst if (burst.Type == BurstType.SYNC) { _phyLevel.ExtractSBChannels(burst, _sb1BufferPtr); _logicChannel = _lowerMac.ExtractLogicChannelFromSB(_sb1BufferPtr, _sb1Buffer.Length); _badBurstCounter += _logicChannel.CrcIsOk ? 0.0f : 0.5f; _haveErrors |= !_logicChannel.CrcIsOk; _averageBer = _averageBer * 0.5f + _lowerMac.Ber * 0.5f; //Debug.Write(" slot 1:" + (_logicChannel.CrcIsOk ? " OK" : " Err")); if (_logicChannel.CrcIsOk) { _parse.SyncPDU(_logicChannel, _syncInfo); if (_syncInfo.Value(GlobalNames.SystemCode) < 8) { TetraMode = Mode.TMO; _lowerMac.ScramblerCode = TetraUtils.CreateScramblerCode(_syncInfo.Value(GlobalNames.MCC), _syncInfo.Value(GlobalNames.MNC), _syncInfo.Value(GlobalNames.ColorCode)); _networkTime.Synchronize(_syncInfo.Value(GlobalNames.TimeSlot), _syncInfo.Value(GlobalNames.Frame), _syncInfo.Value(GlobalNames.MultiFrame)); } else { TetraMode = Mode.DMO; if (_syncInfo.Value(GlobalNames.SYNC_PDU_type) == 0) { //Debug.Write(_syncInfo.Value(GlobalNames.Master_slave_link_flag) == 1 ? " Master" : " Slave"); if (_syncInfo.Value(GlobalNames.Master_slave_link_flag) == 1 || _syncInfo.Value(GlobalNames.Communication_type) == 0) { _networkTime.SynchronizeMaster(_syncInfo.Value(GlobalNames.TimeSlot), _syncInfo.Value(GlobalNames.Frame)); } else { _networkTime.SynchronizeSlave(_syncInfo.Value(GlobalNames.TimeSlot), _syncInfo.Value(GlobalNames.Frame)); } } } } else { //Debug.WriteLine("Sync SB crc error"); } _phyLevel.ExtractPhyChannels(TetraMode, burst, _bbBufferPtr, _bkn1BufferPtr, _bkn2BufferPtr); if (TetraMode == Mode.TMO) { _logicChannel = _lowerMac.ExtractLogicChannelFromBKN(_bkn2BufferPtr, _bkn2Buffer.Length); _logicChannel.TimeSlot = _networkTime.TimeSlot; _logicChannel.Frame = _networkTime.Frame; _badBurstCounter += _logicChannel.CrcIsOk ? 0.0f : 0.5f; _haveErrors |= !_logicChannel.CrcIsOk; _averageBer = _averageBer * 0.5f + _lowerMac.Ber * 0.5f; //Debug.Write(" slot 2:" + (_logicChannel.CrcIsOk ? " OK" : " Err")); if (_logicChannel.CrcIsOk) { _parse.TmoParseMacPDU(_logicChannel, _data); } else { //Debug.WriteLine("Sync BKN2 crc error"); } } else { _logicChannel = _lowerMac.ExtractLogicChannelFromBKN2(_bkn2BufferPtr, _bkn2Buffer.Length); _logicChannel.TimeSlot = _networkTime.TimeSlot; _logicChannel.Frame = _networkTime.Frame; _badBurstCounter += _logicChannel.CrcIsOk ? 0.0f : 0.5f; _haveErrors |= !_logicChannel.CrcIsOk; _averageBer = _averageBer * 0.5f + _lowerMac.Ber * 0.5f; //Debug.Write(" slot 2:" + (_logicChannel.CrcIsOk ? " OK" : " Err")); if (_logicChannel.CrcIsOk) { _parse.SyncPDUHalfSlot(_logicChannel, _syncInfo); if (_syncInfo.Value(GlobalNames.Communication_type) == 0) { if (_syncInfo.Contains(GlobalNames.MNC) && _syncInfo.Contains(GlobalNames.Source_address)) { _lowerMac.ScramblerCode = TetraUtils.CreateScramblerCode(_syncInfo.Value(GlobalNames.MNC), _syncInfo.Value(GlobalNames.Source_address)); } } else if (_syncInfo.Value(GlobalNames.Communication_type) == 1) { if (_syncInfo.Contains(GlobalNames.Repeater_address) && _syncInfo.Contains(GlobalNames.Source_address)) { _lowerMac.ScramblerCode = TetraUtils.CreateScramblerCode(_syncInfo.Value(GlobalNames.Repeater_address), _syncInfo.Value(GlobalNames.Source_address)); } } } } UpdateSyncInfo(_syncInfo); } #endregion UpdatePublicProp(); #region Other burst if (burst.Type != BurstType.SYNC) { _phyLevel.ExtractPhyChannels(TetraMode, burst, _bbBufferPtr, _bkn1BufferPtr, _bkn2BufferPtr); if (TetraMode == Mode.TMO) { _logicChannel = _lowerMac.ExtractLogicChannelFromBB(_bbBufferPtr, _bbBuffer.Length); _logicChannel.TimeSlot = _networkTime.TimeSlot; _logicChannel.Frame = _networkTime.Frame; _badBurstCounter += _logicChannel.CrcIsOk ? 0.0f : 0.2f; _haveErrors |= !_logicChannel.CrcIsOk; //Debug.Write(_logicChannel.CrcIsOk ? " BB OK" : " BB Err"); if (_logicChannel.CrcIsOk) { _parse.AccessAsignPDU(_logicChannel); } else { //Debug.WriteLine("BB crc error"); } } switch (burst.Type) { case BurstType.NDB1: if (((TetraMode == Mode.TMO) && (_parse.DownLinkChannelType == ChannelType.Traffic)) || ((TetraMode == Mode.DMO) && (!_networkTime.Frame18) && (_networkTime.TimeSlot == 1)) || ((TetraMode == Mode.DMO) && (!_networkTime.Frame18Slave) && (_networkTime.TimeSlotSlave == 1))) { //Debug.Write(" slot 12:voice"); _logicChannel = _lowerMac.ExtractVoiceDataFromBKN1BKN2(_bkn1BufferPtr, _bkn2BufferPtr, _bkn1Buffer.Length); var itsAudio = DecodeAudio(audioOut, _logicChannel.Ptr, _logicChannel.Length, false, _networkTime.TimeSlot); trafficChannel = itsAudio ? _networkTime.TimeSlot : 0; break; } else { _logicChannel = _lowerMac.ExtractLogicChannelFromBKN1BKN2(_bkn1BufferPtr, _bkn2BufferPtr, _bkn1Buffer.Length); _logicChannel.TimeSlot = _networkTime.TimeSlot; _logicChannel.Frame = _networkTime.Frame; _badBurstCounter += _logicChannel.CrcIsOk ? 0.0f : 0.8f; _haveErrors |= !_logicChannel.CrcIsOk; _averageBer = _averageBer * 0.5f + _lowerMac.Ber * 0.5f; //Debug.Write(" slot 12:" + (_logicChannel.CrcIsOk ? " OK" : " Err")); if (_logicChannel.CrcIsOk) { if (TetraMode == Mode.TMO) { _parse.TmoParseMacPDU(_logicChannel, _data); } else { _parse.DmoParseMacPDU(_logicChannel, _data); } } else { //Debug.WriteLine("BKN1 BKN2 crc error"); } } break; case BurstType.NDB2: _logicChannel = _lowerMac.ExtractLogicChannelFromBKN(_bkn1BufferPtr, _bkn1Buffer.Length); _logicChannel.TimeSlot = _networkTime.TimeSlot; _logicChannel.Frame = _networkTime.Frame; _badBurstCounter += _logicChannel.CrcIsOk ? 0.0f : 0.4f; _haveErrors |= !_logicChannel.CrcIsOk; _averageBer = _averageBer * 0.5f + _lowerMac.Ber * 0.5f; //Debug.Write(" slot 1:" + (_logicChannel.CrcIsOk ? " OK" : " Err")); if (_logicChannel.CrcIsOk) { if (TetraMode == Mode.TMO) { _parse.TmoParseMacPDU(_logicChannel, _data); } else { _parse.DmoParseMacPDU(_logicChannel, _data); } } else { //Debug.WriteLine("BKN1 crc error"); } if ((_parse.DownLinkChannelType == ChannelType.Traffic && !_parse.HalfSlotStolen) || ((TetraMode == Mode.DMO) && (!_networkTime.Frame18) && (_networkTime.TimeSlot == 1) && (!_parse.HalfSlotStolen)) || ((TetraMode == Mode.DMO) && (!_networkTime.Frame18Slave) && (_networkTime.TimeSlotSlave == 1) && (!_parse.HalfSlotStolen))) { //Debug.Write(" slot 2:voice"); _logicChannel = _lowerMac.ExtractVoiceDataFromBKN2(_bkn2BufferPtr, _bkn2Buffer.Length); var itsAudio = DecodeAudio(audioOut, _logicChannel.Ptr, _logicChannel.Length, true, _networkTime.TimeSlot); trafficChannel = itsAudio ? _networkTime.TimeSlot : 0; break; } else { _logicChannel = _lowerMac.ExtractLogicChannelFromBKN(_bkn2BufferPtr, _bkn2Buffer.Length); _logicChannel.TimeSlot = _networkTime.TimeSlot; _logicChannel.Frame = _networkTime.Frame; _badBurstCounter += _logicChannel.CrcIsOk ? 0.0f : 0.4f; _haveErrors |= !_logicChannel.CrcIsOk; _averageBer = _averageBer * 0.5f + _lowerMac.Ber * 0.5f; //Debug.Write(" slot 2:" + (_logicChannel.CrcIsOk ? " OK" : " Err")); if (_logicChannel.CrcIsOk) { if (TetraMode == Mode.TMO) { _parse.TmoParseMacPDU(_logicChannel, _data); } else { _parse.DmoParseMacPDU(_logicChannel, _data); } } else { //Debug.WriteLine("BKN2 crc error"); } } break; default: break; } } if (_data.Count > 0) { UpdateData(_data); } #endregion return(trafficChannel); }
public unsafe void ProcessBuffer( Burst burst, Complex *iqBuffer, double iqSamplerate, int iqBufferLength, float *digitalBuffer) { burst.Type = BurstType.WaitBurst; burst.Length = 0; if (this._buffer == null || iqSamplerate != this._samplerateIn) { this._samplerateIn = iqSamplerate; this._samplerate = this._samplerateIn; this._interpolation = 1; while (this._samplerateIn * (double)this._interpolation < 90000.0) { ++this._interpolation; } this._samplerate = this._samplerateIn * (double)this._interpolation; this._length = iqBufferLength * this._interpolation; this._symbolLength = this._samplerate / 18000.0; this._windowLength = (int)Math.Round(this._symbolLength * (double)byte.MaxValue); this._writeAddress = 0; this._tailBufferLength = (int)Math.Round(this._symbolLength); this._syncCounter = 0; this._buffer = UnsafeBuffer.Create(this._length + this._tailBufferLength, sizeof(Complex)); this._bufferPtr = (Complex *)(void *)this._buffer; this._tempBuffer = UnsafeBuffer.Create((int)this._samplerate, 4); this._tempBufferPtr = (float *)(void *)this._tempBuffer; this._filterLength = Math.Max((int)(this._samplerate / 18000.0) | 1, 5); float[] coefficients = FilterBuilder.MakeSinc(this._samplerate, 13500.0, this._filterLength); this._matchedFilter = new IQFirFilter(coefficients); this._fsFilter = new FirFilter(coefficients); this.CreateFrameSynchronization(); } if (this._interpolation > 1) { int num = 0; Complex complex = new Complex(0.0f, 0.0f); for (int index = 0; index < this._length; ++index) { this._bufferPtr[index + this._tailBufferLength] = index % this._interpolation == 0 ? iqBuffer[num++] : complex; } } else { Radio.Utils.Memcpy((void *)(this._bufferPtr + this._tailBufferLength), (void *)iqBuffer, this._length * sizeof(Complex)); } this._matchedFilter.Process(this._bufferPtr + this._tailBufferLength, this._length); if (this._writeAddress + this._length < this._tempBuffer.Length) { for (int index = 0; index < this._length; ++index) { this._tempBufferPtr[this._writeAddress] = (this._bufferPtr[index + this._tailBufferLength] * this._bufferPtr[index].Conjugate()).ArgumentFast(); ++this._writeAddress; } } for (int index = 0; index < this._tailBufferLength; ++index) { this._bufferPtr[index] = this._bufferPtr[this._length + index]; } if (this._writeAddress < this._windowLength * 2) { return; } this._ntsOffset = burst.Mode == Mode.TMO ? (int)Math.Round(122.0 * this._symbolLength) : (int)Math.Round(115.0 * this._symbolLength); this._stsOffset = (int)Math.Round(107.0 * this._symbolLength); this._ndb1minSum = float.MaxValue; this._ndb1Index = 0; this._ndb2minSum = float.MaxValue; this._ndb2Index = 0; this._stsMinSum = float.MaxValue; this._stsIndex = 0; this._trainingWindow = this._syncCounter > 0 ? 6 * this._tailBufferLength : this._windowLength; if (this._syncCounter > 0) { --this._syncCounter; } for (int index1 = 0; index1 < this._trainingWindow; ++index1) { this._ndb1sum = 0.0f; this._ndb2sum = 0.0f; this._stsSum = 0.0f; for (int index2 = 0; index2 < this._nts1Buffer.Length; ++index2) { this._sample = this._tempBufferPtr[index1 + index2 + this._ntsOffset]; this._training = this._nts1BufferPtr[index2]; this._ndb1sum += (float)(((double)this._training - (double)this._sample) * ((double)this._training - (double)this._sample)); } if ((double)this._ndb1sum < (double)this._ndb1minSum) { this._ndb1minSum = this._ndb1sum; this._ndb1Index = index1; } for (int index2 = 0; index2 < this._nts2Buffer.Length; ++index2) { this._sample = this._tempBufferPtr[index1 + index2 + this._ntsOffset]; this._training = this._nts2BufferPtr[index2]; this._ndb2sum += (float)(((double)this._training - (double)this._sample) * ((double)this._training - (double)this._sample)); } if ((double)this._ndb2sum < (double)this._ndb2minSum) { this._ndb2minSum = this._ndb2sum; this._ndb2Index = index1; } for (int index2 = 0; index2 < this._stsBuffer.Length; ++index2) { this._sample = this._tempBufferPtr[index1 + index2 + this._stsOffset]; this._training = this._stsBufferPtr[index2]; this._stsSum += (float)(((double)this._training - (double)this._sample) * ((double)this._training - (double)this._sample)); } if ((double)this._stsSum < (double)this._stsMinSum) { this._stsMinSum = this._stsSum; this._stsIndex = index1; } } this._ndb1minSum /= (float)this._nts1Buffer.Length; this._ndb2minSum /= (float)this._nts2Buffer.Length; this._stsMinSum /= (float)this._stsBuffer.Length; if ((double)this._ndb1minSum < 1.0 || (double)this._ndb2minSum < 1.0 || (double)this._stsMinSum < 1.0) { if ((double)this._ndb1minSum < (double)this._ndb2minSum && (double)this._ndb1minSum < (double)this._stsMinSum) { this._offset = this._ndb1Index; burst.Type = BurstType.NDB1; } else if ((double)this._ndb2minSum < (double)this._ndb1minSum && (double)this._ndb2minSum < (double)this._stsMinSum) { this._offset = this._ndb2Index; burst.Type = BurstType.NDB2; } else { this._offset = this._stsIndex; burst.Type = BurstType.SYNC; } this._syncCounter = 8; } else { burst.Type = BurstType.None; this._offset = this._tailBufferLength * 2; } int index3 = 0; int num1 = 0; for (; index3 < 256; ++index3) { num1 = (int)Math.Round((double)index3 * this._symbolLength); digitalBuffer[index3] = this._tempBufferPtr[this._offset + num1]; } this._offset += num1; this._offset -= this._tailBufferLength * 2; if (this._offset < 0) { this._offset = 0; } this._writeAddress -= this._offset; if (this._writeAddress < 0) { this._writeAddress = 0; } Radio.Utils.Memcpy((void *)this._tempBufferPtr, (void *)(this._tempBufferPtr + this._offset), this._writeAddress * 4); this.AngleToSymbol(burst.Ptr, digitalBuffer, (int)byte.MaxValue); burst.Length = 510; }
public unsafe void ExtractPhyChannels( Mode mode, Burst burst, byte *bbBuffer, byte *bkn1Buffer, byte *bkn2Buffer) { int offset = 2; switch (mode) { case Mode.TMO: switch (burst.Type) { case BurstType.NDB1: case BurstType.NDB2: offset += nts3_pre_Length + phaseAdjust_Length; BlockCopy(burst.Ptr, offset, bkn1Buffer, 0, bkn_Length); offset += bkn_Length; BlockCopy(burst.Ptr, offset, bbBuffer, 0, bb1_Length); offset += bb1_Length + nts_Length; BlockCopy(burst.Ptr, offset, bbBuffer, bb1_Length, bb2_Length); offset += bb2_Length; BlockCopy(burst.Ptr, offset, bkn2Buffer, 0, bkn_Length); break; case BurstType.SYNC: offset += nts3_pre_Length + phaseAdjust_Length + freqCorrection_Length; offset += sts_Length + sb_Length; BlockCopy(burst.Ptr, offset, bbBuffer, 0, bb_Length); offset += bb_Length; BlockCopy(burst.Ptr, offset, bkn2Buffer, 0, bkn_Length); break; default: break; } break; case Mode.DMO: switch (burst.Type) { case BurstType.NDB1: case BurstType.NDB2: offset += nts3_pre_Length + phaseAdjust_Length; BlockCopy(burst.Ptr, offset, bkn1Buffer, 0, bkn_Length); offset += bkn_Length; offset += nts_Length; BlockCopy(burst.Ptr, offset, bkn2Buffer, 0, bkn_Length); break; case BurstType.SYNC: offset += nts3_pre_Length + phaseAdjust_Length + freqCorrection_Length; offset += sb_Length; offset += sts_Length; BlockCopy(burst.Ptr, offset, bkn2Buffer, 0, bkn_Length); break; default: break; } break; } }