Load Tek ISF File

I recommend that you download the attached file rather than copying this code because I had some formatting problems with the URLs in the comments.

 

 

#pragma rtGlobals=3     // Use modern global access method.

// File Loader for Tektronix ISF files
// A Tektronix ISF file is the contents of what a Tek oscilloscope sends in response
// to a WAVFrm? command. See https://www.tek.com/support/faqs/what-format-isf-file
//
// A Tek ISF file is not the same as a Tek WFM file. There exists a loader for Tek WFM files.
// See https://www.wavemetrics.com/project/LoadTekWaveform.
//
// It is recommended that you name your Tek ISF files with the ".isf" extension to make
// it clear what kind of file it is.

// The way to determine the header length is to look for the ":CURVE" keyword. It is formatted like this:
//      ":CURVE <digit><number>"        .e.g., ":CURVE 41000"
// where <digit> represents the number of digits is the following number and <number> represents the number of
// samples of binary data that follow. In this case, "4" is the number of digits in "1000" and 1000 is the number of samples.

static Constant kHeaderLength = 282             // Length of header in bytes. Empirically determined.
static Constant kWaveDataType = 2               // Single precision floating point

//  LoadTekISFFile(pathName, fileName, createTable, createGraph)
//
//  pathName is the name of an Igor symbolic path or "".
//  fileName is one of the following:
//      The name of a file in the folder designated by pathName.
//      A partial path from the folder designated by pathName to the file to be loaded.
//      A full path to the file to be loaded.
//      "" to get an Open File dialog.

// Add an item to Igor's Load Waves submenu (Data menu)
Menu "Load Waves"
    "Load Tek ISF File...", LoadTekISFFileMenuItem()
    "Load All Tek ISF Files In Folder...", LoadAllTekISFFiles("", "", 0, 0)
End

Function/S StripDoubleQuotes(str)
    String str                  // A string starting and ending with double quotes

    if (CmpStr(str[0], "\"") != 0)
        return str              // String did not start with double quotes
    endif
   
    Variable len  = strlen(str)
    str = str[1,len-2]
    return str
End

Structure TekISFHeaderInfo
    Variable encoding           // 0 = binary. -1 = unknown. Currently the only encoding I know about is binary. From ENCDG keyword.
    Variable byteOrder          // 0 = big-endian, 1 = little-endian.  From BYT_OR keyword.
    Variable dataType           // See WaveType for possible values. From BIT_NR and BN_FMT keywords.
    Variable numPoints          // Number of points in waveform. From NR_PT keyword.
    String xUnits               // From XUNIT keyword.
    Variable x0                 // From XZERO keyword.
    Variable dx                 // From XINCR keyword.
    String yUnits               // From YUNIT keyword.
    Variable yOffset                // From YOFF keyword.
    Variable yZero              // From YZERO keyword.
    Variable yMultiplier        // From YMULT keyword.
EndStructure

Function ExtractISFHeaderInfo(refNum, headerInfo, quiet)
    Variable refNum         // File reference number
    STRUCT TekISFHeaderInfo &headerInfo
    Variable quiet              // 0 - print information about errors
   
    Variable result = 0
   
    Variable originalPos
    FStatus refNum
    originalPos = V_filePos
   
    // Read header string
    String headerStr = ""
    Variable headerStrLength = kHeaderLength
    FSetPos refNum, 0
    headerStr = PadString(headerStr, kHeaderLength, 0x20)
    FBinRead refNum, headerStr
    FSetPos refNum, originalPos
   
    // Parse header string
    String str
    str = StringByKey("ENCDG", headerStr, " ")
    strswitch(str)
        case "BIN":
            headerInfo.encoding = 0
            break
        default:
            headerInfo.encoding = -1            // Unknown encoding
            result -= 1
            break
    endswitch

    str = StringByKey("BYT_OR", headerStr, " ")
    strswitch(str)
        case "MSB":
            headerInfo.byteOrder = 0
            break
        case "LSB":
            headerInfo.byteOrder = 1
            break
        default:
            headerInfo.byteOrder = -1           // Unknown byte order
            result -= 1
            break
    endswitch
   
    headerInfo.numPoints = NumberByKey("NR_PT", headerStr, " ")

    headerInfo.xUnits = StripDoubleQuotes(StringByKey("XUNIT", headerStr, " "))
    headerInfo.x0 = NumberByKey("XZERO", headerStr, " ")
    headerInfo.dx = NumberByKey("XINCR", headerStr, " ")
   
    headerInfo.yUnits = StripDoubleQuotes(StringByKey("YUNIT", headerStr, " "))
    headerInfo.yOffset = NumberByKey("YOFF", headerStr, " ")
    headerInfo.yZero = NumberByKey("YZERO", headerStr, " ")
    headerInfo.yMultiplier = NumberByKey("YMULT", headerStr, " ")
   
    Variable numBitsPerPoint = NumberByKey("BIT_NR", headerStr, " ")
    String binaryFormat = StringByKey("BN_FMT", headerStr, " ")
    strswitch(binaryFormat)
        case "RI":                              // Presumably "real integer"
            switch (numBitsPerPoint)
                case 8:
                    headerInfo.dataType = 8     // 8 bit signed integer
                    break
           
                case 16:
                    headerInfo.dataType = 16    // 16 bit signed integer
                    break
           
                case 32:
                    headerInfo.dataType = 32    // 32 bit signed integer
                    break
           
                default:
                    headerInfo.dataType = -1    // Unknown type
                    result -= 1
                    break
            endswitch      
            break
       
        default:
            headerInfo.dataType = -1            // Don't understand datatype
            result -= 1
            break
    endswitch
   
    return result
End

//  LoadTekISFFileDialog(createTable, createGraph)
//  Displays a dialog in which the user can enter parameters.
//  All of the parameters function both as inputs, to preset the dialog values,
//  and as output, to return the values to the calling routine.
//  The function result is 0 if OK or -1 if cancel.
Function LoadTekISFFileDialog(createTable, createGraph)
    Variable &createTable               // Input and output.
    Variable &createGraph               // Input and output.

    if ( (createTable<1) || (createTable>2) )
        createTable = 1
    endif
    if ( (createGraph<1) || (createGraph>2) )
        createGraph = 1
    endif
   
    // This is necessary because you can't pass an & parameter to Prompt.
    Variable createTable2 = createTable
    Variable createGraph2 = createGraph
   
    Prompt createTable2, "Create table", popup "Yes;No"
    Prompt createGraph2, "Create graph", popup "Yes;No"
    DoPrompt "Load Tek ISF File", createTable2, createGraph2
    if (V_Flag != 0)
        return -1           // User cancelled.
    endif
   
    createTable = createTable2
    createGraph = createGraph2
   
    return 0
End

Function LoadTekISFFile(pathName, fileName, createTable, createGraph, quiet, newWaveName)
    String pathName         // Igor symbolic path name or "" for dialog.
    String fileName             // file name, partial path and file name, or full path or "" for dialog.
    Variable createTable        // 1 = Yes, 2 = No, 0 for dialog.
    Variable createGraph        // 1 = Yes, 2 = No, 0 for dialog.
    Variable quiet              // 0 = print diagnostic and error messages, 1 = print error messages only, 2 = do not print diagnostic or error messages
    String &newWaveName     // Output: Name of wave created.
   
    newWaveName  = ""
   
    Variable err
   
    if ( (createTable==0) || (createGraph==0) )
        err = LoadTekISFFileDialog(createTable, createGraph)
        if (err != 0)
            return err
        endif
    endif

    // This puts up a dialog if the pathName and fileName do not specify a file.
    String message = "Select a Tek ISF file"
    Variable refNum
    Open /R /Z=2 /P=$pathName /T="????" /M=message refNum as fileName   // /T flag presents "All files" in Open File dialog.
   
    // Save outputs from Open in a safe place.
    err = V_Flag
    String fullPath = S_fileName

    if (err != 0)
        return err          // -1 means user canceled.
    endif
   
    // Load the header information
    STRUCT TekISFHeaderInfo headerInfo
    if (ExtractISFHeaderInfo(refNum, headerInfo, quiet!=2) != 0)
        if (quiet != 2)
            Print "Error while loading header section of the file."
        endif
        Close refNum
        return -1
    endif

    Close refNum
   
    switch (headerInfo.encoding)
        case 0:                             // Binary
            break
        default:
            if (quiet != 2)
                Print "The file's encoding is unknown. Only binary encoding is supported."
            endif
            return -1
    endswitch
   
    if (quiet == 0)
        Printf "Loading Tek ISF data from \"%s\"\r", fullPath
    endif
   
    GBLoadWave /B=(headerInfo.byteOrder) /A=tekWave /T={headerInfo.dataType,kWaveDataType} /S=(kHeaderLength) /W=1 /U=(headerInfo.numPoints) /Q fullPath
    if (V_flag == 0)
        if (quiet != 2)
            Print "Error while loading binary data section of the file."
        endif
        return -1
    endif
    newWaveName = StringFromList(0, S_waveNames)
    Wave w = $newWaveName
   
    SetScale/P x, headerInfo.x0, headerInfo.dx, ""+headerInfo.xUnits, w
    SetScale d, 0, 0, ""+headerInfo.yUnits, w
   
    // I don't know what headerInfo.yZero is all about (YZERO keyword).
   
    w = (w - headerInfo.yOffset) * headerInfo.yMultiplier
   
    if (quiet == 0)
        Printf "Created wave %s, %d points.\r", newWaveName, numpnts(w)
    endif
   
    if (createTable == 1)
        Edit w.id
        ModifyTable format[1]=3,digits[1]=9     // Display time in suitable format.
    endif
    if (createGraph == 1)
        Display w
    endif

    return 0            // Zero signifies no error.
End

Function LoadTekISFFileMenuItem()
    String newWaveName
    LoadTekISFFile("", "", 1, 1, 0, newWaveName)
End

//  LoadAllTekISFFilesDialog(extension, createTable, createGraph)
//  Displays a dialog in which the user can enter parameters.
//  All of the parameters function both as inputs, to preset the dialog values,
//  and as output, to return the values to the calling routine.
//  The function result is 0 if OK or -1 if cancel.
Function LoadAllTekISFFilesDialog(extension, createTable, createGraph)
    String &extension                   // Input and output
    Variable &createTable               // Input and output.
    Variable &createGraph               // Input and output.

    if (CmpStr(extension,".isf")!=0 && CmpStr(extension,"????")!=0)
        extension = ".isf"
    endif
    if ( (createTable<1) || (createTable>2) )
        createTable = 1
    endif
    if ( (createGraph<1) || (createGraph>2) )
        createGraph = 1
    endif
   
    // This is necessary because you can't pass an & parameter to Prompt.
    String extension2 = extension
    Variable createTable2 = createTable
    Variable createGraph2 = createGraph
   
    Prompt extension2, "Tek ISF file name extension", popup ".isf;Any extension"
    Prompt createTable2, "Create table", popup "Yes;No"
    Prompt createGraph2, "Create graph", popup "Yes;No"
    DoPrompt "Load All Tek ISF Files", extension2, createTable2, createGraph2
    if (V_Flag != 0)
        return -1           // User cancelled.
    endif

    if (CmpStr(extension2, "Any extension") == 0)
        extension2 = "????"
    endif
   
    extension = extension2
    createTable = createTable2
    createGraph = createGraph2
   
    return 0
End

Function LoadAllTekISFFiles(pathName, extension, createTable, createGraph)
    String pathName         // Name of an Igor symbolic folder created by Misc->NewPath
    String extension            // e.g., ".isf". Pass "????" for any extension. Pass "" for dialog.
    Variable createTable        // 1 = Yes, 2 = No, 0 for dialog.
    Variable createGraph        // 1 = Yes, 2 = No, 0 for dialog.

    if (CmpStr(extension,"")==0 || createTable<1 || createTable>2 || createGraph<1 || createGraph>2)
        if (LoadAllTekISFFilesDialog(extension, createTable, createGraph) != 0)
            return -1                   // User cancelled.
        endif
    endif
   
    if (strlen(pathName) == 0)
        String message
       
        if (CmpStr(extension, "????") == 0)
            message = "Select a directory containing Tek ISF files with any extension"
        else
            sprintf message, "Select a directory containing Tek ISF files with %s extension", extension
        endif
               
        NewPath/O/M=message TekISFDataPath      // This displays a dialog in which you can select a folder
        if (V_flag != 0)
            return V_flag                           // -1 means user canceled
        endif
        pathName = "TekISFDataPath"
    endif
   
    Variable err = 0

    String newWaveName
    String fileName
    Variable i = 0
    do
        fileName = IndexedFile($pathName, i, extension)
        if (strlen(fileName) == 0)
            break                                       // No more files
        endif
   
        err = LoadTekISFFile(pathName, fileName, 2, 2, 1, newWaveName)
        if (err != 0)
            return err
        endif
       
        if (createTable == 1)
            if (i == 0)
                Edit $newWaveName
            else
                AppendToTable $newWaveName
            endif
        endif
       
        if (createGraph == 1)
            if (i == 0)
                Display $newWaveName
            else
                AppendToGraph $newWaveName
            endif
        endif
   
        i += 1
    while(1)
   
    return 0
End

 

LoadTekISFFile.zip (4.11 KB)

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More