OscilloscopeStream.cpp

/**
 * OscilloscopeStream.cpp
 *
 * This example performs a stream mode measurement and writes the data to OscilloscopeStream.csv.
 *
 * Find more information on http://www.tiepie.com/LibTiePie .
 */

#include "PrintInfo.hpp"
#include <fstream>
#include <iostream>
#include <thread>

#if defined(__linux) || defined(__unix)
#  include <cstdlib>
#endif

int main()
{
  int status = EXIT_SUCCESS;

  // Initialize library:
  TiePie::Hardware::Library::init();

  // Print library information:
  printLibraryInfo();

  // Enable network search:
  TiePie::Hardware::Network::setAutoDetectEnabled(true);

  // Update device list:
  TiePie::Hardware::DeviceList::update();

  // Try to open an oscilloscope with with stream measurement support:
  std::unique_ptr<TiePie::Hardware::Oscilloscope> scp;

  for(uint32_t i = 0; !scp && i < TiePie::Hardware::DeviceList::count(); i++)
  {
    const auto item = TiePie::Hardware::DeviceList::getItemByIndex(i);
    if(item->canOpen(TIEPIE_HW_DEVICETYPE_OSCILLOSCOPE) && (scp = item->openOscilloscope()))
    {
      // Check for stream measurement support:
      if(!(scp->measureModes() & TIEPIE_HW_MM_STREAM))
        scp = nullptr;
    }
  }

  if(scp)
  {
    uint16_t channelCount = 0;

    try
    {
      // Get the number of channels:
      channelCount = scp->channels.count();

      // Set measure mode:
      scp->setMeasureMode(TIEPIE_HW_MM_STREAM);

      // Set sample rate:
      scp->setSampleRate(1e3); // 1 kHz

      // Set record length:
      scp->setRecordLength(1000);                        // 1 kS
      const uint64_t recordlength = scp->recordLength(); // Read actual record length

      // For all channels:
      for(const auto& channel : scp->channels)
      {
        // Enable channel to measure it:
        channel->setEnabled(true);

        // Set range:
        channel->setRange(8); // 8 V

        // Set coupling:
        channel->setCoupling(TIEPIE_HW_CK_DCV); // DC Volt
      }

      // Print oscilloscope info:
      printDeviceInfo(*scp);

      // Create data buffers:
      std::vector<std::vector<float>> channelData(channelCount, std::vector<float>(recordlength));
      std::vector<float*> channelDataPointers(channelCount);
      for(size_t i = 0; i < channelCount; i++)
        channelDataPointers[i] = channelData[i].data();

      // Open file with write/update permissions:
      const std::string filename("OscilloscopeStream.csv");
      std::ofstream csv(filename.c_str(), std::ofstream::out);

      if(csv.is_open())
      {
        // Start measurement:
        scp->start();

        // Write csv header:
        csv << "Sample";
        for(uint16_t ch = 0; ch < channelCount; ch++)
          csv << ";Ch" << (ch + 1);
        csv << '\n';

        uint64_t currentSample = 0;

        for(uint8_t chunk = 0; chunk < 10; chunk++) // Measure 10 chunks
        {
          // Print a message, to inform the user that we still do something:
          std::cout << "Data chunk " << (chunk + 1) << '\n';

          // Wait for measurement to complete:
          while(!(scp->isDataReady() || scp->isDataOverflow()))
          {
            // 10 ms delay, to save CPU time:
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(10ms);
          }

          // Throw error on data overflow:
          if(scp->isDataOverflow())
            throw std::runtime_error("Data overflow!");

          // Get data:
          uint64_t samplesRead = scp->getData(channelDataPointers.data(), channelCount, 0, recordlength);

          // Write the data to csv:
          for(uint64_t i = 0; i < samplesRead; i++)
          {
            csv << currentSample++;
            for(uint16_t ch = 0; ch < channelCount; ch++)
              csv << ";" << channelData[ch][i];
            csv << '\n';
          }
        }

        std::cout << "Data written to: " << filename << '\n';

        // Close file:
        csv.close();

        // Stop measurement:
        scp->stop();
      }
      else
      {
        std::cerr << "Couldn't open file: " << filename << '\n';
        status = EXIT_FAILURE;
      }
    }
    catch(const std::exception& e)
    {
      std::cerr << "Exception: " << e.what() << '\n';
      status = EXIT_FAILURE;
    }

    // Close oscilloscope:
    scp = nullptr;
  }
  else
  {
    std::cerr << "No oscilloscope available with stream measurement support!\n";
    status = EXIT_FAILURE;
  }

  // Finalize library:
  TiePie::Hardware::Library::fini();

  return status;
}