Search code examples
c#visa

How to parse binary data transmitted over GPIB with IVI library


I am working with a Fluke 8588 and communicating with it using Ivi.Visa.Interop I am trying to use the digitizer function to get a large number of samples of a 5V 1k Hz sinewave. To improve the transfer time of the data the manual mentions a setting for using a binary packed data format. It provides 2 and 4 byte packing.

This is the smallest example I could put together:

using System;
using System.Threading;
using Ivi.Visa.Interop;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Initiallizing Equipment");

            int timeOut = 3000;
            string resourceName = "GPIB0::1::INSTR";

            ResourceManager rm = new ResourceManager();
            FormattedIO488 fluke8588 = new FormattedIO488
            {
                IO = (IMessage)rm.Open(resourceName, AccessMode.NO_LOCK, timeOut)
            };

            Console.WriteLine("Starting Setup");
            fluke8588.WriteString("FORMAT:DATA PACKED,4");
            fluke8588.WriteString("TRIGGER:COUNT 100000");

            Console.WriteLine("Initiate Readings");
            fluke8588.WriteString("INITIATE:IMMEDIATE");
            Thread.Sleep(3000);

            Console.WriteLine("Readings Complete");

            Console.WriteLine("Fetching Reading");
            fluke8588.WriteString("FETCH?");
            string response = fluke8588.ReadString();

            Byte[] bytes = System.Text.Encoding.ASCII.GetBytes(response);
            fluke8588.WriteString("FORMAT:DATA:SCALE?");
            double scale = Convert.ToDouble(fluke8588.ReadString());

            int parityMask = 0x8;
            for (int i = 0; i < 100000; i += 4)
            {
                int raw = (int)((bytes[i] << 24) | (bytes[i + 1] << 16) | (bytes[i + 2] << 8) | (bytes[i + 3]));
                int parity = (parityMask & bytes[i]) == parityMask ? -1 : 1;

                int number = raw;
                if (parity == -1)
                {
                    number = ~raw * parity;
                }

                Console.WriteLine(number * scale);
            }
            Console.Read();
        }
    }
}

The resulting data looks like this:

enter image description here


I preformed the steps "manually" using a tool called NI Max. I get a header followed by the 10 4 byte integers and ending with a new line char. the negative integers are 2s complement, which was not specified in the manual but I was able to determine after I had enough samples.

NI Max

TRIGGER:COUNT was only set to 10 at the time this image was taken.

enter image description here

How can I get this result in c#?


Solution

  • I found that I was using the wrong Encoding, changing from System.Text.Encoding.ASCII.GetBytes(response) to

    System.Text.Encoding encoding = System.Text.Encoding.GetEncoding(1252);
    Byte[] bytes = encoding.GetBytes(response);
    

    got the desired result.


    That said, I also learned there is an alternative option to FormattedIO488.ReadString for binary data, using FormattedIO488.ReadIEEEBlock(IEEEBinaryType.BinaryType_I4) this will return an array of integers and requires no extra effort with twiddling bits, this is the solution I would suggest.

    using System;
    using System.Linq;
    using Ivi.Visa.Interop;
    using System.Threading;
    using System.Collections.Generic;
    
    namespace Example
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Initiallizing Equipment");
    
                int timeOut = 3000;
                string resourceName = "GPIB0::1::INSTR";
    
                ResourceManager rm = new ResourceManager();
                FormattedIO488 fluke8588 = new FormattedIO488
                {
                    IO = (IMessage)rm.Open(resourceName, AccessMode.NO_LOCK, timeOut)
                };
    
                Console.WriteLine("Starting Setup");
                fluke8588.WriteString("FORMAT:DATA PACKED,4");
                fluke8588.WriteString("TRIGGER:COUNT 100000");
    
                Console.WriteLine("Initiate Readings");
                fluke8588.WriteString("INITIATE:IMMEDIATE");
                Thread.Sleep(3000);
    
                Console.WriteLine("Readings Complete");
    
                Console.WriteLine("Fetching Reading");
                fluke8588.WriteString("FETCH?");
                List<int> response = new List<int>(fluke8588.ReadIEEEBlock(IEEEBinaryType.BinaryType_I4));
    
                fluke8588.WriteString("FORMAT:DATA:SCALE?");
                double scale = Convert.ToDouble(fluke8588.ReadString());
                foreach (var value in response.Select(i => i * scale).ToList())
                {
                    Console.WriteLine(value);
                }
                Console.Read();
            }
        }
    }
    

    Result data looks like:

    enter image description here