ScaNet

Chris Timossi 3-19-2009


Background

Sca (Simple Channel Access) Net is a .NET assembly that can be used to develop EPICS Channel Access clients.

ScaNet contains two classes:
Als.Epics.ChannelAccess is a simple wrapper class of the unmanaged channel access DLL (ca.dll) using the platform invoke (P/Invoke) API.
Als.Epics.SimpleChannelAccess provides the primary interface for .NET application builders.

Installation

An windows installer file can be downloaded  here. The following items will be installed in C:\Program Files\LBNL\ScaNetx86:

To test the installation, run ScaGet from a command line followed by a PV name. For example scaget chris:aoExample

Code samples

The following C# code examples can be run against a softIOC with the standard example data base included in the EPICS distribution (set prefix=chris).

Example 1: Grouped access


//                                         
//Assume softIOC running with prefix 'chris'
//                                         
using Als.Epics.SimpleChannelAccess;       
using Als.Epics.ChannelAccess;             
Sca sca = new Sca(); //Create a new Sca 
sca.GroupAccess = true; //Turn on grouped access
string[] pvnames = { "chris:aoExample", "chris:aiExample" };
double value = new double[pvnames.Length];                      
int tests = 100;                            
sca.AddItem(pvnames); //Add the PV names to get
for (int t = 1; t <= tests; t++) {            
   value[0] = sca.GetDouble(pvnames[0]); //Get the value of pvnames[0] as a double
   if (sca.Error(pvnames[0]))                   
       Console.WriteLine("{0} {1} ", pvnames[0], sca.GetErrorMessage(pvnames[0]));
   value[1] = sca.GetDouble(pvnames[1]);           
   if (sca.Error(pvnames[1]))                   
       Console.WriteLine("{0} {1} ", pvnames[1], sca.GetErrorMessage(pvnames[1]));
                                                 
   if (sca.GroupAccess) sca.RefreshValues();
}                                                

Example 2: Using callbacks

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Als.Epics.SimpleChannelAccess;
using Als.Epics.ChannelAccess;

namespace ScaExample
{
class ScaGetCallback
{

    ///


    /// ScaGet displays the values of the PVs on the command line.
    ///

    [STAThread]
    unsafe static void Main(string[] args)
    {
    //string[] pvnames = new string[args.Length];
    List pvnames = new List();

    if (args.Length == 0)
    {
        Console.WriteLine("Usage: scaget [pvnames]");
        return;
    }
    foreach (string pvstr in args)
    {
        pvnames.Add(pvstr);
    }
    Ca.ca_context_create(Ca.PreemptiveCallback.Disable);
    Sca pv = new Sca("testing");
    Console.WriteLine("{0} ", Sca.Version);
    int AddStatus = pv.AddItem(pvnames);
    pv.GroupAccess = false;
    test t = new test();
    Ca.EventCallbackDelagte cb = new Ca.EventCallbackDelagte(t.subscription_handler);
    int SuccessfulSubscriptions = pv.Subscribe(pvnames, cb);
    Ca.ErrorCode PendStatus = 0;
    int last_count = test.countit;
    while (SuccessfulSubscriptions > 0)
    {   
        PendStatus = Ca.ca_pend_event(0.1);
        foreach (string pvname in pvnames)
        {   
            if (pv.Error(pvname))
            {
                String status_string = pv.GetErrorMessage(pvname);
                Console.WriteLine("{0} {1} ", pvname, status_string);
                continue;
            }

            if (test.countit > last_count)
            {
                Console.WriteLine("{0} {1} ", new String((sbyte*)Ca.ca_name(t.chid)), test.cb_d);
                last_count = test.countit;
            }

        }
    }

    Console.WriteLine("Failed to Subscribe");
}

class test
{
    public static int countit = 0;
    public static Ca.RequestBuffer dbr_type;
    public static Ca.ErrorCode cb_status;
    public static double cb_d = 0.0;
    public IntPtr chid;

    unsafe public void subscription_handler(Ca.event_handler_args args)
    {
        dbr_type = args.type;
        cb_status = args.status;
        chid = args.chid;
        if (dbr_type == Ca.RequestBuffer.DBR_DOUBLE)
            cb_d = *(double*)args.dbr.ToPointer();
            countit++;
        }
    }

}
}