/**
  * \file AOGenerator.cpp
  * \author Blanc.O & Chardes.C
  * \version 0.1
  * \date 11 janvier 2010
  */

#include "aoGenerator.h"

/**
 * @brief aoGenerator::aoGenerator - constructor
 * @param parent
 */
aoGenerator::aoGenerator( QWidget *parent) : QWidget(parent), aiChannelNumber(3)
{
    int32 error;

    qRegisterMetaType<float64>("float64");

    //startGenPB
    startGenPB = new QPushButton("Generate!");
    startGenPB->setCheckable(true);
    startGenPB->setChecked(false);

    //aiRecordPB
    aiRecordPB =  new QPushButton ("Record!");
    aiRecordPB->setCheckable(true);
    aiRecordPB->setChecked(false);
    aiRecordPB->setDisabled(true);

    //zeroGenPB
    zeroGenPB = new QPushButton("reset AOs");

    //onePulsePB
    onePulsePB = new QPushButton("one Pulse!!");

    //samplingRateSB definition
    samplingRateSB = new QSpinBox();
    samplingRateSB->setRange(1, 10000000);//the upper limit  is arbitrary
    samplingRateSB->setValue(1000);
    samplingRateSB->setPrefix("SamplingRate      ");
    samplingRateSB->setSuffix("  samp/sec");

    //bufferSizeSB definition
    bufferSizeSB = new QSpinBox();
    bufferSizeSB->setRange(1, 1000000);//the upper limit  is arbitrary
    bufferSizeSB->setValue(1000);
    bufferSizeSB->setPrefix("bufferSize      ");

    //filename QLineEdit
    fNameE = new QLineEdit();
    fNameE->setText("noFileName");

    //browse Folder widget definition
    browseFolder =  new browseSystemWidget();
    browseFolder->setDefaultFolder("C:/TEMP/");

    console = new qConsole();    

    wfm1 = new waveformMaker(console, samplingRateSB->value(), bufferSizeSB->value());
    wfm2 = new waveformMaker(console, samplingRateSB->value(), bufferSizeSB->value());

    aiParam =  new aiParameters(console);

    aoline = new AOLine(console); // pour aller d'un point A à un point B puis laisser le laser allumer un temps determine

    aoDoubleT = new aoDoubleTweezer(console);

    aiBox = boxIt(aiParam, "AI Parameters");
    aiBox->setChecked(false);
    wfmBox1 = boxIt(wfm1, "Waveform 1 parameters");
    wfmBox2 = boxIt(wfm2, "Waveform 2 parameters");
    lineBox = boxIt(aoline, "Line form parameters");
    doubleTBox = boxIt(aoDoubleT, "Double tweezer parameters");

    lineBox->setChecked(false);
    doubleTBox->setChecked(false);

    QGridLayout *layout = new QGridLayout();
    //ligne0
    layout->addWidget(fNameE, 0, 0 , 1, 1);
    layout->addWidget(samplingRateSB, 0, 1, 1, 2);
    layout->addWidget(bufferSizeSB, 0, 3, 1, 1);\
    //ligne1
    layout->addWidget(browseFolder, 1, 0, 1, 4);
    //ligne2
    layout->addWidget(wfmBox1, 2, 0, 1, 2);
    layout->addWidget(wfmBox2, 2, 2, 1, 2);
    //ligne4
    layout->addWidget(aiBox, 4, 0, 1, 4);
    //ligne 5
    layout->addWidget(lineBox, 5, 0, 1, 4);
    //ligne 6
    layout->addWidget(doubleTBox, 6, 0, 1, 4);
    //ligne 7
    layout->addWidget(startGenPB, 7, 0, 1, 1);
    layout->addWidget(aiRecordPB, 7, 1, 1, 1);
    layout->addWidget(zeroGenPB,  7, 2, 1, 1);
    layout->addWidget(onePulsePB, 7, 3, 1, 1);
    //ligne 8
    layout->addWidget(console, 8, 0, 1, 4);

    setLayout(layout);

    //Global AO Parameters Change
    connect(samplingRateSB, SIGNAL(valueChanged(int)), wfm1, SLOT(setSamplingRate(int)));
    connect(samplingRateSB, SIGNAL(valueChanged(int)), wfm2, SLOT(setSamplingRate(int)));
    connect(bufferSizeSB, SIGNAL(valueChanged(int)), wfm1, SLOT(setBufferSize(int)));
    connect(bufferSizeSB, SIGNAL(valueChanged(int)), wfm2, SLOT(setBufferSize(int)));
    connect(bufferSizeSB, SIGNAL(valueChanged(int)), aoline, SLOT(setBufferSize(int)));

    //pushbutton signals
    connect(startGenPB, SIGNAL(toggled(bool)), this, SLOT(startStopGen(bool)));
    connect(aiRecordPB, SIGNAL(toggled(bool)), this , SLOT(aiRecord(bool)));
    connect(zeroGenPB, SIGNAL(clicked()), this, SLOT(zeroGeneration()));
    connect(onePulsePB, SIGNAL(clicked()), this, SLOT(justOnePulse()));

    connect(aiBox, SIGNAL(clicked(bool)), this, SLOT(test(bool)));

    connect(this, SIGNAL(newD(float64[],int)), this, SLOT(data(float64[],int)));


    //////////////////////////////////////////////////////////////////////////////////////////
    ////DAQMX Initialisation
    //////////////////////////////////////////////////////////////////////////////////////////
    //AO : Analog Output
    //////////////////////////////////////////////////////////////////////////////////////////
    error = DAQmxCreateTask("", &aoTask);
    DAQErrChk (error, "aoTask DAQmxCreateTask");

    //error = DAQmxCreateAOVoltageChan(aoTask, "Dev1/ao0", "", -10.0, 10.0,DAQmx_Val_Volts, NULL);
    error = DAQmxCreateAOVoltageChan(aoTask, "cDAQ1Mod1/ao0", "", -10.0, 10.0,DAQmx_Val_Volts, NULL); // card 1 of the rack : output
    DAQErrChk (error, "aoTask ao0 DAQmxCreateAOVoltageChan");

    //error = DAQmxCreateAOVoltageChan(aoTask, "Dev1/ao1", "", -10.0, 10.0,DAQmx_Val_Volts, NULL);
    error = DAQmxCreateAOVoltageChan(aoTask, "cDAQ1Mod1/ao1", "", -10.0, 10.0,DAQmx_Val_Volts, NULL); // card 1 of the rack : output
    DAQErrChk (error, "aoTask ao1 DAQmxCreateAOVoltageChan");


    //AI : Analog Input 3 channel
    //////////////////////////////////////////////////////////////////////////////////////////
    error = DAQmxCreateTask("", &aiTask);
    DAQErrChk (error, "aiTask DAQmxCreateTask");

    //error = DAQmxCreateAIVoltageChan(aiTask, "Dev1/ai0", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL);
    error = DAQmxCreateAIVoltageChan(aiTask, "cDAQ1Mod2/ai0", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL);  // card 3 of the rack : input
    DAQErrChk (error, "aiTask ai0 DAQmxCreateAIVoltageChan");

    //error = DAQmxCreateAIVoltageChan(aiTask, "Dev1/ai1", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL);
    error = DAQmxCreateAIVoltageChan(aiTask, "cDAQ1Mod2/ai1", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL); // card 3 of the rack : input
    DAQErrChk (error, "aiTask ai1 DAQmxCreateAIVoltageChan");

    //error = DAQmxCreateAIVoltageChan(aiTask, "Dev1/ai2", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL);
    error = DAQmxCreateAIVoltageChan(aiTask, "cDAQ1Mod2/ai2", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL); // card 3 of the rack : input
    DAQErrChk (error, "aiTask ai2 DAQmxCreateAIVoltageChan");

    //error = DAQmxCreateAIVoltageChan(aiTask, "Dev1/ai3", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL);
    error = DAQmxCreateAIVoltageChan(aiTask, "cDAQ1Mod2/ai3", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL); // card 3 of the rack : input
    DAQErrChk (error, "aiTask ai3 DAQmxCreateAIVoltageChan");

//    error = DAQmxCreateAIVoltageChan(aiTask, "Dev1/ai4", "",DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL);
//    DAQErrChk (error, "aiTask ai3 DAQmxCreateAIVoltageChan");


    //CO : Counter output, are used to control the shutter
    //////////////////////////////////////////////////////////////////////////////////////////
    //startCOTask counter (trig AItask start)
    error = DAQmxCreateTask("", &scoTask);
    DAQErrChk (error, "scoTask DAQmxCreateTask");

    // changer PFI1 en _ctr1
    error = DAQmxConnectTerms ("/cDAQ1/Ctr1InternalOutput", "/cDAQ1/PFI1", DAQmx_Val_DoNotInvertPolarity);

    //DAQmxCreateCOPulseChanTime (scoTask, "Dev1/ctr0", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0,0.01, 0.01);
    error = DAQmxCreateCOPulseChanTime(scoTask, "cDAQ1/_ctr1", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0,0.01, 0.01);
    DAQErrChk (error, "scoTask  DAQmxCreateCOPulseChanTime");

    DAQmxCfgImplicitTiming (scoTask, DAQmx_Val_FiniteSamps, 1);
    DAQErrChk (error, "startCOTask  DAQmxCfgImplicitTiming");

    //coTask : generate one pulse, used for continuous generation pulse
    error = DAQmxCreateTask("", &coTask);
    DAQErrChk (error, "coTask DAQmxCreateTask");

    //DAQmxCreateCOPulseChanTime (coTask, "Dev1/ctr0", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0,0.01, 0.01);
    error = DAQmxCreateCOPulseChanTime (coTask, "cDAQ1/_ctr1", "", DAQmx_Val_Seconds, DAQmx_Val_Low, 0,0.01, 0.01);
    DAQErrChk (error, "coTask  DAQmxCreateCOPulseChanTime");

    DAQmxCfgImplicitTiming (coTask, DAQmx_Val_FiniteSamps, 1);
    DAQErrChk (error, "coTask  DAQmxCfgImplicitTiming");


    // read image/laser position table for correspondance between image position and laser position
    QFile mFile(FILENAMEPOSITION);
    if (!mFile.open(QIODevice::ReadOnly | QIODevice::Text))
     qDebug()<<"file does not exist";
    else
    {
        QTextStream in(&mFile);
        QString mText ;
        QStringList list;
        x  = new float[NBLINEINFILENAMEPOSITION];
        y  = new float[NBLINEINFILENAMEPOSITION];
        Vx = new float[NBLINEINFILENAMEPOSITION];
        Vy = new float[NBLINEINFILENAMEPOSITION];

        for (int i=0;i<NBLINEINFILENAMEPOSITION;i++)
        {
            mText = in.readLine();
            list = mText.split(QRegExp("\\s+"));
            x[i] = list.value(0).toFloat();
            y[i] =list.value(1).toFloat();
            Vx[i]=list.value(2).toFloat();
            Vy[i]=list.value(3).toFloat();
            list.clear();

        }
        mFile.close();
    }
}

/**
 * @brief aoGenerator::~aoGenerator - destructor
 */
aoGenerator::~aoGenerator()
{
}

/**
 * @brief aoGenerator::boxIt
 * @param wToBox
 * @param header
 * @return
 */
QGroupBox *aoGenerator::boxIt(QWidget *wToBox, QString header)
{
    QGroupBox *box = new QGroupBox (header);
    box->setCheckable(true);
    box->setChecked(true);
    QGridLayout  *grid = new QGridLayout();
    grid->addWidget(wToBox, 0, 0, 1, 1);
    box->setLayout(grid);

    return box;
}

/**
 * @brief aoGenerator::startStopGen
 * @param state
 */
void aoGenerator::startStopGen(bool state)
{        
    int32 error;
    if (state) //start generation
    {                 
        zeroGenPB->setDisabled(true);
        startGenPB->setText("Generating!");

        int bSize = bufferSizeSB->value();
        float64 *buffer;
        float64 buffer1[2*bufferSizeSB->value()];

        if (lineBox->isChecked())
        {
            aoline->setBufferSize(bSize);
            buffer = aoline->makeBuffer();
            qDebug()<<"aoline asked !";
            for (int i=0;i<2*bSize;i++)
            {
                buffer1[i]=buffer[i];
                qDebug()<<buffer1[i];
            }

            //AO clock
            error = DAQmxCfgSampClkTiming (aoTask, "",float64(samplingRateSB->value()),
                                           DAQmx_Val_Rising, DAQmx_Val_FiniteSamps,int64(bSize));
            DAQErrChk (error, "ao DAQmxCfgSampClkTiming");

            //AO buffer writting
            error = DAQmxWriteAnalogF64 (aoTask, int32(bSize), 0, 10.0, DAQmx_Val_GroupByChannel, buffer1, NULL, NULL);
            DAQErrChk (error, " ao DAQmxWriteAnalogF64");

            //Start coTask =>open the shutter if it's close
            justOnePulse();

            //start AO task
            error = DAQmxStartTask(aoTask);
            DAQErrChk (error, " aoTask DAQmxStartTask");

            // wait until task done
            error = DAQmxWaitUntilTaskDone(aoTask, float64(10));
            error = DAQmxStopTask(aoTask);

            // wait delay time before close the shutter
            Sleep(aoline->delayLaser); //milliseconds
            // stop generation & update status
            startGenPB->click();

            // verifier que le laser est allumé durant la translation et s'eteint à la fin après le délai choisi
        }
        else
        {
            if (doubleTBox->isChecked())
            {
                aoDoubleT->setBufferSize(bSize);
                qDebug()<<"double tweezer !";
                buffer = aoDoubleT->makeBuffer();
                for (int i = 0; i<2*bSize; i++)
                {
                    buffer1[i] = buffer[i];
                }
            }
            else
            {
                qDebug()<<"wfm1 !";
                if (wfmBox1->isChecked())//wfm1 required
                {
                    buffer = wfm1->makeBuffer(buffer);
                    for (int i = 0 ; i<bSize; i++)
                    {
                        buffer1[i] = buffer[i];
                    }
                }
                else//wfm1 mute
                {
                    for (int i = 0 ; i<bSize; i++)
                    {
                        buffer1[i] = 0;
                    }
                }

                //fill ao2 buffer
                if (wfmBox2->isChecked())//wfm2 required
                {
                    qDebug()<<"wfm2 !";
                    buffer = wfm2->makeBuffer(buffer);
                    for (int i = 0 ; i<bSize; i++)
                    {
                        buffer1[i+bSize] = buffer[i];
                    }
                }
                else//wfm2 mute
                {
                    for (int i = 0 ; i<bSize; i++)
                    {
                        buffer1[i+bSize] = 0;
                    }
                }

            }

            //AO clock
            error = DAQmxCfgSampClkTiming (aoTask, "",float64(samplingRateSB->value()),
                                           DAQmx_Val_Rising, DAQmx_Val_ContSamps,
                                           int64(bufferSizeSB->value()));
            DAQErrChk (error, "ao DAQmxCfgSampClkTiming");


            //AO buffer writting
            error = DAQmxWriteAnalogF64 (aoTask, int32(bufferSizeSB->value()),
                                         0, 10.0, DAQmx_Val_GroupByChannel, buffer1, NULL, NULL);
            DAQErrChk (error, " ao DAQmxWriteAnalogF64");

            //Start coTask =>open the shutter if it's close
            justOnePulse();

            //start AO task
            error = DAQmxStartTask(aoTask);
            DAQErrChk (error, " aoTask DAQmxStartTask");

        }

    }
    else //stop generation
    {
        qDebug()<<"stop generation";
        //Start coTask =>close the shutter if it's open
        justOnePulse();

        //stop aoTask
        error = DAQmxStopTask(aoTask);
        DAQErrChk (error, "aoTask DAQmxStopTask");

        //update GUI
        zeroGenPB->setDisabled(false);
        startGenPB->setText("Generate!");
    }
}

/**
 * @brief aoGenerator::aiRecord
 * @param state
 */
void aoGenerator::aiRecord(bool state)
{
    int32 error = 0;
    if (state)// start recording
    {
        this->aiChannelNumber = aiParam->getNChannels();
        makeHeader();

        if (aiParam->getWait4it())
        {
            //PFI0 input trigs AI
            //error = DAQmxCfgDigEdgeStartTrig(aiTask, "/Dev1/PFI0", DAQmx_Val_Rising);
            error = DAQmxCfgDigEdgeStartTrig(aiTask, "/cDAQ1/PFI0", DAQmx_Val_Rising);
            DAQErrChk (error, "DAQmxCfgDigEdgeStartTrig");

        }
        else
        {
            //disconnet the AI start from SCO trigger!
            error = DAQmxDisableStartTrig (aiTask);
            DAQErrChk (error, "aoTask DAQmxDisableStartTrig");
        }

        //AI clock
        error = DAQmxCfgSampClkTiming (aiTask, "",float64(aiParam->getSamplingRate()),
                                       DAQmx_Val_Rising, DAQmx_Val_ContSamps,
                                       int64(aiParam->getBufferSize()));
        DAQErrChk (error, "DAQmxCfgSampClkTiming");

        //link EveryncallBack with aiTask
        error = DAQmxRegisterEveryNSamplesEvent(aiTask, DAQmx_Val_Acquired_Into_Buffer
                                                , aiParam->getBufferSize(), 0, EveryNCallback, this);
        DAQErrChk (error, "DAQmxRegisterEveryNSamplesEvent");

        //start AI task
        error = DAQmxStartTask(aiTask);
        DAQErrChk (error, "aiTask DAQmxStartTask");
        aiRecordPB->setText("Stop!");
    }
    else //stop recording
    {
        //stop aiTask
        error = DAQmxStopTask(aiTask);
        DAQErrChk (error, "aiTask DAQmxStopTask");

        //unlink EveryncallBack with aiTask
        error = DAQmxRegisterEveryNSamplesEvent(aiTask, DAQmx_Val_Acquired_Into_Buffer
                                                , aiParam->getBufferSize()
                                                , 0, NULL, this);
        DAQErrChk (error, "DAQmxRegisterEveryNSamplesEvent");

        aiRecordPB->setText("Record");
    }

}

/**
 * @brief aoGenerator::zeroGeneration -  function used to generate a small buffer fill of Zeros in order to AOs voltage do ZEROS!
 */
void aoGenerator::zeroGeneration()
{

    // on lit la valeur pour x et y dans le fichier commun avec microrheo et on met a jour la valeur de l offset.
    // il faut faire la correspondance entre x,y de l image et Vx,Vy des galvos
    // si le fichier n existe pas, on met la valeur de l offset a zero

    QFile mFile(FILENAME);
    float64 xvalue;
    float64 yvalue;
    if(!mFile.open(QFile::ReadOnly | QFile::Text))
    {
        qDebug() << "could not open file for read";
        xvalue = 0;
        yvalue = 0;
    }
    else
    {
        QTextStream in(&mFile);
        QString mText ;
        mText = in.readLine();
        xvalue = mText.toDouble();
        mText = in.readLine();
        yvalue = mText.toDouble();
        qDebug()<<xvalue<<" "<<yvalue;
        *console<<"\r"<<xvalue<<" "<<yvalue<<"\r";
        mFile.close();
    }

    // on doit maintenant trouver le plus proche point x,y pour avoir Vx,Vy
    double dist = 512;
    int ind = 0;
    for (int i=0;i<NBLINEINFILENAMEPOSITION;i++)
    {
        if (sqrt((x[i]-xvalue)*(x[i]-xvalue)+(y[i]-yvalue)*(y[i]-yvalue))<dist)
        {
            dist = sqrt((x[i]-xvalue)*(x[i]-xvalue)+(y[i]-yvalue)*(y[i]-yvalue));
            ind = i;
        }
    }

    xvalue = Vx[ind]; // tant qu'on a pas etablie correspondance entre x et Vx
    yvalue = Vy[ind];

    qDebug()<<x[ind]<<" "<<y[ind]<<"\rtensions"<<xvalue<<yvalue;
    *console<<x[ind]<<" "<<y[ind]<<"\r";//"tensions"<<xvalue<<" "<<yvalue<<"\r";

    // update x and y offset
    wfm1->offsetSB->setValue(xvalue);
    wfm2->offsetSB->setValue(yvalue);


    startGenPB->setDisabled(true);
    int32 error = 0;

    int64 bsize = 100;
    float64 buffer[2*bsize];
    for (int i = 0 ; i<bsize; i++)
    {
        buffer[i] = xvalue; //0 instead of value
        buffer[i+bsize] = yvalue;
    }
    //AO clock
    error = DAQmxCfgSampClkTiming (aoTask, "",float64(10000),
                                   DAQmx_Val_Rising, DAQmx_Val_ContSamps,//DAQmx_Val_FiniteSamps,
                                   bsize);
        DAQErrChk (error, "ao DAQmxCfgSampClkTiming");
    //AO buffer writting
    error = DAQmxWriteAnalogF64 (aoTask, int32(bsize),
                                 0, 10.0, DAQmx_Val_GroupByChannel, buffer, NULL, NULL);
        DAQErrChk (error, " ao DAQmxWriteAnalogF64");
    // start aotask
    error = DAQmxStartTask(aoTask);
        DAQErrChk (error, " aoTask DAQmxStartTask");

    //stop aoTask
    error = DAQmxStopTask(aoTask);
        DAQErrChk (error, "aoTask DAQmxStopTask");

    // update GUI
    startGenPB->setDisabled(false);
}

/**
 * @brief aoGenerator::justOnePulse - Generate one small 5V TTL pulse throught CTR 0 output. invert the state of the shutter!
 */
void aoGenerator::justOnePulse()
{
    int error;
    error = DAQmxStartTask(coTask);
    DAQErrChk(error, "coTask : DAQmxStartTask");
}

/**
 * @brief aoGenerator::GetTerminalNameWithDevPrefix - function needed by NI in order to build the trigger wich is then used to start AO start
 * @param taskHandle
 * @param terminalName
 * @param triggerName
 */
void aoGenerator::GetTerminalNameWithDevPrefix(TaskHandle taskHandle, const char terminalName[], char triggerName[])
{
    int32 error = 0;
    char device[256];
    int32 productCategory;
    uInt32 numDevices, i = 1;

    error = DAQmxGetTaskNumDevices (taskHandle, &numDevices);
        DAQErrChk (error, "DAQmxGetTaskNumDevices");
    while (i <= numDevices)
    {
        error = DAQmxGetNthTaskDevice (taskHandle, i++, device, 256);
            DAQErrChk (error, "DAQmxGetNthTaskDevice");
        error = DAQmxGetDevProductCategory (device, &productCategory);
            DAQErrChk (error, "DAQmxGetDevProductCategory");
        if (productCategory != DAQmx_Val_CSeriesModule && productCategory != DAQmx_Val_SCXIModule)
        {
            *triggerName++ = '/';
            strcat(strcat(strcpy(triggerName, device), "/"), terminalName);
            break;
        }
    }
}

/**
 * @brief aoGenerator::data
 * @param aiBuffer
 * @param bSize
 */
void aoGenerator::data(float64 aiBuffer[], int bSize)
{
    *console<<"newData\n";
}


/**
  * @brief
  */
int32 CVICALLBACK aoGenerator::EveryNCallback(TaskHandle taskHandle, int32 EveryNsamplesEventType, uInt32 nSamples, void * callbackData)
{
    aoGenerator* gen = (aoGenerator*) callbackData;
    
    int nbC = gen->aiChannelNumber;
    int32 error = 0;
    char errBuff[2048] = {'\n'};
    int32 readAI;
    float64 AIdata[nSamples*nbC];//nSamples
    qDebug()<<"nSample"<<nSamples;

    error = DAQmxReadAnalogF64 (taskHandle, nSamples,10.0, DAQmx_Val_GroupByChannel, AIdata
                                , nSamples*nbC, &readAI, NULL);
    if (error!=0)
    {
        DAQmxGetExtendedErrorInfo(errBuff, 2048);
        qDebug()<<errBuff<<"\n";
    }
    else
    {
        QFile file(*gen->fileName);
        file.open(QIODevice::Append | QIODevice::Text);
        QTextStream out(&file);
        for (uint i = 0; i < nSamples; i++)
        {
            for (int j = 0 ; j<nbC ; j++)
            {
                out<< AIdata[i+j*nSamples]<<"\t";
            }
            out<<"\n";
        }
        file.close();
    }
    return(0);
}


/**
 * @brief aoGenerator::getAIHandle
 * @return
 */
TaskHandle aoGenerator::getAIHandle()
{
    return (aiTask);
}

/**
 * @brief aoGenerator::getSCOHandle
 * @return
 */
TaskHandle aoGenerator::getSCOHandle()
{
    return (scoTask);
}

/**
 * @brief aoGenerator::getCOHandle
 * @return
 */
TaskHandle aoGenerator::getCOHandle()
{
    return (coTask);
}

/**
 * @brief aoGenerator::NCB
 */
void aoGenerator::NCB()
{
    qDebug()<<"\tnCallback!!\t";
}

/**
 * @brief aoGenerator::aiDCB
 * @return
 */
int32 aoGenerator::aiDCB()
{
    int error;
    qDebug()<<"it's here!!\n";
    justOnePulse();
    startGenPB->click();
    //unlink EveryncallBack with aiTask
    error = DAQmxRegisterEveryNSamplesEvent(aiTask, DAQmx_Val_Acquired_Into_Buffer
                                            , aiParam->getBufferSize()
                                            , 0, NULL, this);
    DAQErrChk (error, "DAQmxRegisterEveryNSamplesEvent");
    return(error);
}

/**
 * @brief aoGenerator::scoDCB
 * @return
 */
int32 aoGenerator::scoDCB()
{
    int error;
    //stop coTask
    error = DAQmxStopTask(scoTask);
    DAQErrChk (error, "scoTask DAQmxStopTask");
    return(error);

}

/**
 * @brief aoGenerator::coDCB
 * @return
 */
int32 aoGenerator::coDCB()
{
    int error;
    //stop coTask
    error = DAQmxStopTask(coTask);
    DAQErrChk (error, "coTask DAQmxStopTask");
    return(error);
}

/**
 * @brief aoGenerator::DAQErrChk
 * @param DAQError
 * @param fctName
 */
void aoGenerator::DAQErrChk(int32 DAQError, QString fctName)
{
    char errorBuffer[2048];
    if (DAQError != 0)
    {
        DAQmxGetExtendedErrorInfo(errorBuffer, 2048);
        *console<<"\n"<<fctName<<" : "<<errorBuffer;
    }
}

/**
 * @brief aoGenerator::makeHeader
 */
void aoGenerator::makeHeader()
{    
    QMap<QString, QString> map;
    QMapIterator<QString, QString> i(map);

    QDateTime timeCoord = QDateTime::currentDateTime();

    fileName = new QString(".txt");
    fileName->prepend(fNameE->text());
    fileName->prepend(timeCoord.toString("yyyyMMdd_hhmmss_"));
    fileName->prepend("/");
    fileName->prepend(browseFolder->getPath());
//    fileName->append(fNameE->text());

    file = new QFile(*fileName);
    file->open(QIODevice::WriteOnly | QIODevice::Text);
    QTextStream out(file);//out = new QTextStream(file);

    // Header writing
    // Filename date and time
    out <<fileName->toAscii()<<"\t"<<timeCoord.toString("dd/MM/yyyy")<<"\t"<<timeCoord.toString("hh:mm:ss")<<"\n";
    //AI
    out<<"Analog inputs";
    out<<"nbAIChannels->"<<aiParam->getNChannels()<<"\n";
    out<<"AIsamplingRate->"<<aiParam->getSamplingRate()<<"\n";

    //AO
    out<<"HEADER\n";
    out<<"Analog inputs\n";
    out<<"nAIChannel->"<<this->aoChannelNumber<<"\n\n";

    out<<"Analog outputs\n";
    out<<"AOsamplingRate->"<<samplingRateSB->value()<<"\n\n";
    out<<"AO1\n";

    wfm1->getWFParameters(map);
    i = map;
    while (i.hasNext())
    {
        i.next();
        out<<i.key()<<"->"<<i.value()<<"\n";
    }

    map.clear();

    out<<"\nAO2\n";
    wfm2->getWFParameters(map);
    i=map;
    while (i.hasNext())
    {
        i.next();
        out<<i.key()<<"->"<<i.value()<<"\n";
    }

    out<<"\nDATA\n";
    file ->close();
}

/**
 * @brief aoGenerator::test
 * @param state
 */
void aoGenerator::test(bool state)
{
    if (state)// no record
    {
        aiRecordPB->setDisabled(false);
    }
    else // record allowed
    {
        aiRecordPB->setDisabled(true);
    }
}


