This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/DLPNIRNANOEVM: Problem reading scan data (only works some times)

Part Number: DLPNIRNANOEVM

Tool/software: Linux

I'm trying to write a Linux library to control the spectrometer over USB.

Everything is working fine on the communication side, as I ported the API part from the GUI and using HIDAPI. For interpretation I'm using the Spectrum Library.

But when I'm trying to use this code I get either a normal spectrum as expected (pic bottom), or something weird (pic top):

Spectrometer.h

#ifndef _SPECTROMETER_H_
#define _SPECTROMETER_H_

#include <unistd.h>
#include <string>

#include "API.h"
#include "usb.h"
#include <dlpspec/dlpspec_scan_col.h>

struct Spectrum
{
  std::string title;
  std::string comment;
  std::string isoDate;

  double detectorTemperature;
  double systemTemperature;
  double relHumidity;
  double lampIntensity;

  double resolution;
  double exposureTime;
  int gain;
  int repeats;

  int startWavelength;
  int endWavelength;

  size_t dataSize;
  double wavelength[ADC_DATA_LEN];
  int intensity[ADC_DATA_LEN];
  int reference[ADC_DATA_LEN];
};

class Spectrometer
{
public:
  bool init();
  void deinit();

  int scan(Spectrum &spectrum);

private:
  int runScan();
  int fetchActiveConfig();
  int fetchScan(unsigned char *buffer);
  int interpretScan(unsigned char *buffer, int size, scanResults *results);
  int interpretReference(scanResults *results, scanResults *referenceResults);

  void *GetRefCalMatrixBlob();
  void *GetRefCalDataBlob();
  int FetchRefCalData();
  int FetchRefCalMatrix();

  uint8_t refCalMatrixBlob[REF_CAL_MATRIX_BLOB_SIZE];
  uint8_t refCalDataBlob[SCAN_DATA_BLOB_SIZE];

  uint8_t activeConfigurationBuffer[SCAN_DATA_BLOB_SIZE];
  uScanConfig *activeConfiguration;
};

#endif // _SPECTROMETER_H_

Spectrometer.cpp

#include "Spectrometer.h"
#include "refCalMatrix.h"

#include <iostream>
#include <fstream>

using namespace std;

bool Spectrometer::init()
{
    activeConfiguration = NULL;
    if (USB_Init() != 0)
    {
        return false;
    }

    if (USB_Open() != 0)
    {
        return false;
    }

    NNO_SetHibernate(false);

    FetchRefCalData();
    FetchRefCalMatrix();
    return true;
}

void Spectrometer::deinit()
{

    USB_Close();
    USB_Exit();
}

int Spectrometer::scan(Spectrum &spectrum)
{
    uint8_t scanDatBlob[SCAN_DATA_BLOB_SIZE];
    uScanData *scanDat = (uScanData *)scanDatBlob;

    // fetchActiveConfig();

    if (runScan() != PASS)
    {
        return FAIL;
    }

    int realFileSize = fetchScan(scanDatBlob);

    scanResults results;
    scanResults refResults;
    dlpspec_scan_interpret(scanDatBlob, realFileSize, &results);
    dlpspec_scan_interpReference(refCalDataBlob, SCAN_DATA_BLOB_SIZE,
                                 refCalMatrixBlob, REF_CAL_MATRIX_BLOB_SIZE,
                                 &results, &refResults);

    dlpspec_scan_read_data(scanDatBlob, realFileSize);

    spectrum.dataSize = results.length;
    for (size_t i = 0; i < results.length; i++)
    {
        spectrum.wavelength[i] = refResults.wavelength[i];
        spectrum.reference[i] = refResults.intensity[i];
        spectrum.intensity[i] = results.intensity[i];
    }
    spectrum.startWavelength = results.cfg.section[0].wavelength_start_nm;
    spectrum.endWavelength = results.cfg.section[0].wavelength_end_nm;
    spectrum.repeats = results.cfg.head.num_repeats;
    spectrum.exposureTime = results.cfg.section[0].exposure_time;
    spectrum.resolution = results.cfg.section[0].width_px;

    spectrum.gain = scanDat->slew_data.pga;
    spectrum.detectorTemperature = scanDat->slew_data.detector_temp_hundredths / 100.0;
    spectrum.systemTemperature = scanDat->slew_data.system_temp_hundredths / 100.0;
    spectrum.relHumidity = scanDat->slew_data.humidity_hundredths / 100.0;
    spectrum.lampIntensity = scanDat->slew_data.lamp_pd;

    uint32 pVal;
    NNO_error_status_struct error_status;
    NNO_ReadDeviceStatus(&pVal);
    NNO_ReadErrorStatus(&error_status);

    cout << "Device status: " << pVal << endl
         << "Error status: " << error_status.status << endl
         << "Error code adc: " << (int)error_status.errorCodes.adc << endl
         << "Error code eeprom: " << (int)error_status.errorCodes.eeprom << endl
         << "Error code hdc: " << (int)error_status.errorCodes.hdc << endl
         << "Error code hw: " << (int)error_status.errorCodes.hw << endl
         << "Error code spec_lib: " << (int)error_status.errorCodes.spec_lib << endl
         << "Error code scan: " << (int)error_status.errorCodes.scan << endl
         << "Error code tmp: " << (int)error_status.errorCodes.tmp << endl
         << "Error code memory: " << (int)error_status.errorCodes.memory << endl;

    return PASS;
}

int Spectrometer::fetchScan(unsigned char *buffer)
{
    size_t fileSize = NNO_GetFileSizeToRead(NNO_FILE_SCAN_DATA);
    return NNO_GetFile(buffer, fileSize);
}

int Spectrometer::fetchActiveConfig()
{
    int activeIndex = NNO_GetActiveScanIndex();

    uint32 fileSize;
    int res = NNO_GetScanCfg(activeIndex, activeConfigurationBuffer, &fileSize);

    res = dlpspec_scan_read_configuration(activeConfigurationBuffer, fileSize);

    activeConfiguration = (uScanConfig *)activeConfigurationBuffer;

    if (activeConfiguration->slewScanCfg.head.scan_type != SLEW_TYPE)
    {
        cout << "Error: Wrong scan configuration type: " << (int)activeConfiguration->slewScanCfg.head.scan_type << "!" << endl;
        return FAIL;
    }

    cout << "Configuration:" << endl
         << "Active configuration: " << activeIndex << endl
         << "Config name: " << activeConfiguration->slewScanCfg.head.config_name << endl
         << "Scan type: " << (int)activeConfiguration->slewScanCfg.head.scan_type << endl
         << "Repeats: " << (int)activeConfiguration->slewScanCfg.head.num_repeats << endl
         << "Sections: " << (int)activeConfiguration->slewScanCfg.head.num_sections << endl
         << "Section[0]: " << endl
         << "startWavelength: " << (int)activeConfiguration->slewScanCfg.section[0].wavelength_start_nm << endl
         << "endWavelength: " << (int)activeConfiguration->slewScanCfg.section[0].wavelength_end_nm << endl
         << "exposureTime: " << (int)activeConfiguration->slewScanCfg.section[0].exposure_time << endl;

    return res;
}

int Spectrometer::runScan()
{
    unsigned int devStatus;

    NNO_SetScanNumRepeats(6);

    int scanTime = NNO_GetEstimatedScanTime();
    NNO_PerformScan(false);

    usleep(scanTime * 1000);

    int retries = 0;
    while (NNO_ReadDeviceStatus(&devStatus) == PASS && retries < 3)
    {
        if ((devStatus & NNO_STATUS_SCAN_IN_PROGRESS) != NNO_STATUS_SCAN_IN_PROGRESS)
            return PASS;
        usleep(500 * 1000);
        retries++;
    }
    return FAIL;
}

void *Spectrometer::GetRefCalMatrixBlob()
{
    refCalMatrix tmpRefCalMatrix;

    memcpy(tmpRefCalMatrix.width, refCalMatrix_widths, sizeof(uint8_t) * REF_CAL_INTERP_WIDTH);
    memcpy(tmpRefCalMatrix.wavelength, refCalMatrix_wavelengths, sizeof(double) * REF_CAL_INTERP_WAVELENGTH);
    memcpy(tmpRefCalMatrix.ref_lookup, refCalMatrix_intensities, sizeof(uint16_t) * REF_CAL_INTERP_WIDTH * REF_CAL_INTERP_WAVELENGTH);

    dlpspec_calib_write_ref_matrix(&tmpRefCalMatrix, refCalMatrixBlob, REF_CAL_MATRIX_BLOB_SIZE);

    return refCalMatrixBlob;
}

void *Spectrometer::GetRefCalDataBlob()
{
    return refCalDataBlob;
}

int Spectrometer::FetchRefCalData()
{
    int refCalSize = NNO_GetFileSizeToRead(NNO_FILE_REF_CAL_DATA);

    if (NNO_GetFile((unsigned char *)refCalDataBlob, refCalSize) == refCalSize)
        return PASS;
    else
        return FAIL;
}

int Spectrometer::FetchRefCalMatrix()
{
    int refCalSize = NNO_GetFileSizeToRead(NNO_FILE_REF_CAL_MATRIX);

    if (NNO_GetFile((unsigned char *)refCalMatrixBlob, refCalSize) == refCalSize)
        return PASS;
    else
        return FAIL;
}

And an example using it:

Spectrometer spec;

int main(int argc, const char **argv)
{
    string experiment;
    string subject;
    double weight;

    if (argc < 4)
    {
        cout << "Usage: " << argv[0] << " experiment subject weight" << endl;
        exit(0);
    }

    experiment = argv[1];
    subject = argv[2];
    weight = atof(argv[3]);

    curl_global_init(CURL_GLOBAL_ALL);

    if (!spec.init())
    {
        cout << "Cannot initialize USB device!" << endl;
        return -1;
    }

    cout << "Subject weight: " << weight << endl;

    cout << "Put subject on spectrometer and press enter when ready: " << endl;
    getchar();
    Spectrum result;
    spec.scan(result);

    result.title = experiment + "-" + subject;

    string id = saveScan(result, experiment, subject, weight);
    cout << "Scan ID: " << id << endl;

    string openBrowser = "xdg-open http://h4h0.de:8889/viewer/";
    openBrowser += id + " > /dev/null 2>&1";
    system(openBrowser.c_str());

    spec.deinit();

    curl_global_cleanup();

    return 0;
}

  • Harry,

    Please let me ask for clarification. Does this behavior occur over repeated scans of the same sample, or over different samples? In addition, please share whatever test setup conditions you have (e.g. how many systems/samples have you tested, repeatability, etc.).

    Best Regards,
    Philippe Dollo
  • Hi Philippe, thank you for the fast reply!

    The situation is like follows:

    When using the GUI in a virtual machine in windows, the results of the scan are perfectly fine, On every scan I make.

    When using my library in linux to do a scan, everything is also working fine, the scan data blob gets interpreted without error and the struct is valid, the wavelengths are the right one, only the values for intensity are weird: 

    The first few values are: 27902, 17353236, 18569717, 19937013, 21225973, 22510325, 23654133, 24756725, 25682421, 26928373, 27800565, 28766197, 77813, 82738, 86145, 89917, 93654, 97983, 101878, ...

    My test setup is: I'm putting leaves on aluminium sheet as background and putting this onto the window. Iv'e tested 20-30 samples with one device, the problem for shure is not about the test setup, because it doesn't happen with the GUI. It's most probably something in my code, maybe timings, maybe I've missed some command, etc...

    So here again the sources, I'm using (somehow they don't show up in the post above):

    Spectrometer.h:

    #ifndef _SPECTROMETER_H_
    #define _SPECTROMETER_H_
    
    #include <unistd.h>
    #include <string>
    
    #include "API.h"
    #include "usb.h"
    #include <dlpspec/dlpspec_scan_col.h>
    
    struct Spectrum
    {
      std::string title;
      std::string comment;
      std::string isoDate;
    
      double detectorTemperature;
      double systemTemperature;
      double relHumidity;
      double lampIntensity;
    
      double resolution;
      double exposureTime;
      int gain;
      int repeats;
    
      int startWavelength;
      int endWavelength;
    
      size_t dataSize;
      double wavelength[ADC_DATA_LEN];
      int intensity[ADC_DATA_LEN];
      int reference[ADC_DATA_LEN];
    };
    
    class Spectrometer
    {
    public:
      bool init();
      void deinit();
    
      int scan(Spectrum &spectrum);
    
    private:
      int runScan();
      int fetchActiveConfig();
      int fetchScan(unsigned char *buffer);
      int interpretScan(unsigned char *buffer, int size, scanResults *results);
      int interpretReference(scanResults *results, scanResults *referenceResults);
    
      void *GetRefCalMatrixBlob();
      void *GetRefCalDataBlob();
      int FetchRefCalData();
      int FetchRefCalMatrix();
    
      uint8_t refCalMatrixBlob[REF_CAL_MATRIX_BLOB_SIZE];
      uint8_t refCalDataBlob[SCAN_DATA_BLOB_SIZE];
    
      uint8_t activeConfigurationBuffer[SCAN_DATA_BLOB_SIZE];
      uScanConfig *activeConfiguration;
    };
    
    #endif // _SPECTROMETER_H_

    Spectrometer.cpp:

    #include "Spectrometer.h"
    #include "refCalMatrix.h"
    
    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    bool Spectrometer::init()
    {
        activeConfiguration = NULL;
        if (USB_Init() != 0)
        {
            return false;
        }
    
        if (USB_Open() != 0)
        {
            return false;
        }
    
        NNO_SetHibernate(false);
    
        FetchRefCalData();
        FetchRefCalMatrix();
        return true;
    }
    
    void Spectrometer::deinit()
    {
    
        USB_Close();
        USB_Exit();
    }
    
    int Spectrometer::scan(Spectrum &spectrum)
    {
        uint8_t scanDatBlob[SCAN_DATA_BLOB_SIZE];
        uScanData *scanDat = (uScanData *)scanDatBlob;
    
        // fetchActiveConfig();
    
        if (runScan() != PASS)
        {
            return FAIL;
        }
    
        int realFileSize = fetchScan(scanDatBlob);
    
        scanResults results;
        scanResults refResults;
        dlpspec_scan_interpret(scanDatBlob, realFileSize, &results);
        dlpspec_scan_interpReference(refCalDataBlob, SCAN_DATA_BLOB_SIZE,
                                     refCalMatrixBlob, REF_CAL_MATRIX_BLOB_SIZE,
                                     &results, &refResults);
    
        dlpspec_scan_read_data(scanDatBlob, realFileSize);
    
        spectrum.dataSize = results.length;
        for (size_t i = 0; i < results.length; i++)
        {
            spectrum.wavelength[i] = refResults.wavelength[i];
            spectrum.reference[i] = refResults.intensity[i];
            spectrum.intensity[i] = results.intensity[i];
        }
        spectrum.startWavelength = results.cfg.section[0].wavelength_start_nm;
        spectrum.endWavelength = results.cfg.section[0].wavelength_end_nm;
        spectrum.repeats = results.cfg.head.num_repeats;
        spectrum.exposureTime = results.cfg.section[0].exposure_time;
        spectrum.resolution = results.cfg.section[0].width_px;
    
        spectrum.gain = scanDat->slew_data.pga;
        spectrum.detectorTemperature = scanDat->slew_data.detector_temp_hundredths / 100.0;
        spectrum.systemTemperature = scanDat->slew_data.system_temp_hundredths / 100.0;
        spectrum.relHumidity = scanDat->slew_data.humidity_hundredths / 100.0;
        spectrum.lampIntensity = scanDat->slew_data.lamp_pd;
    
        uint32 pVal;
        NNO_error_status_struct error_status;
        NNO_ReadDeviceStatus(&pVal);
        NNO_ReadErrorStatus(&error_status);
    
        cout << "Device status: " << pVal << endl
             << "Error status: " << error_status.status << endl
             << "Error code adc: " << (int)error_status.errorCodes.adc << endl
             << "Error code eeprom: " << (int)error_status.errorCodes.eeprom << endl
             << "Error code hdc: " << (int)error_status.errorCodes.hdc << endl
             << "Error code hw: " << (int)error_status.errorCodes.hw << endl
             << "Error code spec_lib: " << (int)error_status.errorCodes.spec_lib << endl
             << "Error code scan: " << (int)error_status.errorCodes.scan << endl
             << "Error code tmp: " << (int)error_status.errorCodes.tmp << endl
             << "Error code memory: " << (int)error_status.errorCodes.memory << endl;
    
        return PASS;
    }
    
    int Spectrometer::fetchScan(unsigned char *buffer)
    {
        size_t fileSize = NNO_GetFileSizeToRead(NNO_FILE_SCAN_DATA);
        return NNO_GetFile(buffer, fileSize);
    }
    
    int Spectrometer::fetchActiveConfig()
    {
        int activeIndex = NNO_GetActiveScanIndex();
    
        uint32 fileSize;
        int res = NNO_GetScanCfg(activeIndex, activeConfigurationBuffer, &fileSize);
    
        res = dlpspec_scan_read_configuration(activeConfigurationBuffer, fileSize);
    
        activeConfiguration = (uScanConfig *)activeConfigurationBuffer;
    
        if (activeConfiguration->slewScanCfg.head.scan_type != SLEW_TYPE)
        {
            cout << "Error: Wrong scan configuration type: " << (int)activeConfiguration->slewScanCfg.head.scan_type << "!" << endl;
            return FAIL;
        }
    
        cout << "Configuration:" << endl
             << "Active configuration: " << activeIndex << endl
             << "Config name: " << activeConfiguration->slewScanCfg.head.config_name << endl
             << "Scan type: " << (int)activeConfiguration->slewScanCfg.head.scan_type << endl
             << "Repeats: " << (int)activeConfiguration->slewScanCfg.head.num_repeats << endl
             << "Sections: " << (int)activeConfiguration->slewScanCfg.head.num_sections << endl
             << "Section[0]: " << endl
             << "startWavelength: " << (int)activeConfiguration->slewScanCfg.section[0].wavelength_start_nm << endl
             << "endWavelength: " << (int)activeConfiguration->slewScanCfg.section[0].wavelength_end_nm << endl
             << "exposureTime: " << (int)activeConfiguration->slewScanCfg.section[0].exposure_time << endl;
    
        return res;
    }
    
    int Spectrometer::runScan()
    {
        unsigned int devStatus;
    
        NNO_SetScanNumRepeats(6);
    
        int scanTime = NNO_GetEstimatedScanTime();
        NNO_PerformScan(false);
    
        usleep(scanTime * 1000);
    
        int retries = 0;
        while (NNO_ReadDeviceStatus(&devStatus) == PASS && retries < 3)
        {
            if ((devStatus & NNO_STATUS_SCAN_IN_PROGRESS) != NNO_STATUS_SCAN_IN_PROGRESS)
                return PASS;
            usleep(500 * 1000);
            retries++;
        }
        return FAIL;
    }
    
    void *Spectrometer::GetRefCalMatrixBlob()
    {
        refCalMatrix tmpRefCalMatrix;
    
        memcpy(tmpRefCalMatrix.width, refCalMatrix_widths, sizeof(uint8_t) * REF_CAL_INTERP_WIDTH);
        memcpy(tmpRefCalMatrix.wavelength, refCalMatrix_wavelengths, sizeof(double) * REF_CAL_INTERP_WAVELENGTH);
        memcpy(tmpRefCalMatrix.ref_lookup, refCalMatrix_intensities, sizeof(uint16_t) * REF_CAL_INTERP_WIDTH * REF_CAL_INTERP_WAVELENGTH);
    
        dlpspec_calib_write_ref_matrix(&tmpRefCalMatrix, refCalMatrixBlob, REF_CAL_MATRIX_BLOB_SIZE);
    
        return refCalMatrixBlob;
    }
    
    void *Spectrometer::GetRefCalDataBlob()
    {
        return refCalDataBlob;
    }
    
    int Spectrometer::FetchRefCalData()
    {
        int refCalSize = NNO_GetFileSizeToRead(NNO_FILE_REF_CAL_DATA);
    
        if (NNO_GetFile((unsigned char *)refCalDataBlob, refCalSize) == refCalSize)
            return PASS;
        else
            return FAIL;
    }
    
    int Spectrometer::FetchRefCalMatrix()
    {
        int refCalSize = NNO_GetFileSizeToRead(NNO_FILE_REF_CAL_MATRIX);
    
        if (NNO_GetFile((unsigned char *)refCalMatrixBlob, refCalSize) == refCalSize)
            return PASS;
        else
            return FAIL;
    }

    Example:

    Spectrometer spec;
    
    int main(int argc, const char **argv)
    {
        string experiment;
        string subject;
        double weight;
    
        if (argc < 4)
        {
            cout << "Usage: " << argv[0] << " experiment subject weight" << endl;
            exit(0);
        }
    
        experiment = argv[1];
        subject = argv[2];
        weight = atof(argv[3]);
    
        curl_global_init(CURL_GLOBAL_ALL);
    
        if (!spec.init())
        {
            cout << "Cannot initialize USB device!" << endl;
            return -1;
        }
    
        cout << "Subject weight: " << weight << endl;
    
        cout << "Put subject on spectrometer and press enter when ready: " << endl;
        getchar();
        Spectrum result;
        spec.scan(result);
    
        result.title = experiment + "-" + subject;
    
        string id = saveScan(result, experiment, subject, weight);
        cout << "Scan ID: " << id << endl;
    
        spec.deinit();
    
        curl_global_cleanup();
    
        return 0;
    }

    Best regards,

    Harry

  • So I tried around a lot, and it seems to be my desktop system itself, on a Raspberry Pi (which will be the host system anyways) it's running without problems... 

    I'll try it tomorrow with my PC at the office and give a report, if this error is not reproducible, then I guess this thread can be closed.

    EDIT: So checked it on several other systems, and everything is fine, so this can be closed.