Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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;
        }
Пример #5
0
        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;
            }
        }