Click or drag to resize

4.2.2 Simple Custom Trigger Streaming

The C:\Program Files\RAYLASE\ProcessDataAnalyzer\API\SampleCode\SampleApplications\SimpleCustomTriggerStreaming demonstrates a simplified approach to implementing custom trigger-based trace saving. Unlike the more complex Custom Trigger Streaming example, this sample focuses on a single, specific trigger condition: detecting signal timing anomalies. It provides a clearer, more focused example of how to stream trace data and trigger trace saves programmatically.

This example is particularly useful for:

  • Understanding the basic streaming and triggering workflow

  • Detecting signal dropout or timing irregularities

  • Learning how to process frames efficiently in real-time

  • Implementing custom trigger logic with the Process Data Analyzer Client API

Simplified Trigger Architecture

The SimpleCustomTriggerStreaming example implements a streamlined architecture:

  • Uses the Process Data Analyzer Client API for streaming and acquisition control

  • Monitors signal timing between consecutive samples

  • Triggers trace saves when timing threshold is exceeded

  • Processes frames asynchronously using channels for efficiency

  • Supports multiple control cards in parallel

Configuration Structure

The application uses a JSON configuration file to define trigger parameters:

Configuration.json
{
  "Cards": [
    {
      "ConnectionId": "SP310194",
      "CardIP": "10.2.0.101",
      "deltaTus": 100.0,
      "FramesPerTrace": 50,
      "FramesAfterTrigger": 3,
      "TraceSavePath": "C:\\Traces"
    }
  ]
}

Configuration parameters:

  • ConnectionId: Serial number of the control card

  • CardIP: IP address of the control card

  • deltaTus: Maximum allowed time difference (µs) between consecutive signal samples. If exceeded, a trace save is triggered.

  • FramesPerTrace: Number of frames to capture before the trigger (pre-trigger buffer)

  • FramesAfterTrigger: Number of frames to skip after triggering to avoid multiple saves for the same event

  • TraceSavePath: Directory where trace files will be saved

Trigger Condition Logic

The example implements a simple but effective trigger condition that detects timing anomalies:

Timing Anomaly Detection
// Check X signal timing
if (hasX && lastXTimestamp.HasValue)
{
    double timeDifference = currentTimestamp - lastXTimestamp.Value;
    if (timeDifference > _cardConfiguration.deltaTus)
    {
        return true;  // Trigger condition met
    }
}

// Check Y signal timing  
if (hasY && lastYTimestamp.HasValue)
{
    double timeDifference = currentTimestamp - lastYTimestamp.Value;
    if (timeDifference > _cardConfiguration.deltaTus)
    {
        return true;  // Trigger condition met
    }
}

The condition monitors the BuiltInSignal BisField0RxX and BisField0RxY signals. If the time gap between consecutive samples of either signal exceeds the configured threshold, the trigger fires and a trace save is requested.

Streaming Architecture

The application uses a dual-task architecture for efficient processing:

  1. Streaming Task: Continuously receives frames from the Process Data Analyzer server via gRPC streaming and writes them to a channel

  2. Processing Task: Reads frames from the channel, checks trigger conditions, and calls TriggerTraceSave when conditions are met

This separation allows the streaming task to continuously receive data without blocking on condition checking, ensuring no frames are lost due to processing delays.

Dual-Task Architecture
// Streaming task - receives frames
using (var call = _api.Streaming.GetFrame(new API.GetFrameRequest() 
{ 
    DeviceId = _id,
    TimestampInTicks = false,
}))
{
    _api.Acquisition.Start(new API.AcquisitionStartRequest() { Card = _id });

    while (await call.ResponseStream.MoveNext(token))
    {
        var frame = call.ResponseStream.Current;
        _channelWriter.TryWrite(frame);  // Pass to processing task
    }
}

// Processing task - checks conditions
while (await _channelReader.WaitToReadAsync())
{
    while (_channelReader.TryRead(out var frame))
    {
        if (CheckConditions(frame))
        {
            _api.Streaming.TriggerTraceSave(new TriggerTraceSaveRequest() 
            { 
                DeviceId = _id 
            });
        }
    }
}

Program Flow

The main program follows this workflow:

  1. Load configuration from JSON file (card settings, trigger parameters)

  2. Start the Process Data Analyzer server using the Client API

  3. Load PDA configuration file and set card connection parameters

  4. Create a CardStream instance for each configured card

  5. Start streaming and processing threads for each card in parallel

  6. Wait for user input to stop the application

  7. Stop all streams and print statistics

Multi-Card Support

The application supports monitoring multiple control cards simultaneously. Each card runs in its own thread with independent streaming and processing tasks. This allows for:

  • Parallel acquisition from multiple scan heads

  • Independent trigger conditions per card

  • Separate trace save paths for each card

  • Isolated error handling per card stream

Running the Example

To run the SimpleCustomTriggerStreaming application:

  1. Create a Configuration.json file with your card settings and trigger parameters

  2. Prepare a PDA configuration file (see PDA Configuration) with the appropriate card and signal settings

  3. Run the application from the command line:

    SimpleCustomTriggerStreaming.exe "path\to\Configuration.json" "path\to\PdaConfiguration.json"
  4. Optional: Provide a custom path to ProcessDataAnalyzer.Service.exe as a third argument

  5. Monitor console output for trigger events and statistics

  6. Press any key to stop streaming and view final statistics

Comparison with Custom Trigger Streaming

This simplified example differs from the full Custom Trigger Streaming sample in several ways:

Aspect

SimpleCustomTriggerStreaming

CustomTriggerStreaming

Trigger Condition

Single: Signal timing anomaly

Multiple: Position, velocity, power, etc.

Complexity

Simplified, focused example

Full-featured, production-ready

Code Structure

3 files, ~300 lines

Multiple files, extensive configuration

Learning Curve

Easier to understand

More comprehensive but complex

Use SimpleCustomTriggerStreaming as a starting point to understand the basic concepts, then refer to CustomTriggerStreaming for advanced features and production deployment patterns.

Extending the Example

This example can be extended to implement more sophisticated trigger conditions:

  • Position-based triggering: Trigger when commanded vs. measured position difference exceeds a threshold

  • Velocity monitoring: Trigger on sudden velocity changes or overshoots

  • Power monitoring: Trigger when laser power deviates from expected values

  • Multi-signal correlation: Trigger based on relationships between multiple signals

  • Statistical analysis: Implement moving average or standard deviation checks

  • Adaptive thresholds: Adjust trigger parameters based on historical data

See Also