15.1 How to use TraceBufferLib to retrieve TraceEvents from the Card |
By using the TraceBufferClient API provided by SP-ICE-3 TraceBufferLib, your application can, on the Host-PC, retrieve and analyse TraceEvents captured on the SP-ICE-3 Card.
Before we can retrieve any TraceEvents at all, they must first be captured by the SP-ICE-3 Card.
The card can be configured to capture events of a particular type by enabling the appropriate trigger, specifed in a TraceBufferConfig which you pass to SetConfig or AppendTraceConfig.
After enabling a certain trigger, every occurrence of it will cause a trace event to be captured by the TraceBuffer Engine.
All such events are initially captured on the card, from whence they can be retrieved via the TraceBufferClient API.
Note |
---|
Some triggers will cause events to be captured at high rates independently of list execution.
In particular, enabling any of the Scanner Position triggers will result in a new event being captured every 10µs. Best practice in general therefore is to avoid calling Start too early in your application, and preferably not until immediately before list execution is started. |
Only a single connection via the TraceBufferClient is allowed at any one time.
Once the connection has been dropped (either explicitly, with Disconnect, or implicitly, when the client instance is disposed) the trigger configuration on the card will be automatically reset.
No further events will be captured until a new client connection is established and the triggers are re-configured.
Note that it is not necessary to re-configure the triggers between sucessive calls of Stop and Start, as long as the client remains connected.
Note also that each call of Start automatically clears any previously existing data from the capture buffers.
Since all types of event tracing can potentially produce huge volumes of data even in a short period of time, we will generally want to limit the events which we retrieve to those falling within a specific region-of-interest, especially if we are using longer CommandLists with multiple vector paths.
One way to achieve this is by first configuring the TraceBuffer Engine to capture TraceLabel events alongside any other event types we may find interesting, and then using TraceLabels within our CommandList to designate the start and end of a region-of-interest.
For instance, we might use:
Label 1 to designate the start of our region: AppendTraceLabel( 1 )
Label 2 to designate the end of it: AppendTraceLabel( 2 )
Subsequently we can retrieve just the events captured between Label 1 and Label 2 by calling tbClient.Acquire( 1, 2 ), for instance.
On the other hand, if we wish to retrieve all possible captured events regardless of volume, we can use the lower-level facilities of TraceBufferClient, such as Read or TryRead.
The following simple example demonstrates the basic steps required to configure, capture, and retrieve TraceEvents.
For this example, let's assume we are interested in the timing of the Laser Gate signal, but only during the first MARK vector of our complete path:
// **************************************************************** // Prepare a TraceBuffer Configuration. // **************************************************************** TraceBufferConfig tbConfig = new TraceBufferConfig(); tbConfig.ControlEvents.Label = true; // Capture TraceLabel events. tbConfig.IOEvents.Gate = true; // Capture Laser Gate signal events. // **************************************************************** // Assemble a Command List to be investigated using the TraceBuffer // **************************************************************** CommandList commandList = new CommandList(); commandList.AppendLmFrequency( 0.2 ); commandList.AppendLmWidth( 32.0 / 64.0 ); commandList.AppendJumpAbs( 0, 0 ); // TraceLabel(1) marks the beginning of our region-of-interest. commandList.AppendTraceLabel( 1 ); // Mark a line: this will cause the LaserModulation Events which we want to capture commandList.AppendMarkRel( 100, 100 ); // TraceLabel(2) marks the end of our region-of-interest. commandList.AppendTraceLabel( 2 ); commandList.AppendJumpAbs( 0, 0 ); // Mark another line: we are not interested in the LaserModulation Events from this one. commandList.AppendMarkRel( -100, -100 ); commandList.AppendJumpAbs( 0, 0 ); // **************************************************************** // Instantiate the ClientAPI, and connect it to the SP-ICE-3 card. // **************************************************************** using ( ClientAPI client = new ClientAPI( cardIP ) ) { // **************************************************************** // Send our command list to the card. // **************************************************************** int listID = 0; client.List.Set( listID, commandList ); // **************************************************************** // Instantiate a new TraceBufferClient and // connect it to the TraceBuffer Server on the SP-ICE-3 card. // **************************************************************** using ( TraceBufferClient tbClient = new TraceBufferClient( client.Address.ToString() ) ) { // **************************************************************** // Configure the TraceBuffer Triggers on the card. // **************************************************************** tbClient.SetConfig( tbConfig ); // **************************************************************** // Arm Laser: otherwise, no Laser Modulation signal will be output. // // DANGER! OBSERVE ALL LASER-SAFETY PRECAUTIONS! // // Ideally, there should be no laser connected to the card during this test. // // **************************************************************** // client.Laser.ArmLaser( true ); // **************************************************************** // Clear the capture buffers and start streaming events from the card. // **************************************************************** tbClient.Start(); // **************************************************************** // Execute the commandList. // **************************************************************** client.List.Execute( listID ); // **************************************************************** // Wait until list execution is finished. // **************************************************************** int? doneID = 0; client.List.WaitForListDone( out doneID ); // **************************************************************** // Perform error checking. // **************************************************************** if ( doneID != listID ) throw new Exception( "Houston? We've had a problem." ); // **************************************************************** // Dis-arm the Laser. // **************************************************************** client.Laser.ArmLaser( false ); // **************************************************************** // Retrieve just the events that were captured between Label 1 and Label 2. // (Refer to the command list definition, above). // **************************************************************** tbClient.ReadTimeout = 500; List<TraceEvent> traceEvents = tbClient.Acquire( 1, 2 ); // **************************************************************** // Correct the sign of position events from the raw data. // (Optional: only useful if you are capturing Scanner Position events.) // **************************************************************** TraceBufferClient.ToSignedPosition( traceEvents ); // **************************************************************** // Stop streaming any further events from the card. // This reduces both CPU overhead and network traffic. // **************************************************************** tbClient.Stop(); // **************************************************************** // Evaluate the retrieved events. // **************************************************************** double refTime = 0; int eventCount = 0; foreach ( TraceEvent evt in traceEvents ) { switch ( evt.EventType ) { case TraceEventType.Gate: if ( eventCount++ == 0 ) { refTime = evt.Time; } Console.WriteLine( $"{evt.Time - refTime}: Gate {( evt.Value == 1 ? "ON" : "OFF" )}" ); break; default: Console.WriteLine( $"{evt.Time - refTime}: Unexpected event type {evt.EventType}" ); break; } } } }
TBD
TBD