<commit_before>//=============================================================================================================
/**
* @file     main.cpp
* @author   Lorenz Esch <lorenz.esch@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     April, 2019
*
* @section  LICENSE
*
* Copyright (C) 2019, Lorenz Esch and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Example of using the MNE-CPP Connectivity library
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <connectivity/connectivity.h>
#include <connectivity/connectivitysettings.h>
#include <connectivity/network/network.h>
#include <connectivity/metrics/abstractmetric.h>

#include <fiff/fiff_raw_data.h>

#include <utils/ioutils.h>

#include <mne/mne_epoch_data_list.h>
#include <mne/mne.h>

#include <stdio.h>

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QDebug>
#include <QFile>
#include <QDateTime>
#include <QDir>
#include <QCoreApplication>
#include <QHostInfo>
#include <QElapsedTimer>
#include <QThreadPool>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace Eigen;
using namespace FIFFLIB;
using namespace CONNECTIVITYLIB;
using namespace Eigen;
using namespace UTILSLIB;
using namespace MNELIB;

//*************************************************************************************************************
//=============================================================================================================
// Global Defines
//=============================================================================================================

QString m_sCurrentDir;
int m_iCurrentIteration = 0;
int m_iNumberTrials;
int m_iNumberChannels;
int m_iNumberSamples;

void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    Q_UNUSED(context);

    QString dt = QDateTime::currentDateTime().toString("dd/MM/yyyy hh:mm:ss");
    QString txt;// = QString("[%1] ").arg(dt);

    bool writeToLog = false;

    switch (type) {
        case QtWarningMsg:
            //txt += QString("{Warning} \t %1").arg(msg);
            txt += QString("%1").arg(msg);
            writeToLog=true;
            break;
    }

    if(!writeToLog) {
        return;
    }

    QString sFileName = m_sCurrentDir + "/" + QString::number(m_iNumberChannels) + "_" + QString::number(m_iNumberSamples) + "_" + QString::number(m_iNumberTrials) + ".log";

    QFile outFile(sFileName);
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);

    QTextStream textStream(&outFile);
    textStream << txt << endl;
}

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/
int main(int argc, char *argv[])
{
    qInstallMessageHandler(customMessageHandler);

//    printf("globalInstance()->maxThreadCount(): %d\n",QThreadPool::globalInstance()->maxThreadCount());
//    QThreadPool::globalInstance()->setMaxThreadCount(24);

    //Parameters for performance test
    QStringList sConnectivityMethodList = QStringList() << "COR" << "XCOR" << "COH" << "IMAGCOH" << "PLI" << "WPLI" << "USPLI" << "DSWPLI" << "PLV";
    QList<int> lNumberTrials = QList<int>() << 1 << 5 << 10 << 20 << 50 << 100 << 200;
    QList<int> lNumberChannels = QList<int>() << 32 << 64 << 128 << 256;
    QList<int> lNumberSamples = QList<int>() << 100 << 200 << 300 << 400 << 500 << 600 << 700 << 800 << 900 << 1000 << 2000 << 3000 << 4000 << 5000 << 6000 << 7000 << 8000 << 9000 << 10000 << 20000 << 30000 << 40000 << 50000 << 60000 << 70000 << 80000 << 90000 << 100000;

    int iNumberRepeats = 5;
    int iStorageModeActive = 0;

    AbstractMetric::m_bStorageModeIsActive = iStorageModeActive;
    AbstractMetric::m_iNumberBinStart = 8;
    AbstractMetric::m_iNumberBinAmount = 4;

    // Create sensor level data
    QElapsedTimer timer;
    qint64 iTime = 0;
    timer.start();

    QString sRaw = "/cluster/fusion/lesch/Git/mne-cpp-lorenze/bin/MNE-sample-data/MEG/sample/sample_audvis_raw.fif";
    MatrixXd matDataOrig, matData;
    MatrixXd times;
    QFile t_fileRaw(sRaw);
    FiffRawData raw(t_fileRaw);

    raw.read_raw_segment(matDataOrig, times, raw.first_samp, raw.first_samp+100001);

    //Perform connectivity performance tests
    Connectivity connectivityObj;

    ConnectivitySettings connectivitySettings;
    connectivitySettings.setSamplingFrequency(raw.info.sfreq);
    connectivitySettings.setWindowType("hanning");

    QMap<int, QMap<int, MatrixXd > > matInputData;

    for(int j = 0; j < lNumberChannels.size(); ++j) {
        QMap<int, MatrixXd > mapChannelsSamples;

        for(int i = 0; i < lNumberSamples.size(); ++i) {
            mapChannelsSamples[lNumberSamples.at(i)] = matDataOrig.block(0,0,lNumberChannels.at(j), lNumberSamples.at(i));
        }

        matInputData[lNumberChannels.at(j)] = mapChannelsSamples;
    }

    iTime = timer.elapsed();
    qDebug() << "Prepare data " << iTime;
    timer.restart();

    qWarning() << "matInputData[256][40000].first().rows()" << matInputData[256][40000].rows();
    qWarning() << "matInputData[256][40000].first().cols()" << matInputData[256][40000].cols();
    qWarning() << "matInputData[32][500].rows()" << matInputData[32][500].rows();
    qWarning() << "matInputData[32][500].cols()" << matInputData[32][500].cols();
    qWarning() << "matInputData[64][100000].rows()" << matInputData[64][100000].rows();
    qWarning() << "matInputData[64][100000].cols()" << matInputData[64][100000].cols();

    for(int j = 0; j < lNumberSamples.size(); ++j) {
        for(int k = 0; k < lNumberChannels.size(); ++k) {
            connectivitySettings.clearAllData();

            matData = matInputData[lNumberChannels.at(k)][lNumberSamples.at(j)];

            RowVectorXi picks = RowVectorXi::LinSpaced(lNumberChannels.at(k),1,lNumberChannels.at(k)+1);
            connectivitySettings.setNodePositions(raw.info, picks);

            for(int l = 0; l < lNumberTrials.size(); ++l) {
                //Create data to work on

                while(connectivitySettings.size() < lNumberTrials.at(l)) {
                    connectivitySettings.append(matData);
                }

                for(int i = 0; i < sConnectivityMethodList.size(); ++i) {
                    m_iNumberTrials = lNumberTrials.at(l);
                    m_iNumberChannels = lNumberChannels.at(k);
                    m_iNumberSamples = lNumberSamples.at(j);

                    //Create new folder
                    m_sCurrentDir = QString("/cluster/fusion/lesch/connectivity_performance_%1_%2_%3/%4/%5_%6_%7").arg(QHostInfo::localHostName()).arg(AbstractMetric::m_iNumberBinAmount).arg(iStorageModeActive).arg(sConnectivityMethodList.at(i)).arg(QString::number(lNumberChannels.at(k))).arg(QString::number(lNumberSamples.at(j))).arg(QString::number(lNumberTrials.at(l)));
                    QDir().mkpath(m_sCurrentDir);

                    //Write basic information to file
                    qWarning() << "sConnectivityMethod" << sConnectivityMethodList.at(i);
                    qWarning() << "sRaw" << sRaw;
                    qWarning() << "storageModeActive" << iStorageModeActive;
                    qWarning() << "iNumberSamples" << lNumberSamples.at(j);
                    qWarning() << "iNumberChannels" << lNumberChannels.at(k);
                    qWarning() << "iNumberTrials" << lNumberTrials.at(l);
                    qWarning() << "iNumberCSDFreqBins" << AbstractMetric::m_iNumberBinAmount;
                    qWarning() << "rows" << matData.rows();
                    qWarning() << "cols" << matData.cols();
                    qWarning() << "numberNodes" << connectivitySettings.getNodePositions().rows();

                    // Check that iNfft >= signal length
                    int iSignalLength = lNumberSamples.at(j);
                    int iNfft = int(raw.info.sfreq/1.0);
                    if(iNfft > iSignalLength) {
                        iNfft = iSignalLength;
                    }

                    qWarning() << "iNfft" << iNfft;

                    int iNFreqs = int(floor(iNfft / 2.0)) + 1;
                    qWarning() << "iNFreqs" << iNFreqs;

                    connectivitySettings.setConnectivityMethods(QStringList() << sConnectivityMethodList.at(i));

                    m_iCurrentIteration = 0;
                    for(int u = 0; u < iNumberRepeats; ++u) {
                        connectivitySettings.clearIntermediateData();

                        qWarning() << "iteration" << m_iCurrentIteration;

                        //Do connectivity estimation
                        connectivityObj.calculate(connectivitySettings);

                        printf("Iteration %d: Calculating %s for %d trials, %d channels, %d samples\n", m_iCurrentIteration, sConnectivityMethodList.at(i).toLatin1().data(), connectivitySettings.size(), lNumberChannels.at(k), lNumberSamples.at(j));

                        m_iCurrentIteration++;
                    }
                }
            }
        }
    }

    return 0;
}
<commit_msg>added check for function successfully reading file -- cov206043<commit_after>//=============================================================================================================
/**
* @file     main.cpp
* @author   Lorenz Esch <lorenz.esch@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     April, 2019
*
* @section  LICENSE
*
* Copyright (C) 2019, Lorenz Esch and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Example of using the MNE-CPP Connectivity library
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <connectivity/connectivity.h>
#include <connectivity/connectivitysettings.h>
#include <connectivity/network/network.h>
#include <connectivity/metrics/abstractmetric.h>

#include <fiff/fiff_raw_data.h>

#include <utils/ioutils.h>

#include <mne/mne_epoch_data_list.h>
#include <mne/mne.h>

#include <stdio.h>

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QDebug>
#include <QFile>
#include <QDateTime>
#include <QDir>
#include <QCoreApplication>
#include <QHostInfo>
#include <QElapsedTimer>
#include <QThreadPool>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace Eigen;
using namespace FIFFLIB;
using namespace CONNECTIVITYLIB;
using namespace Eigen;
using namespace UTILSLIB;
using namespace MNELIB;

//*************************************************************************************************************
//=============================================================================================================
// Global Defines
//=============================================================================================================

QString m_sCurrentDir;
int m_iCurrentIteration = 0;
int m_iNumberTrials;
int m_iNumberChannels;
int m_iNumberSamples;

void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    Q_UNUSED(context);

    QString dt = QDateTime::currentDateTime().toString("dd/MM/yyyy hh:mm:ss");
    QString txt;// = QString("[%1] ").arg(dt);

    bool writeToLog = false;

    switch (type) {
        case QtWarningMsg:
            //txt += QString("{Warning} \t %1").arg(msg);
            txt += QString("%1").arg(msg);
            writeToLog=true;
            break;
    }

    if(!writeToLog) {
        return;
    }

    QString sFileName = m_sCurrentDir + "/" + QString::number(m_iNumberChannels) + "_" + QString::number(m_iNumberSamples) + "_" + QString::number(m_iNumberTrials) + ".log";

    QFile outFile(sFileName);
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);

    QTextStream textStream(&outFile);
    textStream << txt << endl;
}

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/
int main(int argc, char *argv[])
{
    qInstallMessageHandler(customMessageHandler);

//    printf("globalInstance()->maxThreadCount(): %d\n",QThreadPool::globalInstance()->maxThreadCount());
//    QThreadPool::globalInstance()->setMaxThreadCount(24);

    //Parameters for performance test
    QStringList sConnectivityMethodList = QStringList() << "COR" << "XCOR" << "COH" << "IMAGCOH" << "PLI" << "WPLI" << "USPLI" << "DSWPLI" << "PLV";
    QList<int> lNumberTrials = QList<int>() << 1 << 5 << 10 << 20 << 50 << 100 << 200;
    QList<int> lNumberChannels = QList<int>() << 32 << 64 << 128 << 256;
    QList<int> lNumberSamples = QList<int>() << 100 << 200 << 300 << 400 << 500 << 600 << 700 << 800 << 900 << 1000 << 2000 << 3000 << 4000 << 5000 << 6000 << 7000 << 8000 << 9000 << 10000 << 20000 << 30000 << 40000 << 50000 << 60000 << 70000 << 80000 << 90000 << 100000;

    int iNumberRepeats = 5;
    int iStorageModeActive = 0;

    AbstractMetric::m_bStorageModeIsActive = iStorageModeActive;
    AbstractMetric::m_iNumberBinStart = 8;
    AbstractMetric::m_iNumberBinAmount = 4;

    // Create sensor level data
    QElapsedTimer timer;
    qint64 iTime = 0;
    timer.start();

    QString sRaw = "/cluster/fusion/lesch/Git/mne-cpp-lorenze/bin/MNE-sample-data/MEG/sample/sample_audvis_raw.fif";
    MatrixXd matDataOrig, matData;
    MatrixXd times;
    QFile t_fileRaw(sRaw);
    FiffRawData raw(t_fileRaw);

    bool readSuccessful = false;

    readSuccessful = raw.read_raw_segment(matDataOrig, times, raw.first_samp, raw.first_samp+100001);

    if (!readSuccessful) {
        qDebug() << "Could not read raw segment.";
    }

    //Perform connectivity performance tests
    Connectivity connectivityObj;

    ConnectivitySettings connectivitySettings;
    connectivitySettings.setSamplingFrequency(raw.info.sfreq);
    connectivitySettings.setWindowType("hanning");

    QMap<int, QMap<int, MatrixXd > > matInputData;

    for(int j = 0; j < lNumberChannels.size(); ++j) {
        QMap<int, MatrixXd > mapChannelsSamples;

        for(int i = 0; i < lNumberSamples.size(); ++i) {
            mapChannelsSamples[lNumberSamples.at(i)] = matDataOrig.block(0,0,lNumberChannels.at(j), lNumberSamples.at(i));
        }

        matInputData[lNumberChannels.at(j)] = mapChannelsSamples;
    }

    iTime = timer.elapsed();
    qDebug() << "Prepare data " << iTime;
    timer.restart();

    qWarning() << "matInputData[256][40000].first().rows()" << matInputData[256][40000].rows();
    qWarning() << "matInputData[256][40000].first().cols()" << matInputData[256][40000].cols();
    qWarning() << "matInputData[32][500].rows()" << matInputData[32][500].rows();
    qWarning() << "matInputData[32][500].cols()" << matInputData[32][500].cols();
    qWarning() << "matInputData[64][100000].rows()" << matInputData[64][100000].rows();
    qWarning() << "matInputData[64][100000].cols()" << matInputData[64][100000].cols();

    for(int j = 0; j < lNumberSamples.size(); ++j) {
        for(int k = 0; k < lNumberChannels.size(); ++k) {
            connectivitySettings.clearAllData();

            matData = matInputData[lNumberChannels.at(k)][lNumberSamples.at(j)];

            RowVectorXi picks = RowVectorXi::LinSpaced(lNumberChannels.at(k),1,lNumberChannels.at(k)+1);
            connectivitySettings.setNodePositions(raw.info, picks);

            for(int l = 0; l < lNumberTrials.size(); ++l) {
                //Create data to work on

                while(connectivitySettings.size() < lNumberTrials.at(l)) {
                    connectivitySettings.append(matData);
                }

                for(int i = 0; i < sConnectivityMethodList.size(); ++i) {
                    m_iNumberTrials = lNumberTrials.at(l);
                    m_iNumberChannels = lNumberChannels.at(k);
                    m_iNumberSamples = lNumberSamples.at(j);

                    //Create new folder
                    m_sCurrentDir = QString("/cluster/fusion/lesch/connectivity_performance_%1_%2_%3/%4/%5_%6_%7").arg(QHostInfo::localHostName()).arg(AbstractMetric::m_iNumberBinAmount).arg(iStorageModeActive).arg(sConnectivityMethodList.at(i)).arg(QString::number(lNumberChannels.at(k))).arg(QString::number(lNumberSamples.at(j))).arg(QString::number(lNumberTrials.at(l)));
                    QDir().mkpath(m_sCurrentDir);

                    //Write basic information to file
                    qWarning() << "sConnectivityMethod" << sConnectivityMethodList.at(i);
                    qWarning() << "sRaw" << sRaw;
                    qWarning() << "storageModeActive" << iStorageModeActive;
                    qWarning() << "iNumberSamples" << lNumberSamples.at(j);
                    qWarning() << "iNumberChannels" << lNumberChannels.at(k);
                    qWarning() << "iNumberTrials" << lNumberTrials.at(l);
                    qWarning() << "iNumberCSDFreqBins" << AbstractMetric::m_iNumberBinAmount;
                    qWarning() << "rows" << matData.rows();
                    qWarning() << "cols" << matData.cols();
                    qWarning() << "numberNodes" << connectivitySettings.getNodePositions().rows();

                    // Check that iNfft >= signal length
                    int iSignalLength = lNumberSamples.at(j);
                    int iNfft = int(raw.info.sfreq/1.0);
                    if(iNfft > iSignalLength) {
                        iNfft = iSignalLength;
                    }

                    qWarning() << "iNfft" << iNfft;

                    int iNFreqs = int(floor(iNfft / 2.0)) + 1;
                    qWarning() << "iNFreqs" << iNFreqs;

                    connectivitySettings.setConnectivityMethods(QStringList() << sConnectivityMethodList.at(i));

                    m_iCurrentIteration = 0;
                    for(int u = 0; u < iNumberRepeats; ++u) {
                        connectivitySettings.clearIntermediateData();

                        qWarning() << "iteration" << m_iCurrentIteration;

                        //Do connectivity estimation
                        connectivityObj.calculate(connectivitySettings);

                        printf("Iteration %d: Calculating %s for %d trials, %d channels, %d samples\n", m_iCurrentIteration, sConnectivityMethodList.at(i).toLatin1().data(), connectivitySettings.size(), lNumberChannels.at(k), lNumberSamples.at(j));

                        m_iCurrentIteration++;
                    }
                }
            }
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"

#include "nmea_parser.h"

using namespace nmea;

TEST_CASE("GxRMC parser") {
  RmcData data;
  uint8_t crc;

  // From NL-8002U NAVILOCK Multi GNSS Receiver ublox 8
  CHECK(parse("$GNRMC,031649.50,A,4958.42331,N,00909.23445,E,1.039,,250516,,,A*6F", &data, &crc) == true);

  // Generic

  // NMEA 2.3 (and later) examples
  CHECK(parse("$GPRMC,052848,A,4958.43074,N,00909.25157,E,0.371,,240516,,,A*5C", &data, &crc) == true);
  CHECK(parse("$GNRMC,052848.40,A,4958.43074,N,00909.25157,E,0.371,0.451,240516,,,D*43", &data, &crc) == true);
  CHECK(parse("$GLRMC,052848.40,V,4958.43074,S,00909.25157,W,,,240516,,,E*5D", &data, &crc) == true);
  CHECK(parse("$GARMC,052848.40,A,4958.43074,N,00909.25157,E,,0.451,240516,0.332,E,N*04", &data, &crc) == true);
  CHECK(parse("$GBRMC,052848.40,A,4958.43074,N,00909.25157,E,0.371,,240516,,,S*76", &data, &crc) == true);
  CHECK(parse("$GPRMC,052848,A,4958.43074,N,00909.25157,E,0.371,,240516,,,F*5B", &data, &crc) == true);
  CHECK(parse("$GPRMC,052848,A,4958.43074,N,00909.25157,E,0.371,,240516,,,R*4F", &data, &crc) == true);

  // NMEA pre 2.3 (no mode indicator)
  CHECK(parse("$GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70", &data, &crc) == true);
}

TEST_CASE("GxGGA parser") {
  GgaData data;
  uint8_t crc;

  // From NL-8002U NAVILOCK Multi GNSS Receiver ublox 8
  CHECK(parse("$GNGGA,031649.50,4958.42331,N,00909.23445,E,1,09,1.08,156.1,M,47.7,M,,*4A", &data, &crc) == true);

  // Generic
  CHECK(parse("$GPGGA,152835.00,5554.0114,N,03732.5007,E,1,13,00.8,170.4,M,14.5,M,,*5E", &data, &crc) == true);
  CHECK(parse("$GNGGA,150947.00,5554.0083,N,03732.502,E,1,15,00.6,190.6,M,14.5,M,,*78", &data, &crc) == true);
  CHECK(parse("$GPGGA,151114.00,5554.0093,N,03732.5027,E,1,11,00.7,196.4,M,14.5,M,,*5E", &data, &crc) == true);
  CHECK(parse("$GLGGA,150626.00,5554.0097,N,03732.4979,E,1,06,01.2,192.6,M,14.5,M,,*46", &data, &crc) == true);
}

TEST_CASE("GxGSV parser") {
  GsvData data;
  uint8_t crc;

  // From NL-8002U NAVILOCK Multi GNSS Receiver ublox 8
  CHECK(parse("$GPGSV,3,1,12,02,36,299,24,03,17,119,10,05,05,298,,06,51,230,23*77", &data, &crc) == true);
  CHECK(parse("$GPGSV,3,2,12,07,42,173,22,09,81,053,16,16,15,069,,19,00,233,*78", &data, &crc) == true);
  CHECK(parse("$GPGSV,3,3,12,23,49,068,19,26,12,041,,29,04,345,,30,17,190,18*7B", &data, &crc) == true);
  CHECK(parse("$GLGSV,3,1,09,65,21,293,23,72,05,092,,73,48,073,19,74,36,147,24*6A", &data, &crc) == true);
  CHECK(parse("$GLGSV,3,2,09,80,13,022,,81,06,354,,87,24,250,26,88,30,305,*65", &data, &crc) == true);
  CHECK(parse("$GLGSV,3,3,09,95,13,022,*52", &data, &crc) == true);

  // Generic
  CHECK(parse("$GPGSV,3,1,12,11,52,219,48,12,09,021,40,14,34,057,47,17,25,306,45*72", &data, &crc) == true);
  CHECK(parse("$GPGSV,3,2,12,20,46,274,48,23,14,223,45,24,67,214,49,31,35,123,48*75", &data, &crc) == true);
  CHECK(parse("$GPGSV,3,3,12,32,78,266,51,33,11,238,39,37,15,197,37,39,25,195,00*7A", &data, &crc) == true);
  CHECK(parse("$GLGSV,2,1,07,65,36,079,51,66,77,331,53,74,15,014,42,75,41,067,49*65", &data, &crc) == true);
  CHECK(parse("$GLGSV,2,2,07,76,24,132,50,82,41,296,48,83,13,346,43*78", &data, &crc) == true);
}

TEST_CASE("Checksum calculation") {
  CHECK(calc_checksum("$GNRMC,031649.50,A,4958.42331,N,00909.23445,E,1.039,,250516,,,A*6F") == 0x6F);
  CHECK(calc_checksum("$GNGGA,031649.50,4958.42331,N,00909.23445,E,1,09,1.08,156.1,M,47.7,M,,*4A") == 0x4A);
  CHECK(calc_checksum("$GPGSV,3,2,12,07,42,173,22,09,81,053,16,16,15,069,,19,00,233,*78") == 0x78);
}
<commit_msg>Added tests for sentence contents<commit_after>#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"

#include "nmea_parser.h"

using namespace nmea;
using doctest::Approx;

TEST_CASE("GxRMC parser") {
  RmcData data;
  uint8_t crc;

  // From NL-8002U NAVILOCK Multi GNSS Receiver ublox 8
  CHECK(parse("$GNRMC,031649.50,A,4958.42331,N,00909.23445,E,1.039,,250516,,,A*6F", &data, &crc) == true);

  CHECK(data.talker_id == 'N');
  CHECK(data.utc_time_hour == 3);
  CHECK(data.utc_time_minute == 16);
  CHECK(Approx(data.utc_time_second) == 49.5);
  CHECK(data.status == 'A');
  CHECK(data.degrees_lat == 49);
  CHECK(Approx(data.minutes_lat) == 58.42331);
  CHECK(data.direction_lat == 'N');
  CHECK(data.degrees_long == 9);
  CHECK(Approx(data.minutes_long) == 9.23445);
  CHECK(data.direction_long == 'E');
  CHECK(Approx(data.speed_over_ground) == 1.039);
  CHECK(Approx(data.track_angle) == 0);
  CHECK(data.date_day == 25);
  CHECK(data.date_month == 5);
  CHECK(data.date_year == 16);
  CHECK(data.magnetic_variation == 0);
  CHECK(data.direction_mv == '0');
  CHECK(data.mode_indicator == 'A');

  // Generic

  // NMEA 2.3 (and later) examples
  CHECK(parse("$GPRMC,052848,A,4958.43074,N,00909.25157,E,0.371,,240516,,,A*5C", &data, &crc) == true);
  CHECK(parse("$GNRMC,052848.40,A,4958.43074,N,00909.25157,E,0.371,0.451,240516,,,D*43", &data, &crc) == true);
  CHECK(parse("$GLRMC,052848.40,V,4958.43074,S,00909.25157,W,,,240516,,,E*5D", &data, &crc) == true);
  CHECK(parse("$GARMC,052848.40,A,4958.43074,N,00909.25157,E,,0.451,240516,0.332,E,N*04", &data, &crc) == true);
  CHECK(parse("$GBRMC,052848.40,A,4958.43074,N,00909.25157,E,0.371,,240516,,,S*76", &data, &crc) == true);
  CHECK(parse("$GPRMC,052848,A,4958.43074,N,00909.25157,E,0.371,,240516,,,F*5B", &data, &crc) == true);
  CHECK(parse("$GPRMC,052848,A,4958.43074,N,00909.25157,E,0.371,,240516,,,R*4F", &data, &crc) == true);

  // NMEA pre 2.3 (no mode indicator)
  CHECK(parse("$GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70", &data, &crc) == true);
}

TEST_CASE("GxGGA parser") {
  GgaData data;
  uint8_t crc;

  // From NL-8002U NAVILOCK Multi GNSS Receiver ublox 8
  CHECK(parse("$GNGGA,031649.50,4958.42331,N,00909.23445,E,1,09,1.08,156.1,M,47.7,M,,*4A", &data, &crc) == true);

  CHECK(data.talker_id == 'N');
  CHECK(data.utc_time_hour == 3);
  CHECK(data.utc_time_minute == 16);
  CHECK(Approx(data.utc_time_second) == 49.5);
  CHECK(data.degrees_lat == 49);
  CHECK(Approx(data.minutes_lat) == 58.42331);
  CHECK(data.direction_lat == 'N');
  CHECK(data.degrees_long == 9);
  CHECK(Approx(data.minutes_long) == 9.23445);
  CHECK(data.direction_long == 'E');
  CHECK(data.fix_flag == 1);
  CHECK(data.satellites_used == 9);
  CHECK(Approx(data.hor_dilution_of_precision) == 1.08);
  CHECK(Approx(data.altitude) == 156.1);
  CHECK(Approx(data.geoidal_separation) == 47.7);
  CHECK(Approx(data.age_of_dgps_data) == 0);
  CHECK(data.reference_station_id == 0);

  // Generic
  CHECK(parse("$GPGGA,152835.00,5554.0114,N,03732.5007,E,1,13,00.8,170.4,M,14.5,M,,*5E", &data, &crc) == true);
  CHECK(parse("$GNGGA,150947.00,5554.0083,N,03732.502,E,1,15,00.6,190.6,M,14.5,M,,*78", &data, &crc) == true);
  CHECK(parse("$GPGGA,151114.00,5554.0093,N,03732.5027,E,1,11,00.7,196.4,M,14.5,M,,*5E", &data, &crc) == true);
  CHECK(parse("$GLGGA,150626.00,5554.0097,N,03732.4979,E,1,06,01.2,192.6,M,14.5,M,,*46", &data, &crc) == true);
}

TEST_CASE("GxGSV parser") {
  GsvData data;
  uint8_t crc;

  // From NL-8002U NAVILOCK Multi GNSS Receiver ublox 8

  // GPS satellites

  // Check first message (1/3)
  CHECK(parse("$GPGSV,3,1,12,02,36,299,24,03,17,119,10,05,05,298,,06,51,230,23*77", &data, &crc) == true);
  CHECK(data.talker_id == 'P');
  CHECK(data.total_messages == 3);
  CHECK(data.message_number == 1);
  CHECK(data.satellites_in_view == 12);
    CHECK(data.first.has_data == true);
    CHECK(data.first.satellite_prn_number == 2);
    CHECK(data.first.elevation == 36);
    CHECK(data.first.azimuth == 299);
    CHECK(data.first.snr == 24);

    CHECK(data.second.has_data == true);
    CHECK(data.second.satellite_prn_number == 3);
    CHECK(data.second.elevation == 17);
    CHECK(data.second.azimuth == 119);
    CHECK(data.second.snr == 10);

    CHECK(data.third.has_data == true);
    CHECK(data.third.satellite_prn_number == 5);
    CHECK(data.third.elevation == 5);
    CHECK(data.third.azimuth == 298);
    CHECK(data.third.snr == 0);

    CHECK(data.fourth.has_data == true);
    CHECK(data.fourth.satellite_prn_number == 6);
    CHECK(data.fourth.elevation == 51);
    CHECK(data.fourth.azimuth == 230);
    CHECK(data.fourth.snr == 23);
  CHECK(crc == 0x77);

  // Check second message (2/3)
  CHECK(parse("$GPGSV,3,2,12,07,42,173,22,09,81,053,16,16,15,069,,19,00,233,*78", &data, &crc) == true);
  CHECK(data.talker_id == 'P');
  CHECK(data.total_messages == 3);
  CHECK(data.message_number == 2);
  CHECK(data.satellites_in_view == 12);
    CHECK(data.first.has_data == true);
    CHECK(data.first.satellite_prn_number == 7);
    CHECK(data.first.elevation == 42);
    CHECK(data.first.azimuth == 173);
    CHECK(data.first.snr == 22);

    CHECK(data.second.has_data == true);
    CHECK(data.second.satellite_prn_number == 9);
    CHECK(data.second.elevation == 81);
    CHECK(data.second.azimuth == 53);
    CHECK(data.second.snr == 16);

    CHECK(data.third.has_data == true);
    CHECK(data.third.satellite_prn_number == 16);
    CHECK(data.third.elevation == 15);
    CHECK(data.third.azimuth == 69);
    CHECK(data.third.snr == 0);

    CHECK(data.fourth.has_data == true);
    CHECK(data.fourth.satellite_prn_number == 19);
    CHECK(data.fourth.elevation == 0);
    CHECK(data.fourth.azimuth == 233);
    CHECK(data.fourth.snr == 0);
  CHECK(crc == 0x78);

  // Check third message (3/3)
  CHECK(parse("$GPGSV,3,3,12,23,49,068,19,26,12,041,,29,04,345,,30,17,190,18*7B", &data, &crc) == true);
  CHECK(data.talker_id == 'P');
  CHECK(data.total_messages == 3);
  CHECK(data.message_number == 3);
  CHECK(data.satellites_in_view == 12);
    CHECK(data.first.has_data == true);
    CHECK(data.first.satellite_prn_number == 23);
    CHECK(data.first.elevation == 49);
    CHECK(data.first.azimuth == 68);
    CHECK(data.first.snr == 19);

    CHECK(data.second.has_data == true);
    CHECK(data.second.satellite_prn_number == 26);
    CHECK(data.second.elevation == 12);
    CHECK(data.second.azimuth == 41);
    CHECK(data.second.snr == 0);

    CHECK(data.third.has_data == true);
    CHECK(data.third.satellite_prn_number == 29);
    CHECK(data.third.elevation == 4);
    CHECK(data.third.azimuth == 345);
    CHECK(data.third.snr == 0);

    CHECK(data.fourth.has_data == true);
    CHECK(data.fourth.satellite_prn_number == 30);
    CHECK(data.fourth.elevation == 17);
    CHECK(data.fourth.azimuth == 190);
    CHECK(data.fourth.snr == 18);
  CHECK(crc == 0x7B);

  // GLONASS satellites
  CHECK(parse("$GLGSV,3,1,09,65,21,293,23,72,05,092,,73,48,073,19,74,36,147,24*6A", &data, &crc) == true);
  CHECK(parse("$GLGSV,3,2,09,80,13,022,,81,06,354,,87,24,250,26,88,30,305,*65", &data, &crc) == true);

  // Check last message (3/3)
  CHECK(parse("$GLGSV,3,3,09,95,13,022,*52", &data, &crc) == true);
  CHECK(data.talker_id == 'L');
  CHECK(data.total_messages == 3);
  CHECK(data.message_number == 3);
  CHECK(data.satellites_in_view == 9);
    CHECK(data.first.has_data == true);
    CHECK(data.first.satellite_prn_number == 95);
    CHECK(data.first.elevation == 13);
    CHECK(data.first.azimuth == 22);
    CHECK(data.first.snr == 0);

    CHECK(data.second.has_data == false);
    CHECK(data.third.has_data == false);
    CHECK(data.fourth.has_data == false);
  CHECK(crc == 0x52);

  // Generic
  CHECK(parse("$GPGSV,3,1,12,11,52,219,48,12,09,021,40,14,34,057,47,17,25,306,45*72", &data, &crc) == true);
  CHECK(parse("$GPGSV,3,2,12,20,46,274,48,23,14,223,45,24,67,214,49,31,35,123,48*75", &data, &crc) == true);
  CHECK(parse("$GPGSV,3,3,12,32,78,266,51,33,11,238,39,37,15,197,37,39,25,195,00*7A", &data, &crc) == true);
  CHECK(parse("$GLGSV,2,1,07,65,36,079,51,66,77,331,53,74,15,014,42,75,41,067,49*65", &data, &crc) == true);
  CHECK(parse("$GLGSV,2,2,07,76,24,132,50,82,41,296,48,83,13,346,43*78", &data, &crc) == true);
}

TEST_CASE("Checksum calculation") {
  CHECK(calc_checksum("$GNRMC,031649.50,A,4958.42331,N,00909.23445,E,1.039,,250516,,,A*6F") == 0x6F);
  CHECK(calc_checksum("$GNGGA,031649.50,4958.42331,N,00909.23445,E,1,09,1.08,156.1,M,47.7,M,,*4A") == 0x4A);
  CHECK(calc_checksum("$GPGSV,3,2,12,07,42,173,22,09,81,053,16,16,15,069,,19,00,233,*78") == 0x78);
}
<|endoftext|>


<commit_before>
<commit_msg>Delete 1.cpp<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "leveldbwrapper.h"

#include "util.h"

#include <boost/filesystem.hpp>

#include <leveldb/cache.h>
#include <leveldb/env.h>
#include <leveldb/filter_policy.h>
#include <memenv.h>

void HandleError(const leveldb::Status& status) throw(leveldb_error)
{
    if (status.ok())
        return;
    LogPrintf("%s\n", status.ToString());
    if (status.IsCorruption())
        throw leveldb_error("Database corrupted");
    if (status.IsIOError())
        throw leveldb_error("Database I/O error");
    if (status.IsNotFound())
        throw leveldb_error("Database entry missing");
    throw leveldb_error("Unknown database error");
}

static leveldb::Options GetOptions(size_t nCacheSize)
{
    leveldb::Options options;
    options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
    options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
    options.filter_policy = leveldb::NewBloomFilterPolicy(10);
    options.compression = leveldb::kNoCompression;
    options.max_open_files = 64;
    if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
        // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
        // on corruption in later versions.
        options.paranoid_checks = true;
    }
    return options;
}

CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe)
{
    penv = NULL;
    readoptions.verify_checksums = true;
    iteroptions.verify_checksums = true;
    iteroptions.fill_cache = false;
    syncoptions.sync = true;
    options = GetOptions(nCacheSize);
    options.create_if_missing = true;
    if (fMemory) {
        penv = leveldb::NewMemEnv(leveldb::Env::Default());
        options.env = penv;
    } else {
        if (fWipe) {
            LogPrintf("Wiping LevelDB in %s\n", path.string());
            leveldb::DestroyDB(path.string(), options);
        }
        TryCreateDirectory(path);
        LogPrintf("Opening LevelDB in %s\n", path.string());
    }
    leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
    HandleError(status);
    LogPrintf("Opened LevelDB successfully\n");
}

CLevelDBWrapper::~CLevelDBWrapper()
{
    delete pdb;
    pdb = NULL;
    delete options.filter_policy;
    options.filter_policy = NULL;
    delete options.block_cache;
    options.block_cache = NULL;
    delete penv;
    options.env = NULL;
}

bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error)
{
    leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
    HandleError(status);
    return true;
}
<commit_msg>Handle leveldb::DestroyDB() errors on wipe failure<commit_after>// Copyright (c) 2012-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "leveldbwrapper.h"

#include "util.h"

#include <boost/filesystem.hpp>

#include <leveldb/cache.h>
#include <leveldb/env.h>
#include <leveldb/filter_policy.h>
#include <memenv.h>

void HandleError(const leveldb::Status& status) throw(leveldb_error)
{
    if (status.ok())
        return;
    LogPrintf("%s\n", status.ToString());
    if (status.IsCorruption())
        throw leveldb_error("Database corrupted");
    if (status.IsIOError())
        throw leveldb_error("Database I/O error");
    if (status.IsNotFound())
        throw leveldb_error("Database entry missing");
    throw leveldb_error("Unknown database error");
}

static leveldb::Options GetOptions(size_t nCacheSize)
{
    leveldb::Options options;
    options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
    options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
    options.filter_policy = leveldb::NewBloomFilterPolicy(10);
    options.compression = leveldb::kNoCompression;
    options.max_open_files = 64;
    if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
        // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
        // on corruption in later versions.
        options.paranoid_checks = true;
    }
    return options;
}

CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe)
{
    penv = NULL;
    readoptions.verify_checksums = true;
    iteroptions.verify_checksums = true;
    iteroptions.fill_cache = false;
    syncoptions.sync = true;
    options = GetOptions(nCacheSize);
    options.create_if_missing = true;
    if (fMemory) {
        penv = leveldb::NewMemEnv(leveldb::Env::Default());
        options.env = penv;
    } else {
        if (fWipe) {
            LogPrintf("Wiping LevelDB in %s\n", path.string());
            leveldb::Status result = leveldb::DestroyDB(path.string(), options);
            HandleError(result);
        }
        TryCreateDirectory(path);
        LogPrintf("Opening LevelDB in %s\n", path.string());
    }
    leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
    HandleError(status);
    LogPrintf("Opened LevelDB successfully\n");
}

CLevelDBWrapper::~CLevelDBWrapper()
{
    delete pdb;
    pdb = NULL;
    delete options.filter_policy;
    options.filter_policy = NULL;
    delete options.block_cache;
    options.block_cache = NULL;
    delete penv;
    options.env = NULL;
}

bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error)
{
    leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
    HandleError(status);
    return true;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* libwps
 * Version: MPL 2.0 / LGPLv2.1+
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Major Contributor(s):
 * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr)
 * Copyright (C) 2006, 2007 Andrew Ziem
 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
 * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
 * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca)
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU Lesser General Public License Version 2.1 or later
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
 * applicable instead of those above.
 *
 * For further information visit http://libwps.sourceforge.net
 */

#include "WPS8Struct.h"

#include "WPSDebug.h"

namespace WPS8Struct
{
// try to read a block, which can be or not a list of data
bool FileData::readArrayBlock() const
{
	if (isRead()) return isArray();
	long actPos = m_input->tell();
	m_input->seek(m_beginOffset, librevenge::RVNG_SEEK_SET);
	std::string error;
	bool ok = readBlockData(m_input, m_endOffset, const_cast<FileData &>(*this), error);
	m_input->seek(actPos, librevenge::RVNG_SEEK_SET);
	return ok;
}

// create a message to store unparsed data
std::string FileData::createErrorString(RVNGInputStreamPtr input, long endPos)
{
	libwps::DebugStream f;
	f << ",###unread=(" << std::hex;
	while (input->tell() < endPos-1) f << libwps::readU16(input) << ", ";
	if (input->tell() < endPos)  f << libwps::readU8(input) << ", ";
	f << ")";

	return f.str();
}

bool FileData::getBorderStyles(WPSBorder::Style &style, WPSBorder::Type &type, std::string &mess) const
{
	style = WPSBorder::Simple;
	type = WPSBorder::Single;
	libwps::DebugStream f;
	switch (m_value)
	{
	case 0:
		style  = WPSBorder::None;
		break;
	case 1: // normal
		break;
	case 2: // double normal
		type  = WPSBorder::Double;
		break;
	case 3:
		f << "ext=2,int=1,";
		type  = WPSBorder::Double;
		break;
	case 4:
		f << "ext=1,int=2,";
		type  = WPSBorder::Double;
		break;
	case 5:
		style  = WPSBorder::Dash;
		break;
	case 6:
		style  = WPSBorder::LargeDot;
		break;
	case 7:
		style  = WPSBorder::Dot;
		break;
	case 8:
		f << "dash+rot-5,";
		style  = WPSBorder::Dash;
		break;
	case 9:
		f << "dash+rot5,";
		style  = WPSBorder::Dash;
		break;
	case 0xa:
		f << "triple,";
		type  = WPSBorder::Triple;
		break;
	default:
		f << "#style=" << std::hex << m_value << std::dec << ",";
		break;
	}

	mess = f.str();
	return true;
}

// operator <<
std::ostream &operator<< (std::ostream &o, FileData const &dt)
{
	if (dt.id() != -1)
		o << "unkn" << std::hex << dt.id() << "[typ=" << dt.m_type << "]:" << std::dec;
	FileData &DT = const_cast<FileData &>(dt);
	// If the data are unread, try to read them as a block list
	if (!dt.isRead() && !dt.readArrayBlock())
	{
		// if this fails...
		long size = dt.m_endOffset-dt.m_beginOffset-2;
		int sz = (size%4) == 0 ? 4 : (size%2) == 0 ? 2 : 1;
		int numElt = int(size/sz);

		long actPos = DT.m_input->tell();
		DT.m_input->seek(dt.m_beginOffset, librevenge::RVNG_SEEK_SET);
		o << "###FAILS[sz="<< sz << "]=(" << std::hex;
		long val = (long) libwps::read16(DT.m_input);
		if (val) o << "unkn=" << val <<",";
		for (int i = 0; i < numElt; i++)
		{
			switch (sz)
			{
			case 1:
				o << libwps::readU8(DT.m_input) << ",";
				break;
			case 2:
				o << libwps::readU16(DT.m_input) << ",";
				break;
			case 4:
				o << libwps::readU32(DT.m_input) << ",";
				break;
			default:
				break;
			}
		}
		o << ")" << std::dec;

		DT.m_input->seek(actPos, librevenge::RVNG_SEEK_SET);

		return o;
	}
	if (dt.hasStr()) o << "('" << dt.m_text << "')";
	if (dt.isFalse()) o << "=false,";
	if ((dt.m_type & 0x30) || dt.m_value)
		o << "=" << dt.m_value << ":" << std::hex << dt.m_value << std::dec;
	size_t numChild = dt.m_recursData.size();
	if (!numChild) return o;

	o << ",ch=(";
	for (size_t i = 0; i < numChild; i++)
	{
		if (dt.m_recursData[i].isBad()) continue;
		o << dt.m_recursData[i] << ",";
	}
	o << ")";
	return o;
}

// try to read a data : which can be an item, a list or unknown zone
bool readBlockData(RVNGInputStreamPtr input, long endPos, FileData &dt, std::string &error)
{
	std::string saveError = error;
	long actPos = input->tell();
	dt.m_recursData.resize(0);

	if (actPos+2 > endPos)   // to short
	{
		error += FileData::createErrorString(input, endPos);
		return false;
	}

	dt.m_value = libwps::readU16(input); // normally 0, but who know ...
	dt.m_beginOffset = dt.m_endOffset = -1;

	int prevId = -1;
	bool ok = true;
	while (input->tell() != endPos)
	{
		FileData child;
		if (!readData(input, endPos, child, error))
		{
			ok = false;
			break;
		}
		if (child.isBad()) continue;
		if (prevId > child.id())
		{
			ok = false;
			break;
		}
		prevId = child.id();
		dt.m_recursData.push_back(child);
	}
	if (ok) return true;

	if (dt.m_type == -1) dt.m_type = 0x80;
	dt.m_beginOffset = actPos;
	dt.m_endOffset = endPos;
	dt.m_input = input;

	error = saveError;
	input->seek(endPos, librevenge::RVNG_SEEK_SET);

	return false;
}

// try to read an item
bool readData(RVNGInputStreamPtr input, long endPos,
              FileData &dt, std::string &/*error*/)
{
	long actPos = input->tell();
	dt = FileData();

	if (actPos >= endPos) return false;

	long val = (long) libwps::readU16(input);
	dt.m_type = int((val & 0xFF00)>>8);
	dt.m_id = (val & 0xFF);

	if (dt.m_type & 5)
	{
		dt.m_type = -1;
		return false;
	}

	dt.m_value = 0;
	// what is the meaning of dt.m_type & 0xF
	//   maybe :
	//           0x1/0x4 -> never seem
	//           0x2 -> set for the main child ?
	//           0x8 -> signed/unsigned ? set/unset for bool ?
	switch (dt.m_type>>4)
	{
	case 0:
		return true;
	case 1:
		if (actPos+4 > endPos) break;
		if (dt.m_type == 0x12)
		{
			dt.m_value = libwps::readU8(input);
			input->seek(1, librevenge::RVNG_SEEK_CUR);
		}
		else
			dt.m_value = libwps::readU16(input);
		return true;
	case 2:
	{
		if (dt.m_type == 0x2a)   // special case : STR4 + long
		{
			if (actPos+10 > endPos) break;
			for (int i = 0; i < 4; i++) dt.m_text += (char) libwps::readU8(input);
			dt.m_value = libwps::read32(input);
			return true;
		}
		if (actPos+6 > endPos) break;
		dt.m_value = libwps::read32(input);
		return true;
	}
	case 8:
	{
		if (actPos+4 > endPos) break;

		long extraSize = (long) libwps::readU16(input);
		long newEndPos = actPos+2+extraSize;

		if ((extraSize%2) || newEndPos > endPos) break;

		// can either be a list of data or a structured list, so we stored the information
		dt.m_beginOffset = actPos+4;
		dt.m_endOffset = newEndPos;
		dt.m_input = input;
		input->seek(newEndPos, librevenge::RVNG_SEEK_SET);
		return true;
	}
	default:
		break;
	}

	dt.m_type = -1;
	return false;
}

}

/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
<commit_msg>WPS8Struct.cpp: avoid shadowing a member function...<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* libwps
 * Version: MPL 2.0 / LGPLv2.1+
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Major Contributor(s):
 * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr)
 * Copyright (C) 2006, 2007 Andrew Ziem
 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
 * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
 * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca)
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU Lesser General Public License Version 2.1 or later
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
 * applicable instead of those above.
 *
 * For further information visit http://libwps.sourceforge.net
 */

#include "WPS8Struct.h"

#include "WPSDebug.h"

namespace WPS8Struct
{
// try to read a block, which can be or not a list of data
bool FileData::readArrayBlock() const
{
	if (isRead()) return isArray();
	long actPos = m_input->tell();
	m_input->seek(m_beginOffset, librevenge::RVNG_SEEK_SET);
	std::string error;
	bool ok = readBlockData(m_input, m_endOffset, const_cast<FileData &>(*this), error);
	m_input->seek(actPos, librevenge::RVNG_SEEK_SET);
	return ok;
}

// create a message to store unparsed data
std::string FileData::createErrorString(RVNGInputStreamPtr input, long endPos)
{
	libwps::DebugStream f;
	f << ",###unread=(" << std::hex;
	while (input->tell() < endPos-1) f << libwps::readU16(input) << ", ";
	if (input->tell() < endPos)  f << libwps::readU8(input) << ", ";
	f << ")";

	return f.str();
}

bool FileData::getBorderStyles(WPSBorder::Style &style, WPSBorder::Type &borderType, std::string &mess) const
{
	style = WPSBorder::Simple;
	borderType = WPSBorder::Single;
	libwps::DebugStream f;
	switch (m_value)
	{
	case 0:
		style  = WPSBorder::None;
		break;
	case 1: // normal
		break;
	case 2: // double normal
		borderType  = WPSBorder::Double;
		break;
	case 3:
		f << "ext=2,int=1,";
		borderType  = WPSBorder::Double;
		break;
	case 4:
		f << "ext=1,int=2,";
		borderType  = WPSBorder::Double;
		break;
	case 5:
		style  = WPSBorder::Dash;
		break;
	case 6:
		style  = WPSBorder::LargeDot;
		break;
	case 7:
		style  = WPSBorder::Dot;
		break;
	case 8:
		f << "dash+rot-5,";
		style  = WPSBorder::Dash;
		break;
	case 9:
		f << "dash+rot5,";
		style  = WPSBorder::Dash;
		break;
	case 0xa:
		f << "triple,";
		borderType  = WPSBorder::Triple;
		break;
	default:
		f << "#style=" << std::hex << m_value << std::dec << ",";
		break;
	}

	mess = f.str();
	return true;
}

// operator <<
std::ostream &operator<< (std::ostream &o, FileData const &dt)
{
	if (dt.id() != -1)
		o << "unkn" << std::hex << dt.id() << "[typ=" << dt.m_type << "]:" << std::dec;
	FileData &DT = const_cast<FileData &>(dt);
	// If the data are unread, try to read them as a block list
	if (!dt.isRead() && !dt.readArrayBlock())
	{
		// if this fails...
		long size = dt.m_endOffset-dt.m_beginOffset-2;
		int sz = (size%4) == 0 ? 4 : (size%2) == 0 ? 2 : 1;
		int numElt = int(size/sz);

		long actPos = DT.m_input->tell();
		DT.m_input->seek(dt.m_beginOffset, librevenge::RVNG_SEEK_SET);
		o << "###FAILS[sz="<< sz << "]=(" << std::hex;
		long val = (long) libwps::read16(DT.m_input);
		if (val) o << "unkn=" << val <<",";
		for (int i = 0; i < numElt; i++)
		{
			switch (sz)
			{
			case 1:
				o << libwps::readU8(DT.m_input) << ",";
				break;
			case 2:
				o << libwps::readU16(DT.m_input) << ",";
				break;
			case 4:
				o << libwps::readU32(DT.m_input) << ",";
				break;
			default:
				break;
			}
		}
		o << ")" << std::dec;

		DT.m_input->seek(actPos, librevenge::RVNG_SEEK_SET);

		return o;
	}
	if (dt.hasStr()) o << "('" << dt.m_text << "')";
	if (dt.isFalse()) o << "=false,";
	if ((dt.m_type & 0x30) || dt.m_value)
		o << "=" << dt.m_value << ":" << std::hex << dt.m_value << std::dec;
	size_t numChild = dt.m_recursData.size();
	if (!numChild) return o;

	o << ",ch=(";
	for (size_t i = 0; i < numChild; i++)
	{
		if (dt.m_recursData[i].isBad()) continue;
		o << dt.m_recursData[i] << ",";
	}
	o << ")";
	return o;
}

// try to read a data : which can be an item, a list or unknown zone
bool readBlockData(RVNGInputStreamPtr input, long endPos, FileData &dt, std::string &error)
{
	std::string saveError = error;
	long actPos = input->tell();
	dt.m_recursData.resize(0);

	if (actPos+2 > endPos)   // to short
	{
		error += FileData::createErrorString(input, endPos);
		return false;
	}

	dt.m_value = libwps::readU16(input); // normally 0, but who know ...
	dt.m_beginOffset = dt.m_endOffset = -1;

	int prevId = -1;
	bool ok = true;
	while (input->tell() != endPos)
	{
		FileData child;
		if (!readData(input, endPos, child, error))
		{
			ok = false;
			break;
		}
		if (child.isBad()) continue;
		if (prevId > child.id())
		{
			ok = false;
			break;
		}
		prevId = child.id();
		dt.m_recursData.push_back(child);
	}
	if (ok) return true;

	if (dt.m_type == -1) dt.m_type = 0x80;
	dt.m_beginOffset = actPos;
	dt.m_endOffset = endPos;
	dt.m_input = input;

	error = saveError;
	input->seek(endPos, librevenge::RVNG_SEEK_SET);

	return false;
}

// try to read an item
bool readData(RVNGInputStreamPtr input, long endPos,
              FileData &dt, std::string &/*error*/)
{
	long actPos = input->tell();
	dt = FileData();

	if (actPos >= endPos) return false;

	long val = (long) libwps::readU16(input);
	dt.m_type = int((val & 0xFF00)>>8);
	dt.m_id = (val & 0xFF);

	if (dt.m_type & 5)
	{
		dt.m_type = -1;
		return false;
	}

	dt.m_value = 0;
	// what is the meaning of dt.m_type & 0xF
	//   maybe :
	//           0x1/0x4 -> never seem
	//           0x2 -> set for the main child ?
	//           0x8 -> signed/unsigned ? set/unset for bool ?
	switch (dt.m_type>>4)
	{
	case 0:
		return true;
	case 1:
		if (actPos+4 > endPos) break;
		if (dt.m_type == 0x12)
		{
			dt.m_value = libwps::readU8(input);
			input->seek(1, librevenge::RVNG_SEEK_CUR);
		}
		else
			dt.m_value = libwps::readU16(input);
		return true;
	case 2:
	{
		if (dt.m_type == 0x2a)   // special case : STR4 + long
		{
			if (actPos+10 > endPos) break;
			for (int i = 0; i < 4; i++) dt.m_text += (char) libwps::readU8(input);
			dt.m_value = libwps::read32(input);
			return true;
		}
		if (actPos+6 > endPos) break;
		dt.m_value = libwps::read32(input);
		return true;
	}
	case 8:
	{
		if (actPos+4 > endPos) break;

		long extraSize = (long) libwps::readU16(input);
		long newEndPos = actPos+2+extraSize;

		if ((extraSize%2) || newEndPos > endPos) break;

		// can either be a list of data or a structured list, so we stored the information
		dt.m_beginOffset = actPos+4;
		dt.m_endOffset = newEndPos;
		dt.m_input = input;
		input->seek(newEndPos, librevenge::RVNG_SEEK_SET);
		return true;
	}
	default:
		break;
	}

	dt.m_type = -1;
	return false;
}

}

/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
<|endoftext|>


<commit_before>// Copyright (C) 2016-2020 European Spallation Source, ERIC. See LICENSE file
//===----------------------------------------------------------------------===//
///
/// \file
///
/// \brief EFU main application
///
//===----------------------------------------------------------------------===//

#include <boost/filesystem.hpp>
#include <common/StatPublisher.h>
#include <common/Version.h>
#include <common/debug/Log.h>
#include <common/detector/EFUArgs.h>
#include <common/system/gccintel.h>
#include <common/time/Timer.h>
#include <cstdlib>
#include <efu/ExitHandler.h>
#include <efu/HwCheck.h>
#include <efu/Launcher.h>
#include <efu/Parser.h>
#include <efu/Server.h>
#include <iostream>

#ifdef EFU_MIRACLES
#include <modules/miracles/MiraclesBase.h>
#endif
#ifdef EFU_BIFROST
#include <modules/bifrost/BifrostBase.h>
#endif
#ifdef EFU_CSPEC
#include <modules/cspec/CSPECBase.h>
#endif
#ifdef EFU_DREAM
#include <modules/dream/DreamBase.h>
#endif
#ifdef EFU_FREIA
#include <modules/freia/FreiaBase.h>
#endif
#ifdef EFU_LOKI
#include <modules/loki/LokiBase.h>
#endif
#ifdef EFU_NMX
#include <modules/nmx/NMXBase.h>
#endif
#ifdef EFU_PERFGEN
#include <modules/perfgen/PerfGenBase.h>
#endif
#ifdef EFU_TTLMON
#include <modules/ttlmonitor/TTLMonitorBase.h>
#endif

#include <unistd.h> // sleep()
#include <vector>

static constexpr uint64_t MicrosecondsPerSecond{1000000};

std::string ConsoleFormatter(const Log::LogMessage &Msg) {
  static const std::vector<std::string> SevToString{
      "EMG", "ALR", "CRIT", "ERR", "WAR", "NOTE", "INFO", "DEB"};
  std::string FileName;
  std::int64_t LineNr = -1;
  for (auto &CField : Msg.AdditionalFields) {
    if (CField.first == "file") {
      FileName = CField.second.strVal;
    } else if (CField.first == "line") {
      LineNr = CField.second.intVal;
    }
  }
  return fmt::format("{:5}{:21}{:5} - {}",
                     SevToString.at(static_cast<size_t>(Msg.SeverityLevel)),
                     FileName, LineNr, Msg.MessageString);
}

std::string FileFormatter(const Log::LogMessage &Msg) {
  std::time_t cTime = std::chrono::system_clock::to_time_t(Msg.Timestamp);
  char timeBuffer[50];
  size_t bytes = std::strftime(timeBuffer, 50, "%F %T", std::localtime(&cTime));
  static const std::vector<std::string> SevToString{
      "EMG", "ALR", "CRIT", "ERR", "WAR", "NOTE", "INFO", "DEB"};
  std::string FileName;
  std::int64_t LineNr = -1;
  for (auto &CField : Msg.AdditionalFields) {
    if (CField.first == "file") {
      FileName = CField.second.strVal;
    } else if (CField.first == "line") {
      LineNr = CField.second.intVal;
    }
  }
  return fmt::format("{} {:5}{:21}:{:<5} - {}", std::string(timeBuffer, bytes),
                     SevToString.at(static_cast<size_t>(Msg.SeverityLevel)),
                     FileName, LineNr, Msg.MessageString);
}

void EmptyGraylogMessageQueue() {
  std::vector<Log::LogHandler_P> GraylogHandlers(Log::GetHandlers());
  if (not GraylogHandlers.empty()) {
    int WaitLoops = 25;
    auto SleepTime = std::chrono::milliseconds(20);
    bool ContinueLoop = true;
    for (int i = 0; i < WaitLoops and ContinueLoop; i++) {
      std::this_thread::sleep_for(SleepTime);
      ContinueLoop = false;
      for (auto &Ptr : GraylogHandlers) {
        if (not Ptr->emptyQueue()) {
          ContinueLoop = true;
        }
      }
    }
  }
  Log::RemoveAllHandlers();
}

/** Load detector, launch pipeline threads, then sleep until timeout or break */
int main(int argc, char *argv[]) {
  BaseSettings DetectorSettings;
  std::shared_ptr<Detector> detector;
  std::string DetectorName;
  GraylogSettings GLConfig;
  HwCheck hwcheck;
  Timer RunTimer;

  EFUArgs efu_args;
  if (EFUArgs::Status::EXIT == efu_args.parseFirstPass(argc, argv)) {
    return 0;
  }
  efu_args.printSettings();
  DetectorSettings = efu_args.getBaseSettings();

  #ifdef EFU_MIRACLES
  DetectorName="miracles";
  #endif
  #ifdef EFU_BIFROST
  DetectorName="bifrost";
  #endif
  #ifdef EFU_CSPEC
  DetectorName="cspec";
  #endif
  #ifdef EFU_DREAM
  DetectorName="dream";
  #endif
  #ifdef EFU_FREIA
  DetectorName="freia";
  #endif
  #ifdef EFU_LOKI
  DetectorName="loki";
  #endif
  #ifdef EFU_PERFGEN
  DetectorName="perfgen";
  #endif
  #ifdef EFU_TTLMON
  DetectorName="ttlmonitor";
  #endif

  // Set-up logging before we start doing important stuff
  Log::RemoveAllHandlers();

  auto CI = new Log::ConsoleInterface();
  CI->setMessageStringCreatorFunction(ConsoleFormatter);
  Log::AddLogHandler(CI);

  Log::SetMinimumSeverity(Log::Severity(efu_args.getLogLevel()));
  if (!efu_args.getLogFileName().empty()) {
    auto FI = new Log::FileInterface(efu_args.getLogFileName());
    FI->setMessageStringCreatorFunction(FileFormatter);
    Log::AddLogHandler(FI);
  }

  GLConfig = efu_args.getGraylogSettings();
  if (not GLConfig.address.empty()) {
    Log::AddLogHandler(
        new Log::GraylogInterface(GLConfig.address, GLConfig.port));
  }

  DetectorSettings.GraphitePrefix = std::string("efu.") + DetectorName;

  auto Base = new
  #ifdef EFU_MIRACLES
    Miracles::MiraclesBase(DetectorSettings);
  #endif
  #ifdef EFU_BIFROST
    Bifrost::BifrostBase(DetectorSettings);
  #endif
  #ifdef EFU_CSPEC
    Cspec::CspecBase(DetectorSettings);
  #endif
  #ifdef EFU_DREAM
    Dream::DreamBase(DetectorSettings);
  #endif
  #ifdef EFU_FREIA
    Freia::FreiaBase(DetectorSettings);
  #endif
  #ifdef EFU_LOKI
    Loki::LokiBase(DetectorSettings);
  #endif
  #ifdef EFU_NMX
    Nmx::NmxBase(DetectorSettings);
  #endif
  #ifdef EFU_PERFGEN
    PerfGen::PerfGenBase(DetectorSettings);
  #endif
  #ifdef EFU_TTLMON
    TTLMonitor::TTLMonitorBase(DetectorSettings);
  #endif

  detector = std::shared_ptr<Detector>(Base);

  int keep_running = 1;

  ExitHandler::InitExitHandler();

  int64_t statUpTime{0};
  Statistics mainStats;
  mainStats.setPrefix(DetectorSettings.GraphitePrefix,
                      DetectorSettings.GraphiteRegion);
  mainStats.create("main.uptime", statUpTime);

  LOG(MAIN, Sev::Info, "Starting Event Formation Unit");
  LOG(MAIN, Sev::Info, "Event Formation Unit version: {}", efu_version());
  LOG(MAIN, Sev::Info, "Event Formation Unit build: {}", efu_buildstr());

  if (DetectorSettings.NoHwCheck) {
    LOG(MAIN, Sev::Warning, "Skipping HwCheck - performance might suffer");
  } else {
    if (hwcheck.checkMTU(hwcheck.IgnoredInterfaces) == false) {
      LOG(MAIN, Sev::Error, "MTU checks failed, for a quick fix, try");
      LOG(MAIN, Sev::Error,
          "sudo ifconfig eth0 mtu 9000 (change eth0 to match your system)");
      LOG(MAIN, Sev::Error, "exiting...");
      detector.reset(); // De-allocate detector before we unload detector module
      EmptyGraylogMessageQueue();
      return -1;
    }
  }

  if (DetectorSettings.StopAfterSec == 0) {
    LOG(MAIN, Sev::Info, "Event Formation Unit Exit (Immediate)");
    detector.reset(); // De-allocate detector before we unload detector module
    EmptyGraylogMessageQueue();
    return 0;
  }

  LOG(MAIN, Sev::Info, "Launching EFU as Instrument {}", DetectorName);

  Launcher launcher;

  launcher.launchThreads(detector);

  StatPublisher metrics(DetectorSettings.GraphiteAddress,
                        DetectorSettings.GraphitePort);

  Parser cmdParser(detector, mainStats, keep_running);
  Server cmdAPI(DetectorSettings.CommandServerPort, cmdParser);

  Timer livestats;

  while (true) {
    // Do not allow immediate exits
    if (RunTimer.timeus() >= MicrosecondsPerSecond / 10) {
      if (keep_running == 0) {
        LOG(MAIN, Sev::Info, "Application stop, Exiting...");
        detector->stopThreads();
        sleep(1);
        break;
      }
    }

    if (RunTimer.timeus() >=
        DetectorSettings.StopAfterSec * MicrosecondsPerSecond) {
      LOG(MAIN, Sev::Info, "Application timeout, Exiting...");
      detector->stopThreads();
      sleep(1);
      break;
    }

    if ((livestats.timeus() >= MicrosecondsPerSecond) && detector != nullptr) {
      statUpTime = RunTimer.timeus() / 1000000;
      metrics.publish(detector, mainStats);
      livestats.reset();
    }

    cmdAPI.serverPoll();
    ExitHandler::Exit DoExit = ExitHandler::HandleLastSignal();
    if (DoExit == ExitHandler::Exit::Exit) {
      keep_running = 0;
    }
    usleep(500);
  }

  detector.reset();

  EmptyGraylogMessageQueue();
  return 0;
}
<commit_msg>try to override Graylog process<commit_after>// Copyright (C) 2016-2020 European Spallation Source, ERIC. See LICENSE file
//===----------------------------------------------------------------------===//
///
/// \file
///
/// \brief EFU main application
///
//===----------------------------------------------------------------------===//

#include <boost/filesystem.hpp>
#include <common/StatPublisher.h>
#include <common/Version.h>
#include <common/debug/Log.h>
#include <common/detector/EFUArgs.h>
#include <common/system/gccintel.h>
#include <common/time/Timer.h>
#include <cstdlib>
#include <efu/ExitHandler.h>
#include <efu/HwCheck.h>
#include <efu/Launcher.h>
#include <efu/Parser.h>
#include <efu/Server.h>
#include <iostream>

#ifdef EFU_MIRACLES
#include <modules/miracles/MiraclesBase.h>
#endif
#ifdef EFU_BIFROST
#include <modules/bifrost/BifrostBase.h>
#endif
#ifdef EFU_CSPEC
#include <modules/cspec/CSPECBase.h>
#endif
#ifdef EFU_DREAM
#include <modules/dream/DreamBase.h>
#endif
#ifdef EFU_FREIA
#include <modules/freia/FreiaBase.h>
#endif
#ifdef EFU_LOKI
#include <modules/loki/LokiBase.h>
#endif
#ifdef EFU_NMX
#include <modules/nmx/NMXBase.h>
#endif
#ifdef EFU_PERFGEN
#include <modules/perfgen/PerfGenBase.h>
#endif
#ifdef EFU_TTLMON
#include <modules/ttlmonitor/TTLMonitorBase.h>
#endif

#include <unistd.h> // sleep()
#include <vector>

static constexpr uint64_t MicrosecondsPerSecond{1000000};

std::string ConsoleFormatter(const Log::LogMessage &Msg) {
  static const std::vector<std::string> SevToString{
      "EMG", "ALR", "CRIT", "ERR", "WAR", "NOTE", "INFO", "DEB"};
  std::string FileName;
  std::int64_t LineNr = -1;
  for (auto &CField : Msg.AdditionalFields) {
    if (CField.first == "file") {
      FileName = CField.second.strVal;
    } else if (CField.first == "line") {
      LineNr = CField.second.intVal;
    }
  }
  return fmt::format("{:5}{:21}{:5} - {}",
                     SevToString.at(static_cast<size_t>(Msg.SeverityLevel)),
                     FileName, LineNr, Msg.MessageString);
}

std::string FileFormatter(const Log::LogMessage &Msg) {
  std::time_t cTime = std::chrono::system_clock::to_time_t(Msg.Timestamp);
  char timeBuffer[50];
  size_t bytes = std::strftime(timeBuffer, 50, "%F %T", std::localtime(&cTime));
  static const std::vector<std::string> SevToString{
      "EMG", "ALR", "CRIT", "ERR", "WAR", "NOTE", "INFO", "DEB"};
  std::string FileName;
  std::int64_t LineNr = -1;
  for (auto &CField : Msg.AdditionalFields) {
    if (CField.first == "file") {
      FileName = CField.second.strVal;
    } else if (CField.first == "line") {
      LineNr = CField.second.intVal;
    }
  }
  return fmt::format("{} {:5}{:21}:{:<5} - {}", std::string(timeBuffer, bytes),
                     SevToString.at(static_cast<size_t>(Msg.SeverityLevel)),
                     FileName, LineNr, Msg.MessageString);
}

void EmptyGraylogMessageQueue() {
  std::vector<Log::LogHandler_P> GraylogHandlers(Log::GetHandlers());
  if (not GraylogHandlers.empty()) {
    int WaitLoops = 25;
    auto SleepTime = std::chrono::milliseconds(20);
    bool ContinueLoop = true;
    for (int i = 0; i < WaitLoops and ContinueLoop; i++) {
      std::this_thread::sleep_for(SleepTime);
      ContinueLoop = false;
      for (auto &Ptr : GraylogHandlers) {
        if (not Ptr->emptyQueue()) {
          ContinueLoop = true;
        }
      }
    }
  }
  Log::RemoveAllHandlers();
}

/** Load detector, launch pipeline threads, then sleep until timeout or break */
int main(int argc, char *argv[]) {
  BaseSettings DetectorSettings;
  std::shared_ptr<Detector> detector;
  std::string DetectorName;
  GraylogSettings GLConfig;
  HwCheck hwcheck;
  Timer RunTimer;

  EFUArgs efu_args;
  if (EFUArgs::Status::EXIT == efu_args.parseFirstPass(argc, argv)) {
    return 0;
  }
  efu_args.printSettings();
  DetectorSettings = efu_args.getBaseSettings();

  #ifdef EFU_MIRACLES
  DetectorName="miracles";
  #endif
  #ifdef EFU_BIFROST
  DetectorName="bifrost";
  #endif
  #ifdef EFU_CSPEC
  DetectorName="cspec";
  #endif
  #ifdef EFU_DREAM
  DetectorName="dream";
  #endif
  #ifdef EFU_FREIA
  DetectorName="freia";
  #endif
  #ifdef EFU_LOKI
  DetectorName="loki";
  #endif
  #ifdef EFU_PERFGEN
  DetectorName="perfgen";
  #endif
  #ifdef EFU_TTLMON
  DetectorName="ttlmonitor";
  #endif

  // Set-up logging before we start doing important stuff
  // change process to "efu" and set process_name to Instrument
  std::string ProcessKey{"process"};
  std::string ProcessValue{"efu"};
  std::string ProcessNameKey{"process_name"};
  Log::RemoveAllHandlers();
  Log::Logger::Inst().addField(ProcessKey, ProcessValue);
  Log::Logger::Inst().addField(ProcessNameKey, DetectorName);

  auto CI = new Log::ConsoleInterface();
  CI->setMessageStringCreatorFunction(ConsoleFormatter);
  Log::AddLogHandler(CI);

  Log::SetMinimumSeverity(Log::Severity(efu_args.getLogLevel()));
  if (!efu_args.getLogFileName().empty()) {
    auto FI = new Log::FileInterface(efu_args.getLogFileName());
    FI->setMessageStringCreatorFunction(FileFormatter);
    Log::AddLogHandler(FI);
  }

  GLConfig = efu_args.getGraylogSettings();
  if (not GLConfig.address.empty()) {
    Log::AddLogHandler(
        new Log::GraylogInterface(GLConfig.address, GLConfig.port));
  }

  DetectorSettings.GraphitePrefix = std::string("efu.") + DetectorName;

  auto Base = new
  #ifdef EFU_MIRACLES
    Miracles::MiraclesBase(DetectorSettings);
  #endif
  #ifdef EFU_BIFROST
    Bifrost::BifrostBase(DetectorSettings);
  #endif
  #ifdef EFU_CSPEC
    Cspec::CspecBase(DetectorSettings);
  #endif
  #ifdef EFU_DREAM
    Dream::DreamBase(DetectorSettings);
  #endif
  #ifdef EFU_FREIA
    Freia::FreiaBase(DetectorSettings);
  #endif
  #ifdef EFU_LOKI
    Loki::LokiBase(DetectorSettings);
  #endif
  #ifdef EFU_NMX
    Nmx::NmxBase(DetectorSettings);
  #endif
  #ifdef EFU_PERFGEN
    PerfGen::PerfGenBase(DetectorSettings);
  #endif
  #ifdef EFU_TTLMON
    TTLMonitor::TTLMonitorBase(DetectorSettings);
  #endif

  detector = std::shared_ptr<Detector>(Base);

  int keep_running = 1;

  ExitHandler::InitExitHandler();

  int64_t statUpTime{0};
  Statistics mainStats;
  mainStats.setPrefix(DetectorSettings.GraphitePrefix,
                      DetectorSettings.GraphiteRegion);
  mainStats.create("main.uptime", statUpTime);

  LOG(MAIN, Sev::Info, "Starting Event Formation Unit");
  LOG(MAIN, Sev::Info, "Event Formation Unit version: {}", efu_version());
  LOG(MAIN, Sev::Info, "Event Formation Unit build: {}", efu_buildstr());

  if (DetectorSettings.NoHwCheck) {
    LOG(MAIN, Sev::Warning, "Skipping HwCheck - performance might suffer");
  } else {
    if (hwcheck.checkMTU(hwcheck.IgnoredInterfaces) == false) {
      LOG(MAIN, Sev::Error, "MTU checks failed, for a quick fix, try");
      LOG(MAIN, Sev::Error,
          "sudo ifconfig eth0 mtu 9000 (change eth0 to match your system)");
      LOG(MAIN, Sev::Error, "exiting...");
      detector.reset(); // De-allocate detector before we unload detector module
      EmptyGraylogMessageQueue();
      return -1;
    }
  }

  if (DetectorSettings.StopAfterSec == 0) {
    LOG(MAIN, Sev::Info, "Event Formation Unit Exit (Immediate)");
    detector.reset(); // De-allocate detector before we unload detector module
    EmptyGraylogMessageQueue();
    return 0;
  }

  LOG(MAIN, Sev::Info, "Launching EFU as Instrument {}", DetectorName);

  Launcher launcher;

  launcher.launchThreads(detector);

  StatPublisher metrics(DetectorSettings.GraphiteAddress,
                        DetectorSettings.GraphitePort);

  Parser cmdParser(detector, mainStats, keep_running);
  Server cmdAPI(DetectorSettings.CommandServerPort, cmdParser);

  Timer livestats;

  while (true) {
    // Do not allow immediate exits
    if (RunTimer.timeus() >= MicrosecondsPerSecond / 10) {
      if (keep_running == 0) {
        LOG(MAIN, Sev::Info, "Application stop, Exiting...");
        detector->stopThreads();
        sleep(1);
        break;
      }
    }

    if (RunTimer.timeus() >=
        DetectorSettings.StopAfterSec * MicrosecondsPerSecond) {
      LOG(MAIN, Sev::Info, "Application timeout, Exiting...");
      detector->stopThreads();
      sleep(1);
      break;
    }

    if ((livestats.timeus() >= MicrosecondsPerSecond) && detector != nullptr) {
      statUpTime = RunTimer.timeus() / 1000000;
      metrics.publish(detector, mainStats);
      livestats.reset();
    }

    cmdAPI.serverPoll();
    ExitHandler::Exit DoExit = ExitHandler::HandleLastSignal();
    if (DoExit == ExitHandler::Exit::Exit) {
      keep_running = 0;
    }
    usleep(500);
  }

  detector.reset();

  EmptyGraylogMessageQueue();
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2010 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "thread.h"
#include <stdexcept>

namespace votca {
    namespace tools {

        static void *runwrapper(void *arg) {
            Thread *thread = (Thread*) (arg);
            thread->Run();
            pthread_exit(NULL);
        }

        Thread::Thread() {

        }

        Thread::~Thread() {

        }

        void Thread::Start() {
            pthread_attr_t attr;

            pthread_attr_init(&attr);
            /*
             * according to the POSIX standard, threads are created in the joinable state
             * by default
             * however, some platforms do not obey
             *
             * explicitly create the thread in the joinable state
             * the main program can then wait for the thread by calling pthread_join(thread)
             *
             */
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
            _finished = false;

            int rc = pthread_create(&_thread, &attr, runwrapper, (void *) this);
            if (rc) {
                throw std::runtime_error("ERROR; return code from pthread_create() is "
                        + rc);
            }

        }

        void Thread::WaitDone() {
            void * status;
            int rc = pthread_join(_thread, &status);
            if (rc) {
                throw std::runtime_error("ERROR; return code from pthread_join() is "
                        + rc);
            }
            _finished = true;
        }

        bool Thread::IsFinished() const {
            return _finished;
        }

    }
}

<commit_msg>thread.cc: fixed xlC warning<commit_after>/*
 * Copyright 2010 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "thread.h"
#include <stdexcept>

namespace votca {
    namespace tools {

        static void *runwrapper(void *arg) {
            Thread *thread = (Thread*) (arg);
            thread->Run();
            pthread_exit(NULL);
            return NULL;
        }

        Thread::Thread() {

        }

        Thread::~Thread() {

        }

        void Thread::Start() {
            pthread_attr_t attr;

            pthread_attr_init(&attr);
            /*
             * according to the POSIX standard, threads are created in the joinable state
             * by default
             * however, some platforms do not obey
             *
             * explicitly create the thread in the joinable state
             * the main program can then wait for the thread by calling pthread_join(thread)
             *
             */
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
            _finished = false;

            int rc = pthread_create(&_thread, &attr, runwrapper, (void *) this);
            if (rc) {
                throw std::runtime_error("ERROR; return code from pthread_create() is "
                        + rc);
            }

        }

        void Thread::WaitDone() {
            void * status;
            int rc = pthread_join(_thread, &status);
            if (rc) {
                throw std::runtime_error("ERROR; return code from pthread_join() is "
                        + rc);
            }
            _finished = true;
        }

        bool Thread::IsFinished() const {
            return _finished;
        }

    }
}

<|endoftext|>