OscilloscopeGeneratorTrigger.c

/**
 * OscilloscopeGeneratorTrigger.c - for LibTiePie 0.6+
 *
 * This example sets up the generator to generate a 1 kHz triangle waveform, 4 Vpp.
 * It also sets up the oscilloscope to perform a block mode measurement, triggered on "Generator new period".
 * A measurement is performed and the data is written to OscilloscopeGeneratorTrigger.csv.
 *
 * Find more information on http://www.tiepie.com/LibTiePie .
 */

#include 
#include 
#include 
#include 
#include "CheckStatus.h"
#include "PrintInfo.h"
#include "Utils.h"

int main(int argc, char* argv[])
{
  int status = EXIT_SUCCESS;

  // Initialize library:
  LibInit();

  // Print library information:
  printLibraryInfo();

  // Update device list:
  LstUpdate();
  CHECK_LAST_STATUS();

  // Try to open an oscilloscope with block measurement support and a generator in the same device:
  TpDeviceHandle_t scp = TPDEVICEHANDLE_INVALID;
  TpDeviceHandle_t gen = TPDEVICEHANDLE_INVALID;

  for(uint32_t index = 0; index < LstGetCount(); index++)
  {
    if(LstDevCanOpen(IDKIND_INDEX, index, DEVICETYPE_OSCILLOSCOPE) && LstDevCanOpen(IDKIND_INDEX, index, DEVICETYPE_GENERATOR))
    {
      scp = LstOpenOscilloscope(IDKIND_INDEX, index);
      CHECK_LAST_STATUS();

      // Check for valid handle and block measurement support:
      if(scp != TPDEVICEHANDLE_INVALID && (ScpGetMeasureModes(scp) & MM_BLOCK))
      {
        gen = LstOpenGenerator(IDKIND_INDEX, index);
        break;
      }
      else
      {
        scp = TPDEVICEHANDLE_INVALID;
      }
    }
  }

  if(scp != TPDEVICEHANDLE_INVALID && gen != TPDEVICEHANDLE_INVALID)
  {
    // Oscilloscope settings:

    const uint16_t channelCount = ScpGetChannelCount(scp);
    CHECK_LAST_STATUS();

    // Set measure mode:
    ScpSetMeasureMode(scp, MM_BLOCK);

    // Set sample frequency:
    ScpSetSampleFrequency(scp, 1e6); // 1 MHz

    // Set record length:
    uint64_t recordLength = ScpSetRecordLength(scp, 10000); // 10 kS
    CHECK_LAST_STATUS();

    // Set pre sample ratio:
    ScpSetPreSampleRatio(scp, 0); // 0 %

    // For all channels:
    for(uint16_t ch = 0; ch < channelCount; ch++)
    {
      // Enable channel to measure it:
      ScpChSetEnabled(scp, ch, BOOL8_TRUE);
      CHECK_LAST_STATUS();

      // Set range:
      ScpChSetRange(scp, ch, 8); // 8 V
      CHECK_LAST_STATUS();

      // Set coupling:
      ScpChSetCoupling(scp, ch, CK_DCV); // DC Volt
      CHECK_LAST_STATUS();
    }

    // Set trigger timeout:
    ScpSetTriggerTimeOut(scp, 1); // 1 s
    CHECK_LAST_STATUS();

    // Disable all channel trigger sources:
    for(uint16_t ch = 0; ch < channelCount; ch++)
    {
      ScpChTrSetEnabled(scp, ch, BOOL8_FALSE);
      CHECK_LAST_STATUS();
    }

    // Locate trigger input:
    const uint16_t index = DevTrGetInputIndexById(scp, TIID_GENERATOR_NEW_PERIOD); // or TIID_GENERATOR_START || TIID_GENERATOR_STOP
    CHECK_LAST_STATUS();

    if(index != LIBTIEPIE_TRIGGERIO_INDEX_INVALID)
    {
      // Enable trigger input:
      DevTrInSetEnabled(scp, index, BOOL8_TRUE);
      CHECK_LAST_STATUS();
    }

    // Generator settings:

    // Set signal type:
    GenSetSignalType(gen, ST_TRIANGLE);
    CHECK_LAST_STATUS();

    // Set frequency:
    GenSetFrequency(gen, 1e3); // 1 kHz
    CHECK_LAST_STATUS();

    // Set amplitude:
    GenSetAmplitude(gen, 2); // 2 V
    CHECK_LAST_STATUS();

    // Set offset:
    GenSetOffset(gen, 0); // 0 V
    CHECK_LAST_STATUS();

    // Enable output:
    GenSetOutputOn(gen, BOOL8_TRUE);
    CHECK_LAST_STATUS();

    // Print oscilloscope info:
    printDeviceInfo(scp);

    // Print generator info:
    printDeviceInfo(gen);

    // Start measurement:
    ScpStart(scp);
    CHECK_LAST_STATUS();

    // Start signal generation:
    GenStart(gen);
    CHECK_LAST_STATUS();

    // Wait for measurement to complete:
    while(!ScpIsDataReady(scp) && !ObjIsRemoved(scp))
    {
      sleepMiliSeconds(10); // 10 ms delay, to save CPU time.
    }

    if(ObjIsRemoved(scp))
    {
      fprintf(stderr, "Device gone!");
      status = EXIT_FAILURE;
    }

    // Stop generator:
    GenStop(gen);
    CHECK_LAST_STATUS();

    // Disable output:
    GenSetOutputOn(gen, BOOL8_FALSE);
    CHECK_LAST_STATUS();

    if(ScpIsDataReady(scp))
    {
      // Create data buffers:
      float** channelData = malloc(sizeof(float*) * channelCount);
      for(uint16_t ch = 0; ch < channelCount; ch++)
      {
        channelData[ch] = malloc(sizeof(float) * recordLength);
      }

      // Get the data from the scope:
      recordLength = ScpGetData(scp, channelData, channelCount, 0, recordLength);
      CHECK_LAST_STATUS();

      // Open file with write/update permissions:
      const char* filename = "OscilloscopeGeneratorTrigger.csv";
      FILE* csv = fopen(filename, "w");
      if(csv)
      {
        // Write csv header:
        fprintf(csv, "Sample");
        for(uint16_t ch = 0; ch < channelCount; ch++)
        {
          fprintf(csv, ";Ch%" PRIu16, ch + 1);
        }
        fprintf(csv, NEWLINE);

        // Write the data to csv:
        for(uint64_t i = 0; i < recordLength; i++)
        {
          fprintf(csv, "%" PRIu64, i);
          for(uint16_t ch = 0; ch < channelCount; ch++)
          {
            fprintf(csv, ";%f", channelData[ch][i]);
          }
          fprintf(csv, NEWLINE);
        }

        printf("Data written to: %s" NEWLINE, filename);

        // Close file:
        fclose(csv);
      }
      else
      {
        fprintf(stderr, "Couldn't open file: %s" NEWLINE, filename);
        status = EXIT_FAILURE;
      }

      // Free data buffers:
      for(uint16_t ch = 0; ch < channelCount; ch++)
      {
        free(channelData[ch]);
      }
      free(channelData);
    }

    // Close oscilloscope:
    ObjClose(scp);
    CHECK_LAST_STATUS();

    // Close generator:
    ObjClose(gen);
    CHECK_LAST_STATUS();
  }
  else
  {
    fprintf(stderr, "No oscilloscope available with block measurement support or generator available in the same unit!" NEWLINE);
    status = EXIT_FAILURE;
  }

  // Exit library:
  LibExit();

  return status;
}