/// <summary> /// Ensure that registered delegates receive the FrameAvailable event. /// </summary> /// <param name="e">Event argument.</param> private void OnFrameAvailable(ModeSFrameAvailableEventArgs e) { // If there are subscriber(s), raises event. ModeSFrameAvailable?.Invoke(this, e); }
/// <summary> /// Process the data. Will be invoked after preamble validation. /// </summary> private void ProcessSample() { // Reset the frame buffer. Array.Clear(_frameBuffer, 0, _frameBuffer.Length); // Set the initial helper variables. var frameBitLength = 0; var lastMagnitude = 0f; var lastAverageMagnitude = 0f; // Get the actual pointer and skips the preamble. var pointer = (_candidateFramePointer + PreambleBitLength) % _candidateFrameBuffer.Length; // Go through on the candidate frame, and creates a final one. for (var i = 0; i < LongFrameBitLength * 2; i++) { // Get the magnitude from the action pointer and steps forward. var magnitude = (float)_candidateFrameBuffer[pointer]; pointer = (pointer + 1) % _candidateFrameBuffer.Length; // If the bit is even, does other tasks. if (i % 2 != 0) { // Calculate the new average of magnitude. var averageMagnitude = (magnitude + lastMagnitude) * 0.5f; // Apply correction, if the last average is higher than 0. if (lastAverageMagnitude > 0f) { // Calculate correction. var correction = -CorrectionFactor * (averageMagnitude - lastAverageMagnitude) / averageMagnitude; // If the correction is higher than 0, apply correction on the magnitude value, // and calculate the new average. if (correction > 0) { magnitude += correction; averageMagnitude = (magnitude + lastMagnitude) * 0.5f; } } // Save the average as "previous" for further usage. lastAverageMagnitude = averageMagnitude; // Decide about the value of the bit based on the magnitude. var bit = lastMagnitude > magnitude ? 1 : 0; // Get bit position from sample position. var frameBitPosition = i / 2; // Store the bit, if the bit's value is 1, // Remark: previously the frame buffer was filled with zeros. if (bit == 1) { var index = frameBitPosition / 8; var shift = 7 - (frameBitPosition % 8); _frameBuffer[index] += (byte)(1 << shift); } // Decide about the downlink format (DF), if the frame's bit position is 7. if (frameBitPosition == 7) { // Return, if the first byte is zero (the frame is not valid). if (_frameBuffer[0] == 0) { return; } // Get the downlink format of the frame. var df = ModeSHelper.GetDownlinkFormat(_frameBuffer); // Assign the good length to the frame. switch (df) { // Short DFs. case ModeSDownlinkFormats.DF0: case ModeSDownlinkFormats.DF4: case ModeSDownlinkFormats.DF5: case ModeSDownlinkFormats.DF11: frameBitLength = ShortFrameBitLength; break; // Long DFs. case ModeSDownlinkFormats.DF16: case ModeSDownlinkFormats.DF17: case ModeSDownlinkFormats.DF18: case ModeSDownlinkFormats.DF20: case ModeSDownlinkFormats.DF21: case ModeSDownlinkFormats.DF24: frameBitLength = LongFrameBitLength; break; // Any other number is not valid. default: return; } } // Approach the final bit of the frame. if (frameBitLength > 0 && frameBitPosition == frameBitLength - 1) { // Get length of the frame in byte. var frameByteLength = frameBitLength / 8; // If the last three bits are 0, the frame is not valid. if (_frameBuffer[frameByteLength - 1] == 0 && _frameBuffer[frameByteLength - 2] == 0 && _frameBuffer[frameByteLength - 3] == 0) { return; } // Create the final frame buffer with valid length. var finalFrameBuffer = _frameBuffer.Take(frameByteLength).ToArray(); // Local variable to store ICAO of the frame. uint icao; // Check the parity. var df = ModeSHelper.GetDownlinkFormat(finalFrameBuffer); switch (df) { // Check the frames which have Parity/Interrogator. case ModeSDownlinkFormats.DF11: case ModeSDownlinkFormats.DF17: case ModeSDownlinkFormats.DF18: // The syndrome must be zero, this means that the frame is valid. if (ModeSParity.Syndrome(finalFrameBuffer) != 0) { return; } // Get the ICAO from the frame. icao = ModeSHelper.GetICAOAddress(finalFrameBuffer); // Break. break; // Check the frames which have Address/Parity. case ModeSDownlinkFormats.DF0: case ModeSDownlinkFormats.DF4: case ModeSDownlinkFormats.DF5: case ModeSDownlinkFormats.DF16: case ModeSDownlinkFormats.DF20: case ModeSDownlinkFormats.DF21: case ModeSDownlinkFormats.DF24: // Get the ICAO from the Address/Parity. icao = ModeSHelper.GetICAOAddress(finalFrameBuffer); // If this ICAO is in the trusted list, we assume that the frame is valid. if (!_trustedICAOList.ContainsKey(icao)) { return; } // Break. break; // Invalid DF. default: return; } // Return, if the the ICAO is not trusted and the candidate's confidence is not enough. if (!_trustedICAOList.ContainsKey(icao) && !GetCandidateICAOConfidence(icao)) { UpdateCandidateICAOList(icao); return; } // Update trusted ICAOs "last seen" value and remove the ICAO from the candidate list. _trustedICAOList[icao] = DateTime.UtcNow; _candidateICAOList.TryRemove(icao, out _); // Raise the ModeSFrameAvailable event. var args = new ModeSFrameAvailableEventArgs( new ModeSRawFrame(finalFrameBuffer, icao, df)); OnFrameAvailable(args); // Return. return; } } // Save the current magnitude as "previous" for the future. lastMagnitude = magnitude; } }