Click or drag to resize

4.1.3 Proto Client API Tutorial

The Proto Client API tutorial implements the same behavior as 4.1.1 Standalone API Tutorial and 4.1.2 Client API Tutorial but in a more generic way. It relies directly on the GRPC proto interface and links these dependencies instead. The API is auto generated on build and handles a bit chunkier without some convenience implementations available in the .NET versions of above tutorials.

If you prefer another non-.NET programming language, you will most likely find your language in the list of supported GRPC convertible languages , which can be auto-generated the PDA API from proto files for you.

For an idea how this could look like, have a look at this tutorial, generating proto files to C#/.NET.

Complete Source Code
Proto Client API example
//-----------------------------------------------------------------------------
// This example demonstrates how to acquire data, export to .csv and what
// steps are needed to achieve this with the ProcessDataAnalyzer Proto
// generated API.
// In contrast to the StandaloneAPITutorial, the ProtoClientAPITutorial
// requires the PDA API service to be already running.
// The application will connect to the first available device, acquire
// ten seconds worth of default configured data and save it to the
// desktop from where the .csv file will be opened with the PCs current
// default program for .csv.
// The ProtoClientAPITutorial application is implemented using the async
// interface.
// The ProtoClientAPITutorial application and ClientAPITutorial application
// demonstrate the same implementation with different dependencies.
//-----------------------------------------------------------------------------

using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using RAYLASE.PDA.API;
using System.Diagnostics;

public class Program
{
    // Before running this example, please make sure that the PDA API service is running.
    // The default installation location of the ProcessDataAnalyzer.Service.exe is
    // %ProgramFiles%\RAYLASE\ProcessDataAnalyzer\bin\ProcessDataAnalyzer.Service.exe";
    // 
    // To install the PDA API service as Windows service and have it running in
    // the background:
    //        - Open a command line as admin, navigate to the location and call:
    //            > ProcessDataAnalyzer.Service.exe install
    //            > ProcessDataAnalyzer.Service.exe start
    // Or you can start a single instance in a (non-admin) command line:
    //            > ProcessDataAnalyzer.Service.exe server
    public static int Main( string[] args )
    {
        Console.WriteLine( "\n\nProto Client API sample\n------------------\n\n" );

        // Create a connection to the running PDA API service.
        var channel = new Channel( "127.0.0.1:30051", ChannelCredentials.Insecure );

        // Create a new acquisition service instance which will represent the client acquisition API
        var acquisitionAPI = new Acquisition.AcquisitionClient( channel );

        // The card could be set by IP or serial number
        var suggestedCardIP = args[0];
        if ( !string.IsNullOrEmpty( suggestedCardIP ) )
        {
            Console.WriteLine( $"Connecting to card {suggestedCardIP} given as argument" );
        }
        else
        {
            // Discover all available cards
            Console.WriteLine( "Discovering available cards" );

            // With the protos, we need to use the "raw" generated interface.
            var discoverTask = acquisitionAPI.DiscoverAsync( new DiscoverRequest() ).ResponseAsync;

            var discoveryDuration = 0;
            while ( !discoverTask.IsCompleted )
            {
                Console.WriteLine( $"Discovering... {++discoveryDuration} s" );
                Thread.Sleep( 1000 );
            }

            // Get the card repeated field from the reply message.
            var cards = discoverTask.Result.CardInfos.CardInfos_;
            if ( cards.Count == 0 )
            {
                Console.WriteLine( "No cards found, please check your card configuration and network setup." );
                return -1;
            }
            else
                Console.WriteLine( $"Found {cards.Count} cards" );

            suggestedCardIP = cards[0].SuggestedIp;
            Console.WriteLine( $"Connecting to first card with suggested IP {suggestedCardIP}" );
        }

        // Here the proto interface call requires us to set the IP address. This can be a bit cumbersome at times.
        // Just traverse the messages as seen in acquisition.proto for the Connect() call.
        // Note that the .NET overload to parse the connection argument for IP and serial number
        // Is not available here. If a card should be connected by serial number, it must be set to SerialNumber.
        acquisitionAPI.Connect( new ConnectRequest { Cards = { new Card { CardIp = suggestedCardIP } } } );

        Console.WriteLine( "Starting acquisition (non-blocking)" );
        // The specified timeout will override the PDA's default timeout value.
        var acquisitionStartTask = acquisitionAPI.StartAsync( new AcquisitionStartRequest { AutoStopSeconds = 60 } ).ResponseAsync;

        // Do something else while the acquisition is running and stop after 10 seconds manually
        var processingDuration = 0;
        while ( processingDuration < 10 )
        {
            Console.WriteLine( $"Doing some dummy processing while acquisition is running... completed task {++processingDuration} of 10" );
            Thread.Sleep( 1000 );
        }

        // After "processing", manually stop the acquisition.
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var acquisitionStopTask = acquisitionAPI.StopAsync( new() ).ResponseAsync;
        while ( !acquisitionStartTask.IsCompleted && !acquisitionStopTask.IsCompleted )
        {
            Thread.Sleep( 10 );
        }
        stopwatch.Stop();
        Console.WriteLine( $"Manually stopped acquisition after processing finished, stopping took {stopwatch.ElapsedMilliseconds} ms" );

        // Some commands return a status in their reply which can transport a "soft" error without throwing.
        // In case of the Acquisition, if ADC signals are configured and the license can not be found,
        // The ADC signals will be excluded from acquisition and a warning is returned.
        // It might be a good idea to check the status code if available:
        var acquisitionReply = acquisitionStartTask.Result;
        if ( acquisitionReply.Status.Code != RAYLASE.PDA.API.Error.StatusCode.Ok )
        {
            Console.WriteLine( $"Acquisition encountered an error: {acquisitionReply.Status}" );
            return -1;
        }

        // Export the acquired 10 seconds to a .csv file to load into an excel table.
        // Please note that this path is as seen from the service.exe. If you set a relative path, it will
        // be relative to where the PDA service is running!
        Console.WriteLine( "Exporting acquired data to .csv" );
        var exportPath = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.Desktop ), "ProtoClientAPI_Export.csv" );
        acquisitionAPI.Export( new ExportRequest { ExportPath = exportPath, UseDecimalPoint = true } );

        //// Now you could open the file with Excel (or the default .csv reader on the system)
        //// Open the file with Excel (or the default .csv reader on the system)
        //using ( var fileopener = new Process() )
        //{
        //    fileopener.StartInfo.FileName = "explorer";
        //    fileopener.StartInfo.Arguments = "\"" + exportPath + "\"";
        //    fileopener.Start();
        //}

        // Exiting this client application will keep the service running.
        // This means that you could start an acquisition here and immediately exit. The acquisition will
        // keep running until a stop condition is met (e.g. trigger off or auto-stop timeout).
        return 0;
    }
}