From c839387396b7e7ee266b61ba141a7d5e3a2f36f9 Mon Sep 17 00:00:00 2001
From: MPIBR-kretschmerf <friedrich.kretschmer@brain.mpg.de>
Date: Thu, 2 Mar 2017 10:40:45 +0100
Subject: [PATCH] NIDAQ errors are logged to file and program does not quit
 anymore on errors

---
 NIDAQmxInterface.cpp | 111 +++++++++++++++++++++++++++----------------
 NIDAQmxInterface.h   |   2 +-
 2 files changed, 71 insertions(+), 42 deletions(-)

diff --git a/NIDAQmxInterface.cpp b/NIDAQmxInterface.cpp
index 8da8852..0d55911 100644
--- a/NIDAQmxInterface.cpp
+++ b/NIDAQmxInterface.cpp
@@ -24,28 +24,28 @@ void NIDAQmxInterface::DAQmxInitializeInterface()
     DAQmxSetDefaultEngine();
 
     /* configure digital read error task */
-    DAQmxErrChk(DAQmxCreateTask("DigError", &daq->di_error));
-    DAQmxErrChk(DAQmxCreateDIChan(daq->di_error, "Dev1/port2", "", DAQmx_Val_ChanForAllLines));
+    errorCheck(DAQmxCreateTask("DigError", &daq->di_error));
+    errorCheck(DAQmxCreateDIChan(daq->di_error, "Dev1/port2", "", DAQmx_Val_ChanForAllLines));
     DAQmxReadErrorPort();
 
     /* configure digital read task */
-    DAQmxErrChk(DAQmxCreateTask("DigIn", &daq->di_port));
-    DAQmxErrChk(DAQmxCreateDIChan(daq->di_port, "Dev1/port0", "", DAQmx_Val_ChanForAllLines));
-    DAQmxErrChk(DAQmxCfgChangeDetectionTiming(daq->di_port, "Dev1/port0/line2,Dev1/port0/line3,Dev1/port0/line6", "Dev1/port0/line2,Dev1/port0/line3,Dev1/port0/line6", DAQmx_Val_ContSamps, 1));
-    //DAQmxErrChk(DAQmxCfgChangeDetectionTiming(daq->di_port, "Dev1/port0/line2,Dev1/port0/line6", "Dev1/port0/line2,Dev1/port0/line6", DAQmx_Val_ContSamps, 1));
-    DAQmxErrChk(DAQmxRegisterSignalEvent(daq->di_port, DAQmx_Val_ChangeDetectionEvent, 0, inputCallbackWrapper, this));
+    errorCheck(DAQmxCreateTask("DigIn", &daq->di_port));
+    errorCheck(DAQmxCreateDIChan(daq->di_port, "Dev1/port0", "", DAQmx_Val_ChanForAllLines));
+    errorCheck(DAQmxCfgChangeDetectionTiming(daq->di_port, "Dev1/port0/line2,Dev1/port0/line3,Dev1/port0/line6", "Dev1/port0/line2,Dev1/port0/line3,Dev1/port0/line6", DAQmx_Val_ContSamps, 1));
+    //errorCheck(DAQmxCfgChangeDetectionTiming(daq->di_port, "Dev1/port0/line2,Dev1/port0/line6", "Dev1/port0/line2,Dev1/port0/line6", DAQmx_Val_ContSamps, 1));
+    errorCheck(DAQmxRegisterSignalEvent(daq->di_port, DAQmx_Val_ChangeDetectionEvent, 0, inputCallbackWrapper, this));
 
     /* configure digital write task */
-    DAQmxErrChk(DAQmxCreateTask("DigOut", &daq->do_port));
-    DAQmxErrChk(DAQmxCreateDOChan(daq->do_port, "Dev1/port1", "", DAQmx_Val_ChanForAllLines));
+    errorCheck(DAQmxCreateTask("DigOut", &daq->do_port));
+    errorCheck(DAQmxCreateDOChan(daq->do_port, "Dev1/port1", "", DAQmx_Val_ChanForAllLines));
 
     /* configure digital internal clock task */
-    DAQmxErrChk(DAQmxCreateTask("DigClk", &daq->do_clk));
-    //DAQmxErrChk(DAQmxCreateCOPulseChanTime(daq->do_clk, "Dev1/ctr0", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0, 0.05, DO_PULSE_WIDTH));
-    DAQmxErrChk(DAQmxCreateCOPulseChanTime(daq->do_clk, "Dev1/ctr0", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0, 0.05, 0.08));
-    DAQmxErrChk(DAQmxCfgImplicitTiming(daq->do_clk, DAQmx_Val_FiniteSamps, 1));
+    errorCheck(DAQmxCreateTask("DigClk", &daq->do_clk));
+    //errorCheck(DAQmxCreateCOPulseChanTime(daq->do_clk, "Dev1/ctr0", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0, 0.05, DO_PULSE_WIDTH));
+    errorCheck(DAQmxCreateCOPulseChanTime(daq->do_clk, "Dev1/ctr0", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0, 0.05, 0.08));
+    errorCheck(DAQmxCfgImplicitTiming(daq->do_clk, DAQmx_Val_FiniteSamps, 1));
 
-    DAQmxErrChk(DAQmxRegisterDoneEvent(daq->do_clk, 0, pulldownTimerCallbackWrapper, this));
+    errorCheck(DAQmxRegisterDoneEvent(daq->do_clk, 0, pulldownTimerCallbackWrapper, this));
 
     /* start custom task */
     DAQmxStartCustomTask(daq->di_port);
@@ -87,7 +87,7 @@ void NIDAQmxInterface::DAQmxReadErrorPort()
 
     /* read port */
     if (daq->di_error != 0)
-        DAQmxErrChk(DAQmxReadDigitalU8(daq->di_error, 1, 10.0, DAQmx_Val_GroupByChannel, &port_bit, 1, &read, NULL));
+        errorCheck(DAQmxReadDigitalU8(daq->di_error, 1, 10.0, DAQmx_Val_GroupByChannel, &port_bit, 1, &read, NULL));
 
     /* stop task */
     DAQmxStopCustomTask(daq->di_error);
@@ -98,19 +98,25 @@ void NIDAQmxInterface::DAQmxReadErrorPort()
         if ((port_bit & DAQ_PORT_DE_MONITOR) == DAQ_PORT_DE_MONITOR)
         {
             fprintf(stderr, "DAQmxError:NIDAQmxInterface/DAQmxReadErrorPort:\n\tMONITOR failed!\n");
-            exit(EXIT_FAILURE);
+            QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
+            emit(writeToLogFile("ERROR: Monitor read error on NIDAQ", 0, 0, timeString));
+            return;
         }
 
         if ((port_bit & DAQ_PORT_DE_AIR) == DAQ_PORT_DE_AIR)
         {
             fprintf(stderr, "DAQmxError:NIDAQmxInterface/DAQmxReadErrorPort:\n\tAIR pump failed!\n");
-            exit(EXIT_FAILURE);
+            QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
+            emit(writeToLogFile("ERROR: Air read error on NIDAQ", 0, 0, timeString));
+            return;
         }
 
         if ((port_bit & DAQ_PORT_DE_WATER) == DAQ_PORT_DE_WATER)
         {
             fprintf(stderr, "DAQmxError:NIDAQmxInterface/DAQmxReadErrorPort:\n\tWATER pump failed!\n");
-            exit(EXIT_FAILURE);
+            QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
+            emit(writeToLogFile("ERROR: Water read error on NIDAQ", 0, 0, timeString));
+            return;
         }
     }
 
@@ -122,7 +128,7 @@ void NIDAQmxInterface::DAQmxReadErrorPort()
 void NIDAQmxInterface::DAQmxDestroyInterface()
 {
     /* check if task is digital output task is done */
-    DAQmxErrChk(DAQmxWaitUntilTaskDone(daq->do_clk, -1));
+    errorCheck(DAQmxWaitUntilTaskDone(daq->do_clk, -1));
 
     /* stop tasks */
     DAQmxStopCustomTask(daq->di_port);
@@ -131,13 +137,13 @@ void NIDAQmxInterface::DAQmxDestroyInterface()
     DAQmxStopCustomTask(daq->di_error);
 
     /* clear tasks */
-    DAQmxErrChk(DAQmxClearTask(daq->di_port));
+    errorCheck(DAQmxClearTask(daq->di_port));
     daq->di_port = 0;
-    DAQmxErrChk(DAQmxClearTask(daq->do_port));
+    errorCheck(DAQmxClearTask(daq->do_port));
     daq->do_port = 0;
-    DAQmxErrChk(DAQmxClearTask(daq->do_clk));
+    errorCheck(DAQmxClearTask(daq->do_clk));
     daq->do_clk = 0;
-    DAQmxErrChk(DAQmxClearTask(daq->di_error));
+    errorCheck(DAQmxClearTask(daq->di_error));
     daq->di_error = 0;
 
     return;
@@ -152,12 +158,12 @@ void NIDAQmxInterface::DAQmxStartCustomTask(TaskHandle taskHandle)
     if (taskHandle != 0)
     {
         /* check if task is already active */
-        DAQmxErrChk(DAQmxIsTaskDone(taskHandle, &done));
+        errorCheck(DAQmxIsTaskDone(taskHandle, &done));
         if (!done)
-            DAQmxErrChk(DAQmxStopTask(taskHandle));
+            errorCheck(DAQmxStopTask(taskHandle));
 
         /* start / re-start task */
-        DAQmxErrChk(DAQmxStartTask(taskHandle));
+        errorCheck(DAQmxStartTask(taskHandle));
     }
 
 	return;
@@ -171,9 +177,9 @@ void NIDAQmxInterface::DAQmxStopCustomTask(TaskHandle taskHandle)
     if (taskHandle != 0)
     {
         /* check if task is active */
-        DAQmxErrChk(DAQmxIsTaskDone(taskHandle, &done));
+        errorCheck(DAQmxIsTaskDone(taskHandle, &done));
         if (!done)
-            DAQmxErrChk(DAQmxStopTask(taskHandle));
+            errorCheck(DAQmxStopTask(taskHandle));
     }
 
     return;
@@ -190,24 +196,26 @@ void NIDAQmxInterface::DAQmxTriggerDO(uInt8 qry_port_bit, bool arm_timer)
         if (daq->do_port != 0)
         {
             daq->do_bit_wrt ^= qry_port_bit;
-            DAQmxErrChk(DAQmxWriteDigitalU8(daq->do_port, 1, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->do_bit_wrt, &written, NULL));
+            errorCheck(DAQmxWriteDigitalU8(daq->do_port, 1, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->do_bit_wrt, &written, NULL));
         }
 
         /* check for error */
         if (written == 0)
         {
             fprintf(stderr, "Error::NIDAQmxInterface/DAQmxTriggerDO:\n\tfailed to write to DO port!\n");
-            exit(EXIT_FAILURE);
+            QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
+            emit(writeToLogFile("ERROR: unable to TriggerDO on NIDAQ", qry_port_bit, (qry_port_bit & daq->do_bit_wrt) == qry_port_bit, timeString));
+            return;
         }
 
         /* arm time out if required */
         if ((daq->do_clk != 0) & (arm_timer == TRUE))
         {
 
-            DAQmxErrChk(DAQmxIsTaskDone(daq->do_clk, &done));
+            errorCheck(DAQmxIsTaskDone(daq->do_clk, &done));
             daq->do_bit_qry = (done) ? qry_port_bit : (daq->do_bit_qry | qry_port_bit);
-            DAQmxErrChk(DAQmxStopTask(daq->do_clk));
-            DAQmxErrChk(DAQmxStartTask(daq->do_clk));
+            errorCheck(DAQmxStopTask(daq->do_clk));
+            errorCheck(DAQmxStartTask(daq->do_clk));
         }
         /* log trigger */
         QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
@@ -231,23 +239,25 @@ void NIDAQmxInterface::DAQmxSetDO(uInt8 qry_port_bit, bool arm_timer, bool isSet
             }else{
                 daq->do_bit_wrt &= ~(1 << (qry_port_bit-1));
             }
-            DAQmxErrChk(DAQmxWriteDigitalU8(daq->do_port, 1, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->do_bit_wrt, &written, NULL));
+            errorCheck(DAQmxWriteDigitalU8(daq->do_port, 1, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->do_bit_wrt, &written, NULL));
         }
 
         /* check for error */
         if (written == 0)
         {
             fprintf(stderr, "Error::NIDAQmxInterface/DAQmxTriggerDO:\n\tfailed to write to DO port!\n");
-            exit(EXIT_FAILURE);
+            QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
+            emit(writeToLogFile("ERROR: unable to SetDO on NIDAQ", qry_port_bit, (qry_port_bit & daq->do_bit_wrt) == qry_port_bit, timeString));
+            return;
         }
 
         /* arm time out if required */
         if ((daq->do_clk != 0) & (arm_timer == TRUE))
         {
-            DAQmxErrChk(DAQmxIsTaskDone(daq->do_clk, &done));
+            errorCheck(DAQmxIsTaskDone(daq->do_clk, &done));
             daq->do_bit_qry = (done) ? qry_port_bit : (daq->do_bit_qry | qry_port_bit);
-            DAQmxErrChk(DAQmxStopTask(daq->do_clk));
-            DAQmxErrChk(DAQmxStartTask(daq->do_clk));
+            errorCheck(DAQmxStopTask(daq->do_clk));
+            errorCheck(DAQmxStartTask(daq->do_clk));
         }
 
         /* log trigger */
@@ -264,7 +274,7 @@ int32 CVICALLBACK NIDAQmxInterface::FcnCbckDetectDI(TaskHandle taskHandle, int32
     if(!isPaused){
         int32 read = 0;
         if (taskHandle != 0)
-            DAQmxErrChk(DAQmxReadDigitalU8(taskHandle, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->di_bit_now, 1, &read, NULL));
+            errorCheck(DAQmxReadDigitalU8(taskHandle, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->di_bit_now, 1, &read, NULL));
 
         if (read)
         {
@@ -317,14 +327,16 @@ int32 CVICALLBACK NIDAQmxInterface::FcnCbckTriggerStopDO(TaskHandle taskHandle,
         if (daq->do_port != 0)
         {
             daq->do_bit_wrt ^= daq->do_bit_qry;
-            DAQmxErrChk(DAQmxWriteDigitalU8(daq->do_port, 1, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->do_bit_wrt, &written, NULL));
+            errorCheck(DAQmxWriteDigitalU8(daq->do_port, 1, 1, 10.0, DAQmx_Val_GroupByChannel, &daq->do_bit_wrt, &written, NULL));
         }
 
         /* check for error */
         if (written == 0)
         {
             fprintf(stderr, "Error::NIDAQmxInterface/FcnCbckTriggerStopDO: failed to write to DO port!\n");
-            exit(EXIT_FAILURE);
+            QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
+            emit(writeToLogFile("ERROR: unable to set timeout for NIDAQ", 0, 0, timeString));
+            return -1;
         }
 
         /* log trigger */
@@ -333,3 +345,20 @@ int32 CVICALLBACK NIDAQmxInterface::FcnCbckTriggerStopDO(TaskHandle taskHandle,
     }
     return 0;
 }
+
+bool NIDAQmxInterface::errorCheck(int32 functionReturnValue)
+{
+    if((functionReturnValue) < 0){
+        char errBuffer[2048];
+        DAQmxGetExtendedErrorInfo(errBuffer, 2048);
+        qDebug() << errBuffer;
+        QString timeString = QTime::currentTime().toString("hh:mm:ss.zzz");
+        emit(writeToLogFile(QString("ERROR: ").append(errBuffer), 0, 0, timeString));
+
+        //fprintf(stderr, "DAQmxError: %s\n Calling: %s\n", errBuffer, functionReturnValue);
+        return true;
+    }else{
+        return false;
+    }
+
+}
diff --git a/NIDAQmxInterface.h b/NIDAQmxInterface.h
index dc11cfd..956702e 100644
--- a/NIDAQmxInterface.h
+++ b/NIDAQmxInterface.h
@@ -98,6 +98,6 @@ class NIDAQmxInterface: public QObject
     int32 CVICALLBACK FcnCbckTriggerStopDO(TaskHandle, int32);
     friend int32 CVICALLBACK inputCallbackWrapper(TaskHandle taskHandle, int32 signalID, void *callback_dat);
     friend int32 CVICALLBACK pulldownTimerCallbackWrapper(TaskHandle taskHandle, int32 signalID, void *callback_dat);
-
+    bool errorCheck(int32 functionReturnValue);
     #endif /* define (NIDAQmxInterface_h) */
 };