I found an NI example on how to use some of the DAQmx functions. It's a simple C-file that contains some of the following:
...
// This is a declaration/definition I think
int32 CVICALLBACK ChangeDetectionCallback(TaskHandle taskHandle, int32 signalID, void *callbackData);
...
// Later in the script there is actual function
int32 CVICALLBACK ChangeDetectionCallback(TaskHandle taskHandle, int32 signalID, void *callbackData)
{
...
return 0;
}
When I tend to use some of the variables or functions that are defined in .h file, the ChangeDetectionCallback function does not recognize them. I tried to define this callback function as a member function in .h file, hoping that now all functions will be accessible. Here's my .h content:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "NIDAQmx.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
int32 CVICALLBACK ChangeDetectionCallback(TaskHandle taskHandle, int32 signalID, void *callbackData);
private:
Ui::MainWindow *ui;
void mainLoop();
};
#endif // MAINWINDOW_H
and here's my .c content:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "NIDAQmx.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mainLoop();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::mainLoop()
{
...
DAQmxErrChk (DAQmxRegisterSignalEvent(taskHandle,DAQmx_Val_ChangeDetectionEvent,0,ChangeDetectionCallback,NULL));
...
}
int32 MainWindow::ChangeDetectionCallback(TaskHandle taskHandle, int32 signalID, void *callbackData)
{
...
return 0;
}
So, again, I tried many wrong ways to define my callback function in the header file unsuccessfully. Please, help me to get this straight. And here's the error message that I do not clearly understand:
D:\Projects\sapm3\mainwindow.cpp:37: error: cannot convert 'MainWindow::ChangeDetectionCallback' from type 'int32 (MainWindow::)(TaskHandle, int32, void*) {aka long int (MainWindow::)(void*, long int, void*)}' to type 'DAQmxSignalEventCallbackPtr {aka long int (__attribute__((__cdecl__)) *)(void*, long int, void*)}'
DAQmxErrChk (DAQmxRegisterSignalEvent(taskHandle,DAQmx_Val_ChangeDetectionEvent,0,ChangeDetectionCallback,NULL));
Here's the original code. It triggers callback function to get a measurement sample and outputs the data to console. I wish to write the sampled data to my member variable and emit a signal that is defined in the .h file of the object.
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <NIDAQmx.h>
#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else
static TaskHandle taskHandle;
static uInt32 numLines;
static uInt8 cachedData[200];
int32 CVICALLBACK ChangeDetectionCallback(TaskHandle taskHandle, int32 signalID, void *callbackData);
void Cleanup (void);
int main(void)
{
int32 error=0;
char errBuff[2048]={'\0'};
/*********************************************/
// DAQmx Configure Code
/*********************************************/
DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
DAQmxErrChk (DAQmxCreateDIChan(taskHandle,"Dev1/port0/line0:7","",DAQmx_Val_ChanPerLine));
DAQmxErrChk (DAQmxCfgChangeDetectionTiming(taskHandle,"Dev1/port0/line0:7","Dev1/port0/line0:7",DAQmx_Val_ContSamps,1));
DAQmxErrChk (DAQmxRegisterSignalEvent(taskHandle,DAQmx_Val_ChangeDetectionEvent,0,ChangeDetectionCallback,NULL));
DAQmxErrChk (DAQmxGetTaskNumChans(taskHandle,&numLines));
/*********************************************/
// DAQmx Start Code
/*********************************************/
DAQmxErrChk (DAQmxStartTask(taskHandle));
puts("Continuously reading. Press Enter key to interrupt\n");
puts("Timestamp Data read Changed Lines");
getchar();
Error:
if( DAQmxFailed(error) )
{
DAQmxGetExtendedErrorInfo(errBuff,2048);
Cleanup();
printf("DAQmx Error: %s\n",errBuff);
}
printf("End of program, press Enter key to quit\n");
getchar();
return 0;
}
int32 CVICALLBACK ChangeDetectionCallback(TaskHandle taskHandle, int32 signalID, void *callbackData)
{
int32 error=0;
uInt8 data[200]={0};
int32 numRead;
uInt32 i=0;
char buff[512], *buffPtr;
char errBuff[2048]={'\0'};
char *timeStr;
time_t currTime;
if( taskHandle ) {
time (&currTime);
timeStr = ctime(&currTime);
timeStr[strlen(timeStr)-1]='\0'; // Remove trailing newline.
/*********************************************/
// DAQmx Read Code
/*********************************************/
DAQmxErrChk (DAQmxReadDigitalLines(taskHandle,1,10.0,DAQmx_Val_GroupByScanNumber,data,8,&numRead,NULL,NULL));
if( numRead ) {
buffPtr = buff;
strcpy(buff, timeStr);
strcat(buff," ");
buffPtr = buff + strlen(buff);
for(;i<numLines;++i) {
sprintf(buffPtr,"%d",data[i]);
buffPtr++;
}
strcat(buff," ");
buffPtr = buff + strlen(buff);
for(i=0;i<numLines;++i) {
sprintf(buffPtr,"%c",data[i]==cachedData[i]?'-':'X');
buffPtr++;
cachedData[i] = data[i];
}
puts(buff);
fflush(stdout);
}
}
return 0;
Error:
if( DAQmxFailed(error) )
{
DAQmxGetExtendedErrorInfo(errBuff,2048);
Cleanup();
printf("DAQmx Error: %s\n",errBuff);
}
return 0;
}
void Cleanup (void)
{
if( taskHandle!=0 )
{
/*********************************************/
// DAQmx Stop Code
/*********************************************/
DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
taskHandle = 0;
}
}
I found the way to go around my problem. I declare an array variable at the top of the file. This way my callback function recognizes it. Then, I copy data from this array to my member array. Similarly, I created a counter variable and increment it each time the callback runs. At the same time I loopcheck this variable in my member function until it reaches desirable value and then emit a signal. Such approach really sucks and I wish to find a more intelligent way to writ it.
The problem is that you're trying to pass a member function pointer instead of a function pointer. You could use an indirection to get this working.
Outside of the class you'll define a function:
Then define the MainWindow method to be called like this:
int32 ChangeDetectionCallback(TaskHandle taskHandle, int32 signalID);
And then register it like this:
Note that the
callbackData
parameter is used for passing the pointer to the object around. This data is passed when you register the event, instead of theNULL
.This is a typical pattern for C libraries, and this is a typical way of how to connect this to C++.