/// <summary> /// Copies values from another instance. /// </summary> /// <param name="source">Source from which to copy values.</param> public void Copy(PpmCycle source) { LowTime = source.LowTime; LowLength = source.LowLength; HighTime = source.HighTime; HighLength = source.HighLength; }
/// <summary> /// Runs the decoder thread. /// </summary> /// <param name="inputBuffer">Buffer from which new PPM values are read.</param> /// <param name="inputTrigger">Trigger which is fired by the caller when new data arrives.</param> /// <param name="outputBuffer">Buffer into which decoded PPM frames are written.</param> /// <param name="outputTrigger">Trigger which is fired by this decoder when new data has been decoded.</param> /// <param name="stop">Signals when the decoder should stop.</param> public void DecodePulse(ConcurrentQueue <PpmPulse> inputBuffer, AutoResetEvent inputTrigger, ConcurrentQueue <PpmFrame> outputBuffer, AutoResetEvent outputTrigger, CancellationToken stop) { // Validate if (inputBuffer == null) { throw new ArgumentNullException(nameof(inputBuffer)); } if (inputTrigger == null) { throw new ArgumentNullException(nameof(inputTrigger)); } if (outputBuffer == null) { throw new ArgumentNullException(nameof(outputBuffer)); } if (outputTrigger == null) { throw new ArgumentNullException(nameof(outputTrigger)); } // Decode until stopped... while (!stop.IsCancellationRequested) { // Wait for value in queue... if (!inputBuffer.TryDequeue(out PpmPulse value)) { inputTrigger.WaitOne(SyncLengthMinimum * 2); continue; } // Decode values into cycles... var time = value.Time; if (value.Level) { // Low -> high (mid-cycle) _cycle.HighTime = time; _cycle.LowLength = time - _cycle.LowTime; } else { // High -> low (end of cycle) _cycle.HighLength = time - _cycle.HighTime; // Prepare next value var cycle = _cycle; _cycle = new PpmCycle(time); // Decode cycles into frames... var frame = DecodeCycle(cycle); if (frame != null) { // Output frame when decoding complete outputBuffer.Enqueue(frame); outputTrigger.Set(); } } } }
/// <summary> /// Decodes the incoming PPM signal (each complete cycle) using the CPPM protocol. /// </summary> /// <param name="cycle">PPM cycle to decode.</param> /// <returns> /// <see cref="PpmFrame"/> when complete else null whilst decoding or skipping invalid cycles. /// </returns> private PpmFrame DecodeCycle(PpmCycle cycle) { // Validate if (!cycle.IsValid() || cycle.LowLength >= LowLimit) { // Discard frame _channel = null; return(null); } // Detect start frame if (cycle.HighLength >= SyncLengthMinimum) { // Start decoding from channel 0 at next pulse _channel = 0; _frame = new PpmFrame(cycle.LowTime, new int[ChannelCount]); return(null); } // Do nothing when not decoding if (!_channel.HasValue) { return(null); } var decodeIndex = _channel.Value; // Store channel value whilst decoding if (decodeIndex < ChannelCount) { // Store channel value _frame.Channels[decodeIndex] = (int)cycle.Length; // Wait for next channel... _channel = decodeIndex + 1; // Complete frame when all channels decoded... if (decodeIndex == ChannelCount - 1) { var frame = _frame; _frame = null; return(frame); } } // Continue... return(null); }
/// <summary> /// Creates an instance. /// </summary> public CppmDecoder() { _frame = new PpmFrame(); _cycle = new PpmCycle(); }