Readout a Fluke oscilloscope via GPIB

#pragma TextEncoding = "Windows-1252"
#pragma rtGlobals=3     // Use modern global access method and strict wave access.

/// Acquire spectra from an oscilloscope
/// Tested with a Fluke PM3394B using a PCI GPIB card on Windows 7 and Igor Pro 7 beta
/// The oscilloscope understands SCPI, I've included some commands to add proper units
/// to the acquired data.
///
/// Steps:
/// - Connect oscilloscope
/// - Adapt board and device in Initialize()
/// - Call Initialize(), maybe even twice
/// - Call AcquireData()
/// - Voila!

Function/WAVE StringToBufferWave(str)
    string str
   
    Make/B/FREE/N=(strlen(str)) buf = char2num(str[p])
   
    return buf
End

Function/S BufferWavetoString(buf)
    Wave buf
   
    string str = ""
    str = PadString(str, DimSize(buf, 0), 0x0)
    variable i

    for(i = 0; i < DimSize(buf, 0); i+= 1)
        str[i] = num2char(buf[i])
    endfor
   
    return str
End

Function Send(str)
    string str

    NVAR gBoardID, gDeviceAddress
    Variable DABend = 0x02

    NI4882 Send={gBoardID,gDeviceAddress,StringToBufferWave(str),strlen(str),DABend}
    printf "V_iberr=%d\r", V_iberr
End

Function/WAVE Receive()

    NVAR gBoardID, gDeviceAddress
    Variable STOPend = 0x100    // Means stop receiving when END is asserted.

    Make/B/U/FREE bufferWave
    NI4882 Receive={gBoardID,gDeviceAddress,bufferWave,100000,STOPend}  // Read 1000 bytes or until END is asserted.
    printf "V_iberr=%d\r", V_iberr

    return bufferWave  
End

Function Initialize()
    Variable/G gBoardID, gDeviceAddress, gDeviceDesc
   
    gBoardID = 0
    gDeviceAddress = 3

    NI4882 ibfind={"gpib0"}
    NI4882 ibcac={V_Flag, 1}
    NI4882 ibdev={gBoardID,gDeviceAddress,0,13,1,0}
    gDeviceDesc = V_Flag
End

Function AcquireData()

    variable ptPeak, voltOffset, sweepTime, tracePoints
    string str

    NVAR gBoardID, gDeviceAddress, gDeviceDesc

//  Send("*RST")
    Send("FORMat INTeger,16")
    Send("TRACe:POINts CH1,8192")
///  Only the following trace acquisition lengths can be programmed:
/// 512, 2024 (2K), 4096 (4K), 8192 (8K), 16384 (16K), or 32768 (32K)
    Send("TRIGger:SOURce INTernal1")
    Send("TRIGger:LEVel 0.1")
    Send("INITiate")
    Send("*WAI;TRACe? CH1")
    WAVE bufferWave = Receive()

    Duplicate/O bufferWave, root:bufferWave
    WAVE bufferWave

    ptPeak      = QueryNumericalValue("SENSe:VOLTage:RANGe:PTPeak?")
    voltOffset  = QueryNumericalValue("SENSe:VOLTage:RANGe:OFFSet?")
    sweepTime   = QueryNumericalValue("SENSe:SWEep:TIME?")
    tracePoints = QueryNumericalValue("TRACe:POINts? CH1")
    printf "ptPeak=%g, voltOffset=%g, sweepTime=%g, tracePoints=%g\r", ptPeak, voltOffset, sweepTime, tracePoints
    WAVE bufferWaveConv = ConvertFromOsziFormat(bufferWave, ptPeak, voltOffset, sweepTime, tracePoints)
    Duplicate/O bufferWaveConv, root:result
End

Function QueryNumericalValue(cmd)
    string cmd

    string str

    Send(cmd)
    WAVE bufferWave = Receive()
    str = BufferWavetoString(bufferWave)
    return str2num(str)
End

Function ASSERT(var, str)
    variable var
    string str

    try
        AbortOnValue !var, 0; AbortOnRTE
    catch
        printf "Assertion failed: %s\r", str
        Debugger
        Abort
    endtry
End

Function/WAVE ConvertFromOsziFormat(wv, ptPeak, voltageOffset, sweepTime, tracePoints)
    WAVE wv
    variable ptPeak, voltageOffset, sweepTime, tracePoints

    variable numDigitsSize, checksum, numTraceBytes, intWidth, numRows, i, traceByteOffset
    numRows = DimSize(wv, 0)

    ASSERT(numRows > 20, "Malformed data: Wave is too small")
    ASSERT(wv[0] == char2num("#"), "Malformed data: Expected # as first char")
    ASSERT(wv[numRows - 1] == char2num("\n"), "Malformed data: Expected \\n as last char")

    numDigitsSize = str2num(num2char(wv[1]))
    numTraceBytes = ExtractLength(wv, numDigitsSize)
    traceByteOffset = numDigitsSize + 3
    ASSERT(numRows == traceByteOffset + numTraceBytes, "Malformed data: Unexpected length")

    intWidth = wv[numDigitsSize + 2]

    ASSERT(tracePoints == (numTraceBytes - 2) / (intWidth / 8), "Malformed data: Length does not match requested length")
    printf "numDigitsSize=%g, numTraceBytes=%g, intWidth=%g\r", numDigitsSize, numTraceBytes, intWidth

    Make/D/FREE/N=(tracePoints) data

    for(i = traceByteOffset;i < traceByteOffset + numTraceBytes - 2; i += 1)
        checksum = mod(checksum + wv[i], 256)
    endfor

    ASSERT(checksum == mod(wv[numRows - 2] + 256, 256), "Malformed data: Checksum mismatch")

    switch(intWidth)
        case 8:
            MultiThread data = ConvertTraceByteToVoltage8Bit(wv[traceByteOffset + p], ptPeak, voltageOffset)
            break
        case 16:
            MultiThread data[0, tracePoints - 1] = ConvertTraceByteToVoltage16Bit(wv[traceByteOffset + p * 2],wv[traceByteOffset + p * 2 + 1], ptPeak, voltageOffset)
            break
        default:
            ASSERT(0, "Unexpected intWidth")
            break
    endswitch

    SetScale/P x, 0, sweepTime / (tracePoints - 1), "s", data
    SetScale d, 0, 0, "V", data

    return data
End

threadsafe Function ConvertTraceByteToVoltage8Bit(byte, ptPeak, voltageOffset)
    variable byte, ptPeak, voltageOffset
   
    variable value

    value = byte > 127 ? byte - 256 : byte

    return (value / 200) * ptPeak - voltageOffset
End

threadsafe Function ConvertTraceByteToVoltage16Bit(msbByte, lsbByte, ptPeak, voltageOffset)
    variable msbByte, lsbByte, ptPeak, voltageOffset

    variable value

    value = msbByte > 127 ? (msbByte - 256) * 256 + lsbByte : msbByte * 256 + lsbByte

    return (value / 51200) * ptPeak - voltageOffset
End

Function ExtractLength(wv, numDigitsSize)
    WAVE wv
    variable numDigitsSize

    variable i, length

    for(i = 0; i < numDigitsSize; i += 1)
        length += str2num(num2char(wv[2 + i])) * 10^(numDigitsSize - (1 + i))
    endfor

    return length
End

Forum

Support

Gallery

Igor Pro 8

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More