<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord/util/binarymessagereader.h>
#include <fnord/exception.h>
#include <fnord/inspect.h>

namespace fnord {
namespace util {

BinaryMessageReader::BinaryMessageReader(
    void const* buf,
    size_t buf_len) :
    ptr_(buf),
    size_(buf_len),
    pos_(0) {}

uint8_t const* BinaryMessageReader::readUInt8() {
  return static_cast<uint8_t const*>(read(sizeof(uint8_t)));
}

uint16_t const* BinaryMessageReader::readUInt16() {
  return static_cast<uint16_t const*>(read(sizeof(uint16_t)));
}

uint32_t const* BinaryMessageReader::readUInt32() {
  return static_cast<uint32_t const*>(read(sizeof(uint32_t)));
}

uint64_t const* BinaryMessageReader::readUInt64() {
  return static_cast<uint64_t const*>(read(sizeof(uint64_t)));
}

void const* BinaryMessageReader::read(size_t size) {
  return static_cast<void const*>(readString(size));
}

uint64_t BinaryMessageReader::readVarUInt() {
  uint64_t value = 0;

  for (int i = 0; ; ++i) {
    auto b = *((const unsigned char*) read(1));

    value |= (b & 0x7fULL) << (7 * i);

    if (!(b & 0x80U)) {
      break;
    }
  }

  return value;
}

template <>
uint16_t const* BinaryMessageReader::readValue<uint16_t>() {
  return readUInt16();
}

template <>
uint32_t const* BinaryMessageReader::readValue<uint32_t>() {
  return readUInt32();
}

template <>
String const* BinaryMessageReader::readValue<String>() {
  auto len = *readUInt32();
  cur_str_ = String(reinterpret_cast<const char*>(read(len)), len);
  return &cur_str_;
}

char const* BinaryMessageReader::readString(size_t size) {
#ifndef FNORD_NODBEUG
  if ((pos_ + size) > size_) {
    RAISE(kBufferOverflowError, "requested read exceeds message bounds");
  }
#endif

  auto ptr = static_cast<char const*>(ptr_) + pos_;
  pos_ += size;
  return ptr;
}

std::string BinaryMessageReader::readLenencString() {
  auto len = readVarUInt();
  return String((char*) read(len), len);
}

void BinaryMessageReader::rewind() {
  pos_ = 0;
}

void BinaryMessageReader::seekTo(size_t pos) {
#ifndef FNORD_NODBEUG
  if (pos > size_) {
    RAISE(kBufferOverflowError, "requested position exceeds message bounds");
  }
#endif

  pos_ = pos;
}

size_t BinaryMessageReader::remaining() const {
  return size_ - pos_;
}

size_t BinaryMessageReader::position() const {
  return pos_;
}

}
}

<commit_msg>BinaryMessageReader::readDouble<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord/util/binarymessagereader.h>
#include <fnord/exception.h>
#include <fnord/IEEE754.h>

namespace fnord {
namespace util {

BinaryMessageReader::BinaryMessageReader(
    void const* buf,
    size_t buf_len) :
    ptr_(buf),
    size_(buf_len),
    pos_(0) {}

uint8_t const* BinaryMessageReader::readUInt8() {
  return static_cast<uint8_t const*>(read(sizeof(uint8_t)));
}

uint16_t const* BinaryMessageReader::readUInt16() {
  return static_cast<uint16_t const*>(read(sizeof(uint16_t)));
}

uint32_t const* BinaryMessageReader::readUInt32() {
  return static_cast<uint32_t const*>(read(sizeof(uint32_t)));
}

uint64_t const* BinaryMessageReader::readUInt64() {
  return static_cast<uint64_t const*>(read(sizeof(uint64_t)));
}

void const* BinaryMessageReader::read(size_t size) {
  return static_cast<void const*>(readString(size));
}

uint64_t BinaryMessageReader::readVarUInt() {
  uint64_t value = 0;

  for (int i = 0; ; ++i) {
    auto b = *((const unsigned char*) read(1));

    value |= (b & 0x7fULL) << (7 * i);

    if (!(b & 0x80U)) {
      break;
    }
  }

  return value;
}

template <>
uint16_t const* BinaryMessageReader::readValue<uint16_t>() {
  return readUInt16();
}

template <>
uint32_t const* BinaryMessageReader::readValue<uint32_t>() {
  return readUInt32();
}

template <>
String const* BinaryMessageReader::readValue<String>() {
  auto len = *readUInt32();
  cur_str_ = String(reinterpret_cast<const char*>(read(len)), len);
  return &cur_str_;
}

char const* BinaryMessageReader::readString(size_t size) {
#ifndef FNORD_NODBEUG
  if ((pos_ + size) > size_) {
    RAISE(kBufferOverflowError, "requested read exceeds message bounds");
  }
#endif

  auto ptr = static_cast<char const*>(ptr_) + pos_;
  pos_ += size;
  return ptr;
}

double BinaryMessageReader::readDouble() {
  return IEEE754::fromBytes(
      *static_cast<uint64_t const*>(read(sizeof(uint64_t))));
}

std::string BinaryMessageReader::readLenencString() {
  auto len = readVarUInt();
  return String((char*) read(len), len);
}

void BinaryMessageReader::rewind() {
  pos_ = 0;
}

void BinaryMessageReader::seekTo(size_t pos) {
#ifndef FNORD_NODBEUG
  if (pos > size_) {
    RAISE(kBufferOverflowError, "requested position exceeds message bounds");
  }
#endif

  pos_ = pos;
}

size_t BinaryMessageReader::remaining() const {
  return size_ - pos_;
}

size_t BinaryMessageReader::position() const {
  return pos_;
}

}
}

<|endoftext|>


<commit_before><commit_msg>straighten confusing brackets<commit_after><|endoftext|>


<commit_before>//=============================================================================================================
/**
* @file     fiffstreamthread.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Limin Sun <liminsun@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     July, 2012
*
* @section  LICENSE
*
* Copyright (C) 2012, Christoph Dinh, Limin Sun 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 the Massachusetts General Hospital 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 MASSACHUSETTS GENERAL HOSPITAL 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     implementation of the FiffStreamThread Class.
*
*/

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

#include "fiffstreamthread.h"
#include "fiffstreamserver.h"
#include "mne_rt_commands.h"

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

#include <utils/ioutils.h>
#include <fiff/fiff_constants.h>
#include <fiff/fiff_tag.h>

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

#include <QtNetwork>

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

using namespace UTILSLIB;
using namespace RTSERVER;
using namespace FIFFLIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

FiffStreamThread::FiffStreamThread(qint32 id, int socketDescriptor, QObject *parent)
: QThread(parent)
, m_iDataClientId(id)
, m_sDataClientAlias(QString(""))
, m_bIsSendingRawBuffer(false)
, m_iSocketDescriptor(socketDescriptor)
, m_bIsRunning(false)
{
}

//*************************************************************************************************************

FiffStreamThread::~FiffStreamThread()
{
    //Remove from client list
    FiffStreamServer* t_pFiffStreamServer = qobject_cast<FiffStreamServer*>(this->parent());
    if(t_pFiffStreamServer)
        t_pFiffStreamServer->m_qClientList.remove(m_iDataClientId);

    m_bIsRunning = false;
    QThread::wait();
}

//*************************************************************************************************************

void FiffStreamThread::startMeas(qint32 ID)
{
    if(ID == m_iDataClientId)
    {
        qDebug() << "Activate raw buffer sending.";

        m_qMutex.lock();
        // ToDo send start meas
        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);
        t_FiffStreamOut.start_block(FIFFB_RAW_DATA);
        m_bIsSendingRawBuffer = true;
        m_qMutex.unlock();
    }
}

//*************************************************************************************************************

void FiffStreamThread::stopMeas(qint32 ID)
{
    qDebug() << "void FiffStreamThread::stopMeas(qint32 ID)";
    if(ID == m_iDataClientId || ID == -1)
    {
        qDebug() << "stop raw buffer sending.";

        m_qMutex.lock();
        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);
        t_FiffStreamOut.end_block(FIFFB_RAW_DATA);
        m_bIsSendingRawBuffer = false;
        m_qMutex.unlock();
    }
}

//*************************************************************************************************************

void FiffStreamThread::parseCommand(FiffTag::SPtr p_pTag)
{
    if(p_pTag->size() >= 4)
    {
        qint32* t_pInt = (qint32*)p_pTag->data();
        IOUtils::swap_intp(t_pInt);
        qint32 t_iCmd = t_pInt[0];

        if(t_iCmd == MNE_RT_SET_CLIENT_ALIAS)
        {
            //
            // Set Client Alias
            //
            m_sDataClientAlias = QString(p_pTag->mid(4, p_pTag->size()-4));
            printf("FiffStreamClient (ID %d): new alias = '%s'\r\n\n", m_iDataClientId, m_sDataClientAlias.toUtf8().constData());
        }
        else if(t_iCmd == MNE_RT_GET_CLIENT_ID)
        {
            //
            // Send Client ID
            //
            printf("FiffStreamClient (ID %d): send client ID %d\r\n\n", m_iDataClientId, m_iDataClientId);
            writeClientId();
        }
        else
        {
            printf("FiffStreamClient (ID %d): unknown command\r\n\n", m_iDataClientId);
        }
    }
    else
    {
        printf("FiffStreamClient (ID %d): unknown command\r\n\n", m_iDataClientId);
    }
}

//*************************************************************************************************************

void FiffStreamThread::sendRawBuffer(QSharedPointer<Eigen::MatrixXf> m_pMatRawData)
{
    if(m_bIsSendingRawBuffer)
    {
//        qDebug() << "Send RawBuffer to client";

        m_qMutex.lock();

        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);
        t_FiffStreamOut.write_float(FIFF_DATA_BUFFER,m_pMatRawData->data(),m_pMatRawData->rows()*m_pMatRawData->cols());

        m_qMutex.unlock();

    }
//    else
//    {
//        qDebug() << "Send RawBuffer is not activated";
//    }
}

//*************************************************************************************************************

void FiffStreamThread::sendMeasurementInfo(qint32 ID, FiffInfo p_fiffInfo)
{
    if(ID == m_iDataClientId)
    {
        m_qMutex.lock();

        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);

//        qint32 init_info[2];
//        init_info[0] = FIFF_MNE_RT_CLIENT_ID;
//        init_info[1] = m_iDataClientId;

//        t_FiffStreamOut.start_block(FIFFB_MNE_RT_MEAS_INFO);

//FiffStream::start_writing_raw

        p_fiffInfo.writeToStream(&t_FiffStreamOut);

        m_qMutex.unlock();

//        qDebug() << "MeasInfo Blocksize: " << m_qSendBlock.size();
    }
}

//*************************************************************************************************************

void FiffStreamThread::writeClientId()
{
    FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);

    t_FiffStreamOut.write_int(FIFF_MNE_RT_CLIENT_ID, &m_iDataClientId);
}

//*************************************************************************************************************

void FiffStreamThread::run()
{
    m_bIsRunning = true;

    FiffStreamServer* t_pParentServer = qobject_cast<FiffStreamServer*>(this->parent());

    connect(t_pParentServer, &FiffStreamServer::remitMeasInfo,
            this, &FiffStreamThread::sendMeasurementInfo);
    connect(t_pParentServer, &FiffStreamServer::remitRawBuffer,
            this, &FiffStreamThread::sendRawBuffer);
    connect(t_pParentServer, &FiffStreamServer::startMeasFiffStreamClient,
            this, &FiffStreamThread::startMeas);
    connect(t_pParentServer, &FiffStreamServer::stopMeasFiffStreamClient,
            this, &FiffStreamThread::stopMeas);

    QTcpSocket t_qTcpSocket;
    if (!t_qTcpSocket.setSocketDescriptor(m_iSocketDescriptor)) {
        emit error(t_qTcpSocket.error());
        return;
    }
    else
    {
        printf("FiffStreamClient (assigned ID %d) accepted from\n\tIP:\t%s\n\tPort:\t%d\n\n",
               m_iDataClientId,
               QHostAddress(t_qTcpSocket.peerAddress()).toString().toUtf8().constData(),
               t_qTcpSocket.peerPort());
    }

    FiffStream t_FiffStreamIn(&t_qTcpSocket);

//    int i = 0;
    while(t_qTcpSocket.state() != QAbstractSocket::UnconnectedState && m_bIsRunning)
    {
        //
        // Write available data
        //
        if(m_qSendBlock.size() > 0)
        {
//            qDebug() << "is writeable " << t_qTcpSocket.isWritable();
//            qint32 t_iBlockSize = m_qSendBlock.size();
//            qDebug() << "data available" << t_iBlockSize;
            m_qMutex.lock();
            t_qTcpSocket.write(m_qSendBlock);// qint32 t_iBytesWritten = t_qTcpSocket.write(m_qSendBlock);
//            qDebug() << ++i<< "[wrote bytes] " << t_iBytesWritten;
            t_qTcpSocket.waitForBytesWritten();
//            if(t_iBytesWritten == t_iBlockSize)
//            {
//                m_qSendBlock.clear();
//            }
//            else
//            {
//                m_qSendBlock = m_qSendBlock.mid(t_iBytesWritten, t_iBlockSize-t_iBytesWritten);
//            }
            m_qMutex.unlock();
        }

        //
        // Read: Wait 10ms for incomming tag header, read and continue
        //
        t_qTcpSocket.waitForReadyRead(10);

        if (t_qTcpSocket.bytesAvailable() >= (int)sizeof(qint32)*4)
        {
//            qDebug() << "goes to read bytes " ;
            FiffTag::SPtr t_pTag;
            FiffTag::read_tag_info(&t_FiffStreamIn, t_pTag, false);

            //
            // wait until tag size data are available and read the data
            //
            while (t_qTcpSocket.bytesAvailable() < t_pTag->size())
            {
                t_qTcpSocket.waitForReadyRead(10);
            }
            FiffTag::read_tag_data(&t_FiffStreamIn, t_pTag);

            //
            // Parse the tag
            //
            if(t_pTag->kind == FIFF_MNE_RT_COMMAND)
            {
                parseCommand(t_pTag);
            }
        }
//        usleep(1000);
    }

    t_qTcpSocket.disconnectFromHost();
    if(t_qTcpSocket.state() != QAbstractSocket::UnconnectedState)
        t_qTcpSocket.waitForDisconnected();
}
<commit_msg>connection fix 3<commit_after>//=============================================================================================================
/**
* @file     fiffstreamthread.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Limin Sun <liminsun@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     July, 2012
*
* @section  LICENSE
*
* Copyright (C) 2012, Christoph Dinh, Limin Sun 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 the Massachusetts General Hospital 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 MASSACHUSETTS GENERAL HOSPITAL 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     implementation of the FiffStreamThread Class.
*
*/

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

#include "fiffstreamthread.h"
#include "fiffstreamserver.h"
#include "mne_rt_commands.h"

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

#include <utils/ioutils.h>
#include <fiff/fiff_constants.h>
#include <fiff/fiff_tag.h>

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

#include <QtNetwork>

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

using namespace UTILSLIB;
using namespace RTSERVER;
using namespace FIFFLIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

FiffStreamThread::FiffStreamThread(qint32 id, int socketDescriptor, QObject *parent)
: QThread(parent)
, m_iDataClientId(id)
, m_sDataClientAlias(QString(""))
, m_bIsSendingRawBuffer(false)
, m_iSocketDescriptor(socketDescriptor)
, m_bIsRunning(false)
{
}

//*************************************************************************************************************

FiffStreamThread::~FiffStreamThread()
{
    //Remove from client list
    FiffStreamServer* t_pFiffStreamServer = qobject_cast<FiffStreamServer*>(this->parent());
    if(t_pFiffStreamServer)
        t_pFiffStreamServer->m_qClientList.remove(m_iDataClientId);

    m_bIsRunning = false;
    QThread::wait();
}

//*************************************************************************************************************

void FiffStreamThread::startMeas(qint32 ID)
{
    if(ID == m_iDataClientId)
    {
        qDebug() << "Activate raw buffer sending.";

        m_qMutex.lock();
        // ToDo send start meas
        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);
        t_FiffStreamOut.start_block(FIFFB_RAW_DATA);
        m_bIsSendingRawBuffer = true;
        m_qMutex.unlock();
    }
}

//*************************************************************************************************************

void FiffStreamThread::stopMeas(qint32 ID)
{
    qDebug() << "void FiffStreamThread::stopMeas(qint32 ID)";
    if(ID == m_iDataClientId || ID == -1)
    {
        qDebug() << "stop raw buffer sending.";

        m_qMutex.lock();
        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);
        t_FiffStreamOut.end_block(FIFFB_RAW_DATA);
        m_bIsSendingRawBuffer = false;
        m_qMutex.unlock();
    }
}

//*************************************************************************************************************

void FiffStreamThread::parseCommand(FiffTag::SPtr p_pTag)
{
    if(p_pTag->size() >= 4)
    {
        qint32* t_pInt = (qint32*)p_pTag->data();
        IOUtils::swap_intp(t_pInt);
        qint32 t_iCmd = t_pInt[0];

        if(t_iCmd == MNE_RT_SET_CLIENT_ALIAS)
        {
            //
            // Set Client Alias
            //
            m_sDataClientAlias = QString(p_pTag->mid(4, p_pTag->size()-4));
            printf("FiffStreamClient (ID %d): new alias = '%s'\r\n\n", m_iDataClientId, m_sDataClientAlias.toUtf8().constData());
        }
        else if(t_iCmd == MNE_RT_GET_CLIENT_ID)
        {
            //
            // Send Client ID
            //
            printf("FiffStreamClient (ID %d): send client ID %d\r\n\n", m_iDataClientId, m_iDataClientId);
            writeClientId();
        }
        else
        {
            printf("FiffStreamClient (ID %d): unknown command\r\n\n", m_iDataClientId);
        }
    }
    else
    {
        printf("FiffStreamClient (ID %d): unknown command\r\n\n", m_iDataClientId);
    }
}

//*************************************************************************************************************

void FiffStreamThread::sendRawBuffer(QSharedPointer<Eigen::MatrixXf> m_pMatRawData)
{
    if(m_bIsSendingRawBuffer)
    {
//        qDebug() << "Send RawBuffer to client";

        m_qMutex.lock();

        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);
        t_FiffStreamOut.write_float(FIFF_DATA_BUFFER,m_pMatRawData->data(),m_pMatRawData->rows()*m_pMatRawData->cols());

        m_qMutex.unlock();

    }
//    else
//    {
//        qDebug() << "Send RawBuffer is not activated";
//    }
}

//*************************************************************************************************************

void FiffStreamThread::sendMeasurementInfo(qint32 ID, FiffInfo p_fiffInfo)
{
    if(ID == m_iDataClientId)
    {
        m_qMutex.lock();

        FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);

//        qint32 init_info[2];
//        init_info[0] = FIFF_MNE_RT_CLIENT_ID;
//        init_info[1] = m_iDataClientId;

//        t_FiffStreamOut.start_block(FIFFB_MNE_RT_MEAS_INFO);

//FiffStream::start_writing_raw

        p_fiffInfo.writeToStream(&t_FiffStreamOut);

        m_qMutex.unlock();

//        qDebug() << "MeasInfo Blocksize: " << m_qSendBlock.size();
    }
}

//*************************************************************************************************************

void FiffStreamThread::writeClientId()
{
    FiffStream t_FiffStreamOut(&m_qSendBlock, QIODevice::WriteOnly);

    t_FiffStreamOut.write_int(FIFF_MNE_RT_CLIENT_ID, &m_iDataClientId);
}

//*************************************************************************************************************

void FiffStreamThread::run()
{
    m_bIsRunning = true;

    FiffStreamServer* t_pParentServer = qobject_cast<FiffStreamServer*>(this->parent());

    connect(t_pParentServer, &FiffStreamServer::remitMeasInfo,
            this, &FiffStreamThread::sendMeasurementInfo);
    connect(t_pParentServer, &FiffStreamServer::remitRawBuffer,
            this, &FiffStreamThread::sendRawBuffer);
    connect(t_pParentServer, &FiffStreamServer::startMeasFiffStreamClient,
            this, &FiffStreamThread::startMeas);
    connect(t_pParentServer, &FiffStreamServer::stopMeasFiffStreamClient,
            this, &FiffStreamThread::stopMeas);

    QTcpSocket t_qTcpSocket;
    if (!t_qTcpSocket.setSocketDescriptor(m_iSocketDescriptor)) {
        emit error(t_qTcpSocket.error());
        return;
    }
    else
    {
        printf("FiffStreamClient (assigned ID %d) accepted from\n\tIP:\t%s\n\tPort:\t%d\n\n",
               m_iDataClientId,
               QHostAddress(t_qTcpSocket.peerAddress()).toString().toUtf8().constData(),
               t_qTcpSocket.peerPort());
    }

    FiffStream t_FiffStreamIn(&t_qTcpSocket);

//    int i = 0;
    while(t_qTcpSocket.state() != QAbstractSocket::UnconnectedState && m_bIsRunning)
    {
        //
        // Write available data
        //
        if(m_qSendBlock.size() > 0)
        {
//            qDebug() << "is writeable " << t_qTcpSocket.isWritable();
            qint32 t_iBlockSize = m_qSendBlock.size();
//            qDebug() << "data available" << t_iBlockSize;
            m_qMutex.lock();
            qint32 t_iBytesWritten = t_qTcpSocket.write(m_qSendBlock);
//            qDebug() << ++i<< "[wrote bytes] " << t_iBytesWritten;
            t_qTcpSocket.waitForBytesWritten();
            if(t_iBytesWritten == t_iBlockSize)
            {
                m_qSendBlock.clear();
            }
            else
            {
                //we have to store bytes which were not written to the socket, due to writing limit
                //m_qSendBlock = m_qSendBlock.mid(t_iBytesWritten, t_iBlockSize-t_iBytesWritten);
                m_qSendBlock.remove(0,t_iBytesWritten); //higher performance then mid
            }
            m_qMutex.unlock();
        }

        //
        // Read: Wait 10ms for incomming tag header, read and continue
        //
        t_qTcpSocket.waitForReadyRead(10);

        if (t_qTcpSocket.bytesAvailable() >= (int)sizeof(qint32)*4)
        {
//            qDebug() << "goes to read bytes " ;
            FiffTag::SPtr t_pTag;
            FiffTag::read_tag_info(&t_FiffStreamIn, t_pTag, false);

            //
            // wait until tag size data are available and read the data
            //
            while (t_qTcpSocket.bytesAvailable() < t_pTag->size())
            {
                t_qTcpSocket.waitForReadyRead(10);
            }
            FiffTag::read_tag_data(&t_FiffStreamIn, t_pTag);

            //
            // Parse the tag
            //
            if(t_pTag->kind == FIFF_MNE_RT_COMMAND)
            {
                parseCommand(t_pTag);
            }
        }
//        usleep(1000);
    }

    t_qTcpSocket.disconnectFromHost();
    if(t_qTcpSocket.state() != QAbstractSocket::UnconnectedState)
        t_qTcpSocket.waitForDisconnected();
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2006  Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/

#include "OgreStableHeaders.h"
#include "OgreCommon.h"
#include "OgreSceneManager.h"
#include "OgreLight.h"
#include "OgreShadowCameraSetup.h"
#include "OgreCamera.h"
#include "OgreViewport.h"

namespace Ogre
{
	/// Default constructor
	DefaultShadowCameraSetup::DefaultShadowCameraSetup()  {}

	/// Destructor
	DefaultShadowCameraSetup::~DefaultShadowCameraSetup() {}

	/// Default shadow camera setup implementation
	void DefaultShadowCameraSetup::getShadowCamera (const SceneManager *sm, const Camera *cam,
		const Viewport *vp, const Light *light, Camera *texCam, size_t iteration) const
	{
		Vector3 pos, dir;

		// reset custom view / projection matrix in case already set
		texCam->setCustomViewMatrix(false);
		texCam->setCustomProjectionMatrix(false);

		// get the shadow frustum's far distance
		Real shadowDist = light->getShadowFarDistance();
		if (!shadowDist)
		{
			// need a shadow distance, make one up
			shadowDist = cam->getNearClipDistance() * 300;
		}
		Real shadowOffset = shadowDist * (sm->getShadowDirLightTextureOffset());

		// Directional lights
		if (light->getType() == Light::LT_DIRECTIONAL)
		{
			// set up the shadow texture
			// Set ortho projection
			texCam->setProjectionType(PT_ORTHOGRAPHIC);
			// set easy FOV and near dist so that texture covers far dist
			texCam->setFOVy(Degree(90));
			texCam->setNearClipDistance(shadowDist);

			// Calculate look at position
			// We want to look at a spot shadowOffset away from near plane
			// 0.5 is a litle too close for angles
			Vector3 target = cam->getDerivedPosition() +
				(cam->getDerivedDirection() * shadowOffset);

			// Calculate direction, which same as directional light direction
			dir = - light->getDerivedDirection(); // backwards since point down -z
			dir.normalise();

			// Calculate position
			// We want to be in the -ve direction of the light direction
			// far enough to project for the dir light extrusion distance
			pos = target + dir * sm->getShadowDirectionalLightExtrusionDistance();

			// Round local x/y position based on a world-space texel; this helps to reduce
			// jittering caused by the projection moving with the camera
			// Viewport is 2 * near clip distance across (90 degree fov)
			Real worldTexelSize = (texCam->getNearClipDistance() * 20) / vp->getActualWidth();
			pos.x -= fmod(pos.x, worldTexelSize);
			pos.y -= fmod(pos.y, worldTexelSize);
			pos.z -= fmod(pos.z, worldTexelSize);
		}
		// Spotlight
		else if (light->getType() == Light::LT_SPOTLIGHT)
		{
			// Set perspective projection
			texCam->setProjectionType(PT_PERSPECTIVE);
			// set FOV slightly larger than the spotlight range to ensure coverage
			Radian fovy = light->getSpotlightOuterAngle()*1.2;
			// limit angle
			if (fovy.valueDegrees() > 175)
				fovy = Degree(175);
			texCam->setFOVy(fovy);
			// set near clip the same as main camera, since they are likely
			// to both reflect the nature of the scene
			texCam->setNearClipDistance(cam->getNearClipDistance());

			// Calculate position, which same as spotlight position
			pos = light->getDerivedPosition();

			// Calculate direction, which same as spotlight direction
			dir = - light->getDerivedDirection(); // backwards since point down -z
			dir.normalise();
		}
		// Point light
		else
		{
			// Set perspective projection
			texCam->setProjectionType(PT_PERSPECTIVE);
			// Use 120 degree FOV for point light to ensure coverage more area
			texCam->setFOVy(Degree(120));
			// set near clip the same as main camera, since they are likely
			// to both reflect the nature of the scene
			texCam->setNearClipDistance(cam->getNearClipDistance());

			// Calculate look at position
			// We want to look at a spot shadowOffset away from near plane
			// 0.5 is a litle too close for angles
			Vector3 target = cam->getDerivedPosition() +
				(cam->getDerivedDirection() * shadowOffset);

			// Calculate position, which same as point light position
			pos = light->getDerivedPosition();

			dir = (pos - target); // backwards since point down -z
			dir.normalise();
		}

		// Finally set position
		texCam->setPosition(pos);

		// Calculate orientation based on direction calculated above
		/*
		// Next section (camera oriented shadow map) abandoned
		// Always point in the same direction, if we don't do this then
		// we get 'shadow swimming' as camera rotates
		// As it is, we get swimming on moving but this is less noticeable

		// calculate up vector, we want it aligned with cam direction
		Vector3 up = cam->getDerivedDirection();
		// Check it's not coincident with dir
		if (up.dotProduct(dir) >= 1.0f)
		{
		// Use camera up
		up = cam->getUp();
		}
		*/
		Vector3 up = Vector3::UNIT_Y;
		// Check it's not coincident with dir
		if (Math::Abs(up.dotProduct(dir)) >= 1.0f)
		{
			// Use camera up
			up = Vector3::UNIT_Z;
		}
		// cross twice to rederive, only direction is unaltered
		Vector3 left = dir.crossProduct(up);
		left.normalise();
		up = dir.crossProduct(left);
		up.normalise();
		// Derive quaternion from axes
		Quaternion q;
		q.FromAxes(left, up, dir);
		texCam->setOrientation(q);
	}

}
<commit_msg>Since near clip & FOV no longer affect orthographic projection, uniform shadow camera setup should use setOrthoWindow to configure itself.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2006  Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/

#include "OgreStableHeaders.h"
#include "OgreCommon.h"
#include "OgreSceneManager.h"
#include "OgreLight.h"
#include "OgreShadowCameraSetup.h"
#include "OgreCamera.h"
#include "OgreViewport.h"

namespace Ogre
{
	/// Default constructor
	DefaultShadowCameraSetup::DefaultShadowCameraSetup()  {}

	/// Destructor
	DefaultShadowCameraSetup::~DefaultShadowCameraSetup() {}

	/// Default shadow camera setup implementation
	void DefaultShadowCameraSetup::getShadowCamera (const SceneManager *sm, const Camera *cam,
		const Viewport *vp, const Light *light, Camera *texCam, size_t iteration) const
	{
		Vector3 pos, dir;

		// reset custom view / projection matrix in case already set
		texCam->setCustomViewMatrix(false);
		texCam->setCustomProjectionMatrix(false);

		// get the shadow frustum's far distance
		Real shadowDist = light->getShadowFarDistance();
		if (!shadowDist)
		{
			// need a shadow distance, make one up
			shadowDist = cam->getNearClipDistance() * 300;
		}
		Real shadowOffset = shadowDist * (sm->getShadowDirLightTextureOffset());

		// Directional lights
		if (light->getType() == Light::LT_DIRECTIONAL)
		{
			// set up the shadow texture
			// Set ortho projection
			texCam->setProjectionType(PT_ORTHOGRAPHIC);
			// set ortho window so that texture covers far dist
			texCam->setOrthoWindow(shadowDist * 2, shadowDist * 2);

			// Calculate look at position
			// We want to look at a spot shadowOffset away from near plane
			// 0.5 is a litle too close for angles
			Vector3 target = cam->getDerivedPosition() +
				(cam->getDerivedDirection() * shadowOffset);

			// Calculate direction, which same as directional light direction
			dir = - light->getDerivedDirection(); // backwards since point down -z
			dir.normalise();

			// Calculate position
			// We want to be in the -ve direction of the light direction
			// far enough to project for the dir light extrusion distance
			pos = target + dir * sm->getShadowDirectionalLightExtrusionDistance();

			// Round local x/y position based on a world-space texel; this helps to reduce
			// jittering caused by the projection moving with the camera
			// Viewport is 2 * near clip distance across (90 degree fov)
			Real worldTexelSize = (texCam->getNearClipDistance() * 20) / vp->getActualWidth();
			pos.x -= fmod(pos.x, worldTexelSize);
			pos.y -= fmod(pos.y, worldTexelSize);
			pos.z -= fmod(pos.z, worldTexelSize);
		}
		// Spotlight
		else if (light->getType() == Light::LT_SPOTLIGHT)
		{
			// Set perspective projection
			texCam->setProjectionType(PT_PERSPECTIVE);
			// set FOV slightly larger than the spotlight range to ensure coverage
			Radian fovy = light->getSpotlightOuterAngle()*1.2;
			// limit angle
			if (fovy.valueDegrees() > 175)
				fovy = Degree(175);
			texCam->setFOVy(fovy);
			// set near clip the same as main camera, since they are likely
			// to both reflect the nature of the scene
			texCam->setNearClipDistance(cam->getNearClipDistance());

			// Calculate position, which same as spotlight position
			pos = light->getDerivedPosition();

			// Calculate direction, which same as spotlight direction
			dir = - light->getDerivedDirection(); // backwards since point down -z
			dir.normalise();
		}
		// Point light
		else
		{
			// Set perspective projection
			texCam->setProjectionType(PT_PERSPECTIVE);
			// Use 120 degree FOV for point light to ensure coverage more area
			texCam->setFOVy(Degree(120));
			// set near clip the same as main camera, since they are likely
			// to both reflect the nature of the scene
			texCam->setNearClipDistance(cam->getNearClipDistance());

			// Calculate look at position
			// We want to look at a spot shadowOffset away from near plane
			// 0.5 is a litle too close for angles
			Vector3 target = cam->getDerivedPosition() +
				(cam->getDerivedDirection() * shadowOffset);

			// Calculate position, which same as point light position
			pos = light->getDerivedPosition();

			dir = (pos - target); // backwards since point down -z
			dir.normalise();
		}

		// Finally set position
		texCam->setPosition(pos);

		// Calculate orientation based on direction calculated above
		/*
		// Next section (camera oriented shadow map) abandoned
		// Always point in the same direction, if we don't do this then
		// we get 'shadow swimming' as camera rotates
		// As it is, we get swimming on moving but this is less noticeable

		// calculate up vector, we want it aligned with cam direction
		Vector3 up = cam->getDerivedDirection();
		// Check it's not coincident with dir
		if (up.dotProduct(dir) >= 1.0f)
		{
		// Use camera up
		up = cam->getUp();
		}
		*/
		Vector3 up = Vector3::UNIT_Y;
		// Check it's not coincident with dir
		if (Math::Abs(up.dotProduct(dir)) >= 1.0f)
		{
			// Use camera up
			up = Vector3::UNIT_Z;
		}
		// cross twice to rederive, only direction is unaltered
		Vector3 left = dir.crossProduct(up);
		left.normalise();
		up = dir.crossProduct(left);
		up.normalise();
		// Derive quaternion from axes
		Quaternion q;
		q.FromAxes(left, up, dir);
		texCam->setOrientation(q);
	}

}
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include <wx/extension/header.h>
#include <wx/extension/tool.h>
#include "test.h"

#define TEST_FILE "./test.h"
#define TEST_BIN "./test.bin"

void wxExAppTestFixture::setUp()
{
  m_Grid = new wxExGrid(wxTheApp->GetTopWindow());
  m_ListView = new wxExListView(wxTheApp->GetTopWindow());
  m_Notebook = new wxExNotebook(wxTheApp->GetTopWindow(), NULL);
  m_STC = new wxExSTC(wxTheApp->GetTopWindow(), wxExFileName(TEST_FILE));
  m_STCShell = new wxExSTCShell(wxTheApp->GetTopWindow());
  m_SVN = new wxExSVN(SVN_INFO, TEST_FILE);
}

void wxExAppTestFixture::testConstructors()
{
}

void wxExAppTestFixture::testMethods()
{
  // test wxExApp
  CPPUNIT_ASSERT(!wxExApp::GetCatalogDir().empty());
  CPPUNIT_ASSERT(wxExApp::GetConfig() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetLexers() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetPrinter() != NULL);
  CPPUNIT_ASSERT(!wxExTool::GetToolInfo().empty());

  // test wxExGrid
  CPPUNIT_ASSERT(m_Grid->CreateGrid(5, 5));
  m_Grid->SetGridCellValue(wxGridCellCoords(0, 0), "test");
  m_Grid->SelectAll();
  CPPUNIT_ASSERT(!m_Grid->GetSelectedCellsValue().empty());
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test");
  m_Grid->SetCellsValue(wxGridCellCoords(0, 0), "test1\ttest2\ntest3\ttest4\n");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test1");

  // test wxExListView
  m_ListView->SetSingleStyle(wxLC_REPORT); // wxLC_ICON);
  m_ListView->InsertColumn("String", wxExColumn::COL_STRING);
  m_ListView->InsertColumn("Number", wxExColumn::COL_INT);
  CPPUNIT_ASSERT(m_ListView->FindColumn("String") == 0);
  CPPUNIT_ASSERT(m_ListView->FindColumn("Number") == 1);
  wxExListItem item1(m_ListView, "c item"); ///< testing wxExListItem
  item1.Insert();
  wxExListItem item2(m_ListView, "b item"); ///< testing wxExListItem
  item2.Insert();
  wxExListItem item3(m_ListView, "a item"); ///< testing wxExListItem
  item3.Insert();
  m_ListView->SortColumn(0, SORT_ASCENDING);
  wxExListItem test(m_ListView, 0);
  CPPUNIT_ASSERT(test.GetColumnText(0) == "a item");

  // test wxExNotebook (parent should not be NULL)
  wxWindow* page1 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  wxWindow* page2 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page2, "key2") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") == NULL);
  CPPUNIT_ASSERT(m_Notebook->GetKeyByPage(page1) == "key1");
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("key1") == page1);
  CPPUNIT_ASSERT(m_Notebook->SetPageText("key1", "keyx", "hello"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == page1);
  CPPUNIT_ASSERT(m_Notebook->DeletePage("keyx"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == NULL);

  // test wxExSTC
  // do the same test as with wxExFile in base for a binary file
  CPPUNIT_ASSERT(m_STC->Open(wxExFileName(TEST_BIN)));
  CPPUNIT_ASSERT(m_STC->GetFlags() == 0);
  CPPUNIT_ASSERT(m_STC->GetMenuFlags() == wxExSTC::STC_MENU_DEFAULT);
  const wxCharBuffer& buffer = m_STC->GetTextRaw();
  wxLogMessage(buffer.data());
  CPPUNIT_ASSERT(buffer.length() == 40);
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StartRecord();
  CPPUNIT_ASSERT( m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StopRecord();
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded()); // still no macro

  // test wxExSTCShell
  m_STCShell->Prompt("test1");
  m_STCShell->Prompt("test2");
  m_STCShell->Prompt("test3");
  m_STCShell->Prompt("test4");
  // Prompting does not add a command to history.
  CPPUNIT_ASSERT(!m_STCShell->GetHistory().Contains("test4"));
  // Post 3 'a' chars to the shell, and check whether it comes in the history.
  wxKeyEvent event(wxEVT_CHAR);
  event.m_keyCode = 97; // one char 'a'
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  event.m_keyCode = WXK_RETURN;
  wxPostEvent(m_STCShell, event);
  // The event queue for shell is not yet processed, so next will assert anyway.
  //CPPUNIT_ASSERT(m_STCShell->GetHistory().Contains("aaa"));

  // test wxExSVN
//  CPPUNIT_ASSERT(m_SVN->Execute(NULL) == 0); // do not use a dialog
//  CPPUNIT_ASSERT(!m_SVN->GetOutput().empty());

  // test util
  CPPUNIT_ASSERT(wxExClipboardAdd("test"));
  CPPUNIT_ASSERT(wxExClipboardGet() == "test");
  CPPUNIT_ASSERT(wxExGetNumberOfLines("test\ntest\n") == 3);
  CPPUNIT_ASSERT(wxExGetLineNumberFromText("test on line: 1200") == 1200);

  // Only usefull if the lexers file was present
  if (wxExApp::GetLexers()->Count() > 0)
  {
    wxExApp::GetConfig()->Set(_("Purpose"), "hello test");
    const wxExFileName fn(TEST_FILE);
    const wxString header = wxExHeader(wxExApp::GetConfig()).Get(&fn);
    CPPUNIT_ASSERT(header.Contains("hello test"));
  }
  else
  {
    wxLogMessage("No lexers available");
  }

  CPPUNIT_ASSERT(wxExLog("hello from wxextension test"));
  CPPUNIT_ASSERT(!wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp"));
  CPPUNIT_ASSERT(wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp;*.txt"));
  CPPUNIT_ASSERT(wxExSkipWhiteSpace("t     es   t") == "t es t");
  CPPUNIT_ASSERT(!wxExTranslate("hello @PAGENUM@ from @PAGESCNT@", 1, 2).Contains("@"));
}

void wxExAppTestFixture::tearDown()
{
}

wxExTestSuite::wxExTestSuite()
  : CppUnit::TestSuite("wxextension test suite")
{
  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testConstructors",
    &wxExAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testMethods",
    &wxExAppTestFixture::testMethods));
}
<commit_msg>sort using name instead of column<commit_after>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include <wx/extension/header.h>
#include <wx/extension/tool.h>
#include "test.h"

#define TEST_FILE "./test.h"
#define TEST_BIN "./test.bin"

void wxExAppTestFixture::setUp()
{
  m_Grid = new wxExGrid(wxTheApp->GetTopWindow());
  m_ListView = new wxExListView(wxTheApp->GetTopWindow());
  m_Notebook = new wxExNotebook(wxTheApp->GetTopWindow(), NULL);
  m_STC = new wxExSTC(wxTheApp->GetTopWindow(), wxExFileName(TEST_FILE));
  m_STCShell = new wxExSTCShell(wxTheApp->GetTopWindow());
  m_SVN = new wxExSVN(SVN_INFO, TEST_FILE);
}

void wxExAppTestFixture::testConstructors()
{
}

void wxExAppTestFixture::testMethods()
{
  // test wxExApp
  CPPUNIT_ASSERT(!wxExApp::GetCatalogDir().empty());
  CPPUNIT_ASSERT(wxExApp::GetConfig() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetLexers() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetPrinter() != NULL);
  CPPUNIT_ASSERT(!wxExTool::GetToolInfo().empty());

  // test wxExGrid
  CPPUNIT_ASSERT(m_Grid->CreateGrid(5, 5));
  m_Grid->SetGridCellValue(wxGridCellCoords(0, 0), "test");
  m_Grid->SelectAll();
  CPPUNIT_ASSERT(!m_Grid->GetSelectedCellsValue().empty());
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test");
  m_Grid->SetCellsValue(wxGridCellCoords(0, 0), "test1\ttest2\ntest3\ttest4\n");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test1");

  // test wxExListView
  m_ListView->SetSingleStyle(wxLC_REPORT); // wxLC_ICON);
  m_ListView->InsertColumn("String", wxExColumn::COL_STRING);
  m_ListView->InsertColumn("Number", wxExColumn::COL_INT);
  CPPUNIT_ASSERT(m_ListView->FindColumn("String") == 0);
  CPPUNIT_ASSERT(m_ListView->FindColumn("Number") == 1);
  wxExListItem item1(m_ListView, "c item"); ///< testing wxExListItem
  item1.Insert();
  wxExListItem item2(m_ListView, "b item"); ///< testing wxExListItem
  item2.Insert();
  wxExListItem item3(m_ListView, "a item"); ///< testing wxExListItem
  item3.Insert();
  m_ListView->SortColumn("String", SORT_ASCENDING);
  wxExListItem test(m_ListView, 0);
  CPPUNIT_ASSERT(test.GetColumnText("String") == "a item");

  // test wxExNotebook (parent should not be NULL)
  wxWindow* page1 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  wxWindow* page2 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page2, "key2") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") == NULL);
  CPPUNIT_ASSERT(m_Notebook->GetKeyByPage(page1) == "key1");
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("key1") == page1);
  CPPUNIT_ASSERT(m_Notebook->SetPageText("key1", "keyx", "hello"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == page1);
  CPPUNIT_ASSERT(m_Notebook->DeletePage("keyx"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == NULL);

  // test wxExSTC
  // do the same test as with wxExFile in base for a binary file
  CPPUNIT_ASSERT(m_STC->Open(wxExFileName(TEST_BIN)));
  CPPUNIT_ASSERT(m_STC->GetFlags() == 0);
  CPPUNIT_ASSERT(m_STC->GetMenuFlags() == wxExSTC::STC_MENU_DEFAULT);
  const wxCharBuffer& buffer = m_STC->GetTextRaw();
  wxLogMessage(buffer.data());
  CPPUNIT_ASSERT(buffer.length() == 40);
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StartRecord();
  CPPUNIT_ASSERT( m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StopRecord();
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded()); // still no macro

  // test wxExSTCShell
  m_STCShell->Prompt("test1");
  m_STCShell->Prompt("test2");
  m_STCShell->Prompt("test3");
  m_STCShell->Prompt("test4");
  // Prompting does not add a command to history.
  CPPUNIT_ASSERT(!m_STCShell->GetHistory().Contains("test4"));
  // Post 3 'a' chars to the shell, and check whether it comes in the history.
  wxKeyEvent event(wxEVT_CHAR);
  event.m_keyCode = 97; // one char 'a'
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  wxPostEvent(m_STCShell, event);
  event.m_keyCode = WXK_RETURN;
  wxPostEvent(m_STCShell, event);
  // The event queue for shell is not yet processed, so next will assert anyway.
  //CPPUNIT_ASSERT(m_STCShell->GetHistory().Contains("aaa"));

  // test wxExSVN
//  CPPUNIT_ASSERT(m_SVN->Execute(NULL) == 0); // do not use a dialog
//  CPPUNIT_ASSERT(!m_SVN->GetOutput().empty());

  // test util
  CPPUNIT_ASSERT(wxExClipboardAdd("test"));
  CPPUNIT_ASSERT(wxExClipboardGet() == "test");
  CPPUNIT_ASSERT(wxExGetNumberOfLines("test\ntest\n") == 3);
  CPPUNIT_ASSERT(wxExGetLineNumberFromText("test on line: 1200") == 1200);

  // Only usefull if the lexers file was present
  if (wxExApp::GetLexers()->Count() > 0)
  {
    wxExApp::GetConfig()->Set(_("Purpose"), "hello test");
    const wxExFileName fn(TEST_FILE);
    const wxString header = wxExHeader(wxExApp::GetConfig()).Get(&fn);
    CPPUNIT_ASSERT(header.Contains("hello test"));
  }
  else
  {
    wxLogMessage("No lexers available");
  }

  CPPUNIT_ASSERT(wxExLog("hello from wxextension test"));
  CPPUNIT_ASSERT(!wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp"));
  CPPUNIT_ASSERT(wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp;*.txt"));
  CPPUNIT_ASSERT(wxExSkipWhiteSpace("t     es   t") == "t es t");
  CPPUNIT_ASSERT(!wxExTranslate("hello @PAGENUM@ from @PAGESCNT@", 1, 2).Contains("@"));
}

void wxExAppTestFixture::tearDown()
{
}

wxExTestSuite::wxExTestSuite()
  : CppUnit::TestSuite("wxextension test suite")
{
  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testConstructors",
    &wxExAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testMethods",
    &wxExAppTestFixture::testMethods));
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 "ColumnPrinter.hh"
#include "Exceptions.hh"

#include <string>
#include <memory>
#include <iostream>
#include <string>

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cout << "Usage: file-metadata <filename>\n";
  }

  orc::ReaderOptions opts;
  std::list<int> cols;
  cols.push_back(0);
  opts.include(cols);

  std::unique_ptr<orc::Reader> reader;
  try{
    reader = orc::createReader(orc::readLocalFile(std::string(argv[1])), opts);
  } catch (orc::ParseError e) {
    std::cout << "Error reading file " << argv[1] << "! "
              << e.what() << std::endl;
    return -1;
  }

 // print out all selected columns statistics.
 std::list<orc::ColumnStatistics*> colStats = reader->getStatistics();
 std::cout << "File " << argv[1] << " has " << colStats.size() << " columns"  << std::endl;
 int i = 0;
 for(std::list<orc::ColumnStatistics*>::const_iterator iter = colStats.begin();
     iter != colStats.end(); iter++,i++) {
   std::cout << "Column " << i << ": " << std::endl;
   std::cout << (*iter)->toString() << std::endl;
 }

 // test stripe statistics
 std::unique_ptr<orc::StripeStatistics> stripeStats;
 std::cout << "File " << argv[1] << " has " << reader->getNumberOfStripes() << " stripes"  << std::endl;
 for (unsigned int i = 0; i < reader->getNumberOfStripes(); i++) {
   stripeStats = reader->getStripeStatistics(i);
   std::cout << "Stripe " << i << ": " << std::endl ;

   for(unsigned int i = 0; i < stripeStats->getNumberOfColumnStatistics(); ++i){
     std::cout << stripeStats->getColumnStatisticsInStripe(i)->toString() << std::endl;
   }
 }

  return 0;
}
<commit_msg>Fixed code that caused clang warnings.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 "ColumnPrinter.hh"
#include "Exceptions.hh"

#include <string>
#include <memory>
#include <iostream>
#include <string>

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cout << "Usage: file-metadata <filename>\n";
  }

  orc::ReaderOptions opts;
  std::list<int> cols;
  cols.push_back(0);
  opts.include(cols);

  std::unique_ptr<orc::Reader> reader;
  try{
    reader = orc::createReader(orc::readLocalFile(std::string(argv[1])), opts);
  } catch (orc::ParseError e) {
    std::cout << "Error reading file " << argv[1] << "! "
              << e.what() << std::endl;
    return -1;
  }

 // print out all selected columns statistics.
 std::list<orc::ColumnStatistics*> colStats = reader->getStatistics();
 std::cout << "File " << argv[1] << " has " << colStats.size() << " columns"  << std::endl;
 int i = 0;
 for(std::list<orc::ColumnStatistics*>::const_iterator iter = colStats.begin();
     iter != colStats.end(); iter++,i++) {
   std::cout << "*** Column " << i << " ***" << std::endl;
   std::cout << (*iter)->toString() << std::endl;
 }

 // test stripe statistics
 std::unique_ptr<orc::StripeStatistics> stripeStats;
 std::cout << "File " << argv[1] << " has " << reader->getNumberOfStripes() << " stripes"  << std::endl;
 for (unsigned int j = 0; j < reader->getNumberOfStripes(); j++) {
   stripeStats = reader->getStripeStatistics(j);
   std::cout << "*** Stripe " << j << " ***" << std::endl << std::endl ;

   for(unsigned int k = 0; k < stripeStats->getNumberOfColumnStatistics(); ++k){
     std::cout << "--- Column " << k << " ---" << std::endl;
     std::cout << stripeStats->getColumnStatisticsInStripe(k)->toString() << std::endl;
   }
 }

  return 0;
}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file Stm32Gpio.hxx
 *
 * Helper declarations for using GPIO pins (both for GPIO and other hardware)
 * on STM32 microcontrollers.
 *
 * @author Balazs Racz
 * @date 24 Aug 2015
 */

#ifndef _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
#define _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_

#include "os/Gpio.hxx"
#include "GpioWrapper.hxx"

#if defined(STM32F072xB) || defined(STM32F091xC)
#include "stm32f0xx_hal_gpio.h"
#elif defined(STM32F103xB)
#include "stm32f1xx_hal_gpio.h"
#elif defined(STM32F303xC) || defined(STM32F303xE)
#include "stm32f3xx_hal_gpio.h"
#elif defined(STM32F767xx)
#include "stm32f7xx_hal_gpio.h"
#else
#error Dont know what STM32 chip you have.
#endif

/// Static GPIO implementation for the STM32 microcontrollers. Do not use
/// directly: use @ref GPIO_PIN macro.
/// @param PORT is the port base address pointer (e.g. GPIOC)
/// @param PIN is the GPIO_PIN_# value for the pin number.
/// @param PIN_NUM is the number of the pin in the port. Zero-based.
template <uint32_t GPIOx, uint16_t PIN, uint8_t PIN_NUM> struct Stm32GpioDefs
{
    /// @return the PIO structure of the give gpio port.
    static GPIO_TypeDef *port()
    {
        return (GPIO_TypeDef *)GPIOx;
    }

    /// @return the pin number within the port.
    static uint16_t pin()
    {
        return PIN;
    }

    /// Sets the output pin to a given level.
    static void set(bool value)
    {
        if (value)
        {
// These alternatives are needed for old releases of STM32F HAL library.
#if 0 && (defined(STM32F303xC) || defined(STM32F303xE))
            port()->BSRRL = pin();
#else
            port()->BSRR = pin();
#endif
        }
        else
        {
#if 0 && (defined(STM32F303xC) || defined(STM32F303xE))
            port()->BSRRH = pin();
#else
            port()->BSRR = pin() << 16;
#endif
        }
    }

    /// Sets the output pin to a given level.
    static bool get()
    {
        return port()->IDR & pin();
    }

    /// @return a os-indepentent Gpio abstraction instance for use in
    /// libraries.
    static constexpr const Gpio *instance()
    {
        return GpioWrapper<Stm32GpioDefs<GPIOx, PIN, PIN_NUM>>::instance();
    }

    /// @return whether this pin is configured as an output.
    static bool is_output()
    {
        uint8_t* mode = (uint8_t*)port();
        uint8_t m = mode[PIN_NUM >> 1];
        if (PIN_NUM & 1) { m >>= 4; }
        return (m & 3) != 0;
    }

};

template <class Defs, bool SAFE_VALUE> struct GpioOutputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
        gpio_init.Pull = GPIO_NOPULL;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
        set(SAFE_VALUE);
    }
    /// Sets the output pin to a safe value.
    static void hw_set_to_safe()
    {
        hw_init();
        set(SAFE_VALUE);
    }
};

/// Defines a GPIO output pin, initialized to be an output pin with low level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLow : public GpioOutputPin<Defs, false>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHigh : public GpioOutputPin<Defs, true>
{
};

/// Defines a GPIO output pin for driving an LED. The MCU must be in spec for
/// the necessary output current.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs> struct LedPin : public GpioOutputPin<Defs, false>
{
};

template <class Defs, uint32_t PULL_MODE> struct GpioInputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_INPUT;
        gpio_init.Pull = PULL_MODE;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
    }
    /// Sets the hardware pin to a safe state.
    static void hw_set_to_safe()
    {
        hw_init();
    }
    /// @return true if the pin is set to drive an output.
    static bool is_output()
    {
        return false;
    }
};

/// GPIO Input pin with weak pull up.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPU : public GpioInputPin<Defs, GPIO_PULLUP>
{
};

/// GPIO Input pin with weak pull down.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPD : public GpioInputPin<Defs, GPIO_PULLDOWN>
{
};

/// GPIO Input pin in standard configuration (no pull).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputNP : public GpioInputPin<Defs, GPIO_NOPULL>
{
};

/// Helper macro for defining GPIO pins.
///
/// @param NAME is the basename of the declaration. For NAME==FOO the macro
/// declares FOO_Pin as a structure on which the read-write functions will be
/// available.
///
/// @param BaseClass is the initialization structure, such as @ref LedPin, or
/// @ref GpioOutputSafeHigh or @ref GpioOutputSafeLow.
///
/// @param PORTNAME is a letter defining which port this is (like A, B,
/// C). E.g. for PC8 this is C.
///
/// @param NUM is the pin number, such as 8 for PC8.
///
/// Example:
///  GPIO_PIN(FOO, LedPin, 0, 3);
///  ...
///  FOO_Pin::set(true);
#define GPIO_PIN(NAME, BaseClass, PORTNAME, NUM)                               \
    typedef BaseClass<Stm32GpioDefs<(uint32_t)(GPIO ## PORTNAME ## _BASE), GPIO_PIN_ ## NUM, NUM>> NAME##_Pin

#endif // _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
<commit_msg>fixes a typo.<commit_after>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file Stm32Gpio.hxx
 *
 * Helper declarations for using GPIO pins (both for GPIO and other hardware)
 * on STM32 microcontrollers.
 *
 * @author Balazs Racz
 * @date 24 Aug 2015
 */

#ifndef _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
#define _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_

#include "os/Gpio.hxx"
#include "GpioWrapper.hxx"

#if defined(STM32F072xB) || defined(STM32F091xC)
#include "stm32f0xx_hal_gpio.h"
#elif defined(STM32F103xB)
#include "stm32f1xx_hal_gpio.h"
#elif defined(STM32F303xC) || defined(STM32F303xE)
#include "stm32f3xx_hal_gpio.h"
#elif defined(STM32F767xx)
#include "stm32f7xx_hal_gpio.h"
#else
#error Dont know what STM32 chip you have.
#endif

/// Static GPIO implementation for the STM32 microcontrollers. Do not use
/// directly: use @ref GPIO_PIN macro.
/// @param PORT is the port base address pointer (e.g. GPIOC)
/// @param PIN is the GPIO_PIN_# value for the pin number.
/// @param PIN_NUM is the number of the pin in the port. Zero-based.
template <uint32_t GPIOx, uint16_t PIN, uint8_t PIN_NUM> struct Stm32GpioDefs
{
    /// @return the GPIO structure of the given gpio port.
    static GPIO_TypeDef *port()
    {
        return (GPIO_TypeDef *)GPIOx;
    }

    /// @return the pin number within the port.
    static uint16_t pin()
    {
        return PIN;
    }

    /// Sets the output pin to a given level.
    static void set(bool value)
    {
        if (value)
        {
// These alternatives are needed for old releases of STM32F HAL library.
#if 0 && (defined(STM32F303xC) || defined(STM32F303xE))
            port()->BSRRL = pin();
#else
            port()->BSRR = pin();
#endif
        }
        else
        {
#if 0 && (defined(STM32F303xC) || defined(STM32F303xE))
            port()->BSRRH = pin();
#else
            port()->BSRR = pin() << 16;
#endif
        }
    }

    /// Sets the output pin to a given level.
    static bool get()
    {
        return port()->IDR & pin();
    }

    /// @return a os-indepentent Gpio abstraction instance for use in
    /// libraries.
    static constexpr const Gpio *instance()
    {
        return GpioWrapper<Stm32GpioDefs<GPIOx, PIN, PIN_NUM>>::instance();
    }

    /// @return whether this pin is configured as an output.
    static bool is_output()
    {
        uint8_t* mode = (uint8_t*)port();
        uint8_t m = mode[PIN_NUM >> 1];
        if (PIN_NUM & 1) { m >>= 4; }
        return (m & 3) != 0;
    }

};

template <class Defs, bool SAFE_VALUE> struct GpioOutputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
        gpio_init.Pull = GPIO_NOPULL;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
        set(SAFE_VALUE);
    }
    /// Sets the output pin to a safe value.
    static void hw_set_to_safe()
    {
        hw_init();
        set(SAFE_VALUE);
    }
};

/// Defines a GPIO output pin, initialized to be an output pin with low level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLow : public GpioOutputPin<Defs, false>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHigh : public GpioOutputPin<Defs, true>
{
};

/// Defines a GPIO output pin for driving an LED. The MCU must be in spec for
/// the necessary output current.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs> struct LedPin : public GpioOutputPin<Defs, false>
{
};

template <class Defs, uint32_t PULL_MODE> struct GpioInputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_INPUT;
        gpio_init.Pull = PULL_MODE;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
    }
    /// Sets the hardware pin to a safe state.
    static void hw_set_to_safe()
    {
        hw_init();
    }
    /// @return true if the pin is set to drive an output.
    static bool is_output()
    {
        return false;
    }
};

/// GPIO Input pin with weak pull up.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPU : public GpioInputPin<Defs, GPIO_PULLUP>
{
};

/// GPIO Input pin with weak pull down.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPD : public GpioInputPin<Defs, GPIO_PULLDOWN>
{
};

/// GPIO Input pin in standard configuration (no pull).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputNP : public GpioInputPin<Defs, GPIO_NOPULL>
{
};

/// Helper macro for defining GPIO pins.
///
/// @param NAME is the basename of the declaration. For NAME==FOO the macro
/// declares FOO_Pin as a structure on which the read-write functions will be
/// available.
///
/// @param BaseClass is the initialization structure, such as @ref LedPin, or
/// @ref GpioOutputSafeHigh or @ref GpioOutputSafeLow.
///
/// @param PORTNAME is a letter defining which port this is (like A, B,
/// C). E.g. for PC8 this is C.
///
/// @param NUM is the pin number, such as 8 for PC8.
///
/// Example:
///  GPIO_PIN(FOO, LedPin, 0, 3);
///  ...
///  FOO_Pin::set(true);
#define GPIO_PIN(NAME, BaseClass, PORTNAME, NUM)                               \
    typedef BaseClass<Stm32GpioDefs<(uint32_t)(GPIO ## PORTNAME ## _BASE), GPIO_PIN_ ## NUM, NUM>> NAME##_Pin

#endif // _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include "test.h"

void wxExAppTestFixture::setUp()
{
  m_Grid = new wxExGrid(wxTheApp->GetTopWindow());
  m_ListView = new wxExListView(wxTheApp->GetTopWindow());
  m_Notebook = new wxExNotebook(wxTheApp->GetTopWindow(), NULL);
  m_STC = new wxExSTC(wxTheApp->GetTopWindow(), wxExFileName("test.h"));
  m_STCShell = new wxExSTCShell(wxTheApp->GetTopWindow());
  m_SVN = new wxExSVN(SVN_STAT, "test.h");
}

void wxExAppTestFixture::testConstructors()
{
}

void wxExAppTestFixture::testMethods()
{
  // test wxExApp
  CPPUNIT_ASSERT(wxExApp::GetConfig() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetLexers() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetPrinter() != NULL);
  CPPUNIT_ASSERT(!wxExTool::GetToolInfo().empty());

  // test wxExGrid
  CPPUNIT_ASSERT(m_Grid->CreateGrid(5, 5));
  m_Grid->SelectAll();
  m_Grid->SetGridCellValue(wxGridCellCoords(0, 0), "test");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test");
  m_Grid->SetCellsValue(wxGridCellCoords(0, 0), "test1\ttest2\ntest3\ttest4\n");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test1");

  // test wxExListView
  m_ListView->SetSingleStyle(wxLC_REPORT); // wxLC_ICON);
  m_ListView->InsertColumn("String", wxExColumn::COL_STRING);
  m_ListView->InsertColumn("Number", wxExColumn::COL_INT);
  CPPUNIT_ASSERT(m_ListView->FindColumn("String") == 0);
  CPPUNIT_ASSERT(m_ListView->FindColumn("Number") == 1);

  // test wxExNotebook (parent should not be NULL)
  wxWindow* page1 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  wxWindow* page2 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);

  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page2, "key2") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") == NULL);
  CPPUNIT_ASSERT(m_Notebook->GetKeyByPage(page1) == "key1");
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("key1") == page1);
  CPPUNIT_ASSERT(m_Notebook->SetPageText("key1", "keyx", "hello"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == page1);
  CPPUNIT_ASSERT(m_Notebook->DeletePage("keyx"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == NULL);

  // test wxExSTC
  CPPUNIT_ASSERT(m_STC->GetFileName().GetFullName() == "test.h");
  // do the same test as with wxExFile in base for a binary file
  CPPUNIT_ASSERT(m_STC->Open(wxExFileName("../base/test.bin")));
  CPPUNIT_ASSERT(m_STC->GetFlags() == 0);
  const wxCharBuffer& buffer = m_STC->GetTextRaw();
  wxLogMessage(buffer.data());
  CPPUNIT_ASSERT(buffer.length() == 40);
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StartRecord();
  CPPUNIT_ASSERT( m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StopRecord();
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded()); // still no macro

  // test wxExSTCShell
  m_STCShell->Prompt("test1");
  m_STCShell->Prompt("test2");
  m_STCShell->Prompt("test3");
  m_STCShell->Prompt("test4");
  // Prompting does not add a command to history...
  // TODO: Make a better test.
  CPPUNIT_ASSERT(!m_STCShell->GetHistory().Contains("test4"));

  // test wxExSVN
// Next test fails (hangs)
//  CPPUNIT_ASSERT(m_SVN->Execute(false) == 0); // do not use a dialog
  // The output depends on the svn stat, of course,
  // so do not assert on it.
  m_SVN->GetOutput();

  // test various wxEx methods that need the app
  // Only usefull if the lexers file was present
  if (wxExApp::GetLexers()->Count() > 0)
  {
    const wxString header = wxExHeader(wxExFileName("test.h"), wxExApp::GetConfig(), "hello test");
    CPPUNIT_ASSERT(header.Contains("hello test"));
  }
  else
  {
    wxLogMessage("No lexers available");
  }

  // test util
  CPPUNIT_ASSERT(wxExClipboardAdd("test"));
  CPPUNIT_ASSERT(wxExClipboardGet() == "test");
  CPPUNIT_ASSERT(wxExGetNumberOfLines("test\ntest\n") == 3);
  CPPUNIT_ASSERT(wxExGetLineNumberFromText("test on line: 1200") == 1200);
  CPPUNIT_ASSERT(wxExLog("hello from wxextension test"));
  CPPUNIT_ASSERT(!wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp"));
  CPPUNIT_ASSERT(wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp;*.txt"));
  CPPUNIT_ASSERT(wxExSkipWhiteSpace("t     es   t") == "t es t");
}

void wxExAppTestFixture::tearDown()
{
}

wxExTestSuite::wxExTestSuite()
  : CppUnit::TestSuite("wxextension test suite")
{
  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testConstructors",
    &wxExAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testMethods",
    &wxExAppTestFixture::testMethods));
}
<commit_msg>updated test for new wxExHeader API<commit_after>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include "test.h"

void wxExAppTestFixture::setUp()
{
  m_Grid = new wxExGrid(wxTheApp->GetTopWindow());
  m_ListView = new wxExListView(wxTheApp->GetTopWindow());
  m_Notebook = new wxExNotebook(wxTheApp->GetTopWindow(), NULL);
  m_STC = new wxExSTC(wxTheApp->GetTopWindow(), wxExFileName("test.h"));
  m_STCShell = new wxExSTCShell(wxTheApp->GetTopWindow());
  m_SVN = new wxExSVN(SVN_STAT, "test.h");
}

void wxExAppTestFixture::testConstructors()
{
}

void wxExAppTestFixture::testMethods()
{
  // test wxExApp
  CPPUNIT_ASSERT(wxExApp::GetConfig() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetLexers() != NULL);
  CPPUNIT_ASSERT(wxExApp::GetPrinter() != NULL);
  CPPUNIT_ASSERT(!wxExTool::GetToolInfo().empty());

  // test wxExGrid
  CPPUNIT_ASSERT(m_Grid->CreateGrid(5, 5));
  m_Grid->SelectAll();
  m_Grid->SetGridCellValue(wxGridCellCoords(0, 0), "test");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test");
  m_Grid->SetCellsValue(wxGridCellCoords(0, 0), "test1\ttest2\ntest3\ttest4\n");
  CPPUNIT_ASSERT(m_Grid->GetCellValue(0, 0) == "test1");

  // test wxExListView
  m_ListView->SetSingleStyle(wxLC_REPORT); // wxLC_ICON);
  m_ListView->InsertColumn("String", wxExColumn::COL_STRING);
  m_ListView->InsertColumn("Number", wxExColumn::COL_INT);
  CPPUNIT_ASSERT(m_ListView->FindColumn("String") == 0);
  CPPUNIT_ASSERT(m_ListView->FindColumn("Number") == 1);

  // test wxExNotebook (parent should not be NULL)
  wxWindow* page1 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  wxWindow* page2 = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);

  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page2, "key2") != NULL);
  CPPUNIT_ASSERT(m_Notebook->AddPage(page1, "key1") == NULL);
  CPPUNIT_ASSERT(m_Notebook->GetKeyByPage(page1) == "key1");
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("key1") == page1);
  CPPUNIT_ASSERT(m_Notebook->SetPageText("key1", "keyx", "hello"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == page1);
  CPPUNIT_ASSERT(m_Notebook->DeletePage("keyx"));
  CPPUNIT_ASSERT(m_Notebook->GetPageByKey("keyx") == NULL);

  // test wxExSTC
  CPPUNIT_ASSERT(m_STC->GetFileName().GetFullName() == "test.h");
  // do the same test as with wxExFile in base for a binary file
  CPPUNIT_ASSERT(m_STC->Open(wxExFileName("../base/test.bin")));
  CPPUNIT_ASSERT(m_STC->GetFlags() == 0);
  const wxCharBuffer& buffer = m_STC->GetTextRaw();
  wxLogMessage(buffer.data());
  CPPUNIT_ASSERT(buffer.length() == 40);
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StartRecord();
  CPPUNIT_ASSERT( m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded());
  m_STC->StopRecord();
  CPPUNIT_ASSERT(!m_STC->MacroIsRecording());
  CPPUNIT_ASSERT(!m_STC->MacroIsRecorded()); // still no macro

  // test wxExSTCShell
  m_STCShell->Prompt("test1");
  m_STCShell->Prompt("test2");
  m_STCShell->Prompt("test3");
  m_STCShell->Prompt("test4");
  // Prompting does not add a command to history...
  // TODO: Make a better test.
  CPPUNIT_ASSERT(!m_STCShell->GetHistory().Contains("test4"));

  // test wxExSVN
// Next test fails (hangs)
//  CPPUNIT_ASSERT(m_SVN->Execute(false) == 0); // do not use a dialog
  // The output depends on the svn stat, of course,
  // so do not assert on it.
  m_SVN->GetOutput();

  // test various wxEx methods that need the app
  // Only usefull if the lexers file was present
  if (wxExApp::GetLexers()->Count() > 0)
  {
	wxExApp::GetConfig()->Set(_("Purpose"), "hello test");
    const wxString header = wxExHeader(wxExFileName("test.h"), wxExApp::GetConfig());
    CPPUNIT_ASSERT(header.Contains("hello test"));
  }
  else
  {
    wxLogMessage("No lexers available");
  }

  // test util
  CPPUNIT_ASSERT(wxExClipboardAdd("test"));
  CPPUNIT_ASSERT(wxExClipboardGet() == "test");
  CPPUNIT_ASSERT(wxExGetNumberOfLines("test\ntest\n") == 3);
  CPPUNIT_ASSERT(wxExGetLineNumberFromText("test on line: 1200") == 1200);
  CPPUNIT_ASSERT(wxExLog("hello from wxextension test"));
  CPPUNIT_ASSERT(!wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp"));
  CPPUNIT_ASSERT(wxExMatchesOneOf(wxFileName("test.txt"), "*.cpp;*.txt"));
  CPPUNIT_ASSERT(wxExSkipWhiteSpace("t     es   t") == "t es t");
}

void wxExAppTestFixture::tearDown()
{
}

wxExTestSuite::wxExTestSuite()
  : CppUnit::TestSuite("wxextension test suite")
{
  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testConstructors",
    &wxExAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<wxExAppTestFixture>(
    "testMethods",
    &wxExAppTestFixture::testMethods));
}
<|endoftext|>


<commit_before>/*
 The MIT License (MIT)

 Copyright (c) 2013-2015 SRS(simple-rtmp-server)

 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <srs_app_process.hpp>

#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>

// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
#ifndef _WIN32
#include <unistd.h>
#endif

using namespace std;

#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_app_config.hpp>
#include <srs_app_utility.hpp>

SrsProcess::SrsProcess()
{
    is_started         = false;
    fast_stopped       = false;
    pid                = -1;
}

SrsProcess::~SrsProcess()
{
}

bool SrsProcess::started()
{
    return is_started;
}

int SrsProcess::initialize(string binary, vector<string> argv)
{
    int ret = ERROR_SUCCESS;

    bin = binary;

    for (int i = 0; i < (int)argv.size(); i++) {
        std::string ffp = argv[i];
        cli += " " + ffp;
    }

    for (int i = 0; i < (int)argv.size(); i++) {
        std::string ffp = argv[i];

        // remove the stdout and stderr.
        if (ffp == "1") {
            if (i + 2 < (int)argv.size()) {
                stdout_file = argv[i + 2];
                i += 2;
            }
            continue;
        } else if (ffp == "2") {
            if (i + 2 < (int)argv.size()) {
                stderr_file = argv[i + 2];
                i += 2;
            }
            continue;
        }

        // startup params.
        params.push_back(ffp);
    }

    return ret;
}

int SrsProcess::start()
{
    int ret = ERROR_SUCCESS;

    if (is_started) {
        return ret;
    }

    // generate the argv of process.
    srs_trace("fork process: %s", cli.c_str());

    // for log
    int cid = _srs_context->get_id();
    int ppid = getpid();

    // TODO: fork or vfork?
    if ((pid = fork()) < 0) {
        ret = ERROR_ENCODER_FORK;
        srs_error("vfork process failed. ret=%d", ret);
        return ret;
    }

    // child process: ffmpeg encoder engine.
    if (pid == 0) {
        // ignore the SIGINT and SIGTERM
        signal(SIGINT, SIG_IGN);
        signal(SIGTERM, SIG_IGN);

        // redirect stdout to file.
        if (!stdout_file.empty()) {
            int stdout_fd = -1;
            int flags = O_CREAT|O_WRONLY|O_APPEND;
            mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;

            if ((stdout_fd = ::open(stdout_file.c_str(), flags, mode)) < 0) {
                ret = ERROR_ENCODER_OPEN;
                fprintf(stderr, "open process stdout %s failed. ret=%d", stdout_file.c_str(), ret);
                return ret;
            }

            if (dup2(stdout_fd, STDOUT_FILENO) < 0) {
                ret = ERROR_ENCODER_DUP2;
                srs_error("dup2 process stdout failed. ret=%d", ret);
                return ret;
            }
        }

        // redirect stderr to file.
        if (!stderr_file.empty()) {
            int stderr_fd = -1;
            int flags = O_CREAT|O_WRONLY|O_APPEND;
            mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;

            if ((stderr_fd = ::open(stderr_file.c_str(), flags, mode)) < 0) {
                ret = ERROR_ENCODER_OPEN;
                fprintf(stderr, "open process stderr %s failed. ret=%d", stderr_file.c_str(), ret);
                return ret;
            }

            if (dup2(stderr_fd, STDERR_FILENO) < 0) {
                ret = ERROR_ENCODER_DUP2;
                srs_error("dup2 process stderr failed. ret=%d", ret);
                return ret;
            }
        }

        // log basic info
        if (true) {
            fprintf(stderr, "\n");
            fprintf(stderr, "process parent pid=%d\n", ppid);
            fprintf(stderr, "process parent cid=%d\n", cid);
            fprintf(stderr, "process binary=%s\n", bin.c_str());
            fprintf(stderr, "process cli: %s\n", cli.c_str());
        }

        // close other fds
        // TODO: do in right way.
        for (int i = 3; i < 1024; i++) {
            ::close(i);
        }

        // memory leak in child process, it's ok.
        char** charpv_params = new char*[params.size() + 1];
        for (int i = 0; i < (int)params.size(); i++) {
            std::string& p = params[i];
            charpv_params[i] = (char*)p.data();
        }
        // EOF: NULL
        charpv_params[params.size()] = NULL;

        // TODO: execv or execvp
        ret = execv(bin.c_str(), charpv_params);
        if (ret < 0) {
            fprintf(stderr, "fork process failed, errno=%d(%s)", errno, strerror(errno));
        }
        exit(ret);
    }

    // parent.
    if (pid > 0) {
        is_started = true;
        srs_trace("vfored process, pid=%d, bin=%s", pid, bin.c_str());
        return ret;
    }

    return ret;
}

int SrsProcess::cycle()
{
    int ret = ERROR_SUCCESS;

    if (!is_started) {
        return ret;
    }

    // ffmpeg is prepare to stop, donot cycle.
    if (fast_stopped) {
        return ret;
    }

    int status = 0;
    pid_t p = waitpid(pid, &status, WNOHANG);

    if (p < 0) {
        ret = ERROR_SYSTEM_WAITPID;
        srs_error("process waitpid failed, pid=%d, ret=%d", pid, ret);
        return ret;
    }

    if (p == 0) {
        srs_info("process process pid=%d is running.", pid);
        return ret;
    }

    srs_trace("process pid=%d terminate, restart it.", pid);
    is_started = false;

    return ret;
}

void SrsProcess::stop()
{
    if (!is_started) {
        return;
    }

    // kill the ffmpeg,
    // when rewind, upstream will stop publish(unpublish),
    // unpublish event will stop all ffmpeg encoders,
    // then publish will start all ffmpeg encoders.
    int ret = srs_kill_forced(pid);
    if (ret != ERROR_SUCCESS) {
        srs_warn("ignore kill the process failed, pid=%d. ret=%d", pid, ret);
        return;
    }

    // terminated, set started to false to stop the cycle.
    is_started = false;
}

void SrsProcess::fast_stop()
{
    int ret = ERROR_SUCCESS;

    if (!is_started) {
        return;
    }

    if (pid <= 0) {
        return;
    }

    if (kill(pid, SIGTERM) < 0) {
        ret = ERROR_SYSTEM_KILL;
        srs_warn("ignore fast stop process failed, pid=%d. ret=%d", pid, ret);
        return;
    }

    return;
}

<commit_msg>fix the process restart bug.<commit_after>/*
 The MIT License (MIT)

 Copyright (c) 2013-2015 SRS(simple-rtmp-server)

 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <srs_app_process.hpp>

#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>

// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213
#ifndef _WIN32
#include <unistd.h>
#endif

using namespace std;

#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_app_config.hpp>
#include <srs_app_utility.hpp>

SrsProcess::SrsProcess()
{
    is_started         = false;
    fast_stopped       = false;
    pid                = -1;
}

SrsProcess::~SrsProcess()
{
}

bool SrsProcess::started()
{
    return is_started;
}

int SrsProcess::initialize(string binary, vector<string> argv)
{
    int ret = ERROR_SUCCESS;

    bin = binary;
    cli = "";
    params.clear();

    for (int i = 0; i < (int)argv.size(); i++) {
        std::string ffp = argv[i];
        cli += ffp;
        if (i < (int)argv.size() - 1) {
            cli += " ";
        }
    }

    for (int i = 0; i < (int)argv.size(); i++) {
        std::string ffp = argv[i];

        // remove the stdout and stderr.
        if (ffp == "1") {
            if (i + 2 < (int)argv.size()) {
                stdout_file = argv[i + 2];
                i += 2;
            }
            continue;
        } else if (ffp == "2") {
            if (i + 2 < (int)argv.size()) {
                stderr_file = argv[i + 2];
                i += 2;
            }
            continue;
        }

        // startup params.
        params.push_back(ffp);
    }

    return ret;
}

int SrsProcess::start()
{
    int ret = ERROR_SUCCESS;

    if (is_started) {
        return ret;
    }

    // generate the argv of process.
    srs_trace("fork process: %s", cli.c_str());

    // for log
    int cid = _srs_context->get_id();
    int ppid = getpid();

    // TODO: fork or vfork?
    if ((pid = fork()) < 0) {
        ret = ERROR_ENCODER_FORK;
        srs_error("vfork process failed. ret=%d", ret);
        return ret;
    }

    // child process: ffmpeg encoder engine.
    if (pid == 0) {
        // ignore the SIGINT and SIGTERM
        signal(SIGINT, SIG_IGN);
        signal(SIGTERM, SIG_IGN);

        // redirect stdout to file.
        if (!stdout_file.empty()) {
            int stdout_fd = -1;
            int flags = O_CREAT|O_WRONLY|O_APPEND;
            mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;

            if ((stdout_fd = ::open(stdout_file.c_str(), flags, mode)) < 0) {
                ret = ERROR_ENCODER_OPEN;
                fprintf(stderr, "open process stdout %s failed. ret=%d", stdout_file.c_str(), ret);
                return ret;
            }

            if (dup2(stdout_fd, STDOUT_FILENO) < 0) {
                ret = ERROR_ENCODER_DUP2;
                srs_error("dup2 process stdout failed. ret=%d", ret);
                return ret;
            }
        }

        // redirect stderr to file.
        if (!stderr_file.empty()) {
            int stderr_fd = -1;
            int flags = O_CREAT|O_WRONLY|O_APPEND;
            mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;

            if ((stderr_fd = ::open(stderr_file.c_str(), flags, mode)) < 0) {
                ret = ERROR_ENCODER_OPEN;
                fprintf(stderr, "open process stderr %s failed. ret=%d", stderr_file.c_str(), ret);
                return ret;
            }

            if (dup2(stderr_fd, STDERR_FILENO) < 0) {
                ret = ERROR_ENCODER_DUP2;
                srs_error("dup2 process stderr failed. ret=%d", ret);
                return ret;
            }
        }

        // log basic info
        if (true) {
            fprintf(stderr, "\n");
            fprintf(stderr, "process parent pid=%d\n", ppid);
            fprintf(stderr, "process parent cid=%d\n", cid);
            fprintf(stderr, "process binary=%s\n", bin.c_str());
            fprintf(stderr, "process cli: %s\n", cli.c_str());
        }

        // close other fds
        // TODO: do in right way.
        for (int i = 3; i < 1024; i++) {
            ::close(i);
        }

        // memory leak in child process, it's ok.
        char** charpv_params = new char*[params.size() + 1];
        for (int i = 0; i < (int)params.size(); i++) {
            std::string& p = params[i];
            charpv_params[i] = (char*)p.data();
        }
        // EOF: NULL
        charpv_params[params.size()] = NULL;

        // TODO: execv or execvp
        ret = execv(bin.c_str(), charpv_params);
        if (ret < 0) {
            fprintf(stderr, "fork process failed, errno=%d(%s)", errno, strerror(errno));
        }
        exit(ret);
    }

    // parent.
    if (pid > 0) {
        is_started = true;
        srs_trace("vfored process, pid=%d, bin=%s", pid, bin.c_str());
        return ret;
    }

    return ret;
}

int SrsProcess::cycle()
{
    int ret = ERROR_SUCCESS;

    if (!is_started) {
        return ret;
    }

    // ffmpeg is prepare to stop, donot cycle.
    if (fast_stopped) {
        return ret;
    }

    int status = 0;
    pid_t p = waitpid(pid, &status, WNOHANG);

    if (p < 0) {
        ret = ERROR_SYSTEM_WAITPID;
        srs_error("process waitpid failed, pid=%d, ret=%d", pid, ret);
        return ret;
    }

    if (p == 0) {
        srs_info("process process pid=%d is running.", pid);
        return ret;
    }

    srs_trace("process pid=%d terminate, restart it.", pid);
    is_started = false;

    return ret;
}

void SrsProcess::stop()
{
    if (!is_started) {
        return;
    }

    // kill the ffmpeg,
    // when rewind, upstream will stop publish(unpublish),
    // unpublish event will stop all ffmpeg encoders,
    // then publish will start all ffmpeg encoders.
    int ret = srs_kill_forced(pid);
    if (ret != ERROR_SUCCESS) {
        srs_warn("ignore kill the process failed, pid=%d. ret=%d", pid, ret);
        return;
    }

    // terminated, set started to false to stop the cycle.
    is_started = false;
}

void SrsProcess::fast_stop()
{
    int ret = ERROR_SUCCESS;

    if (!is_started) {
        return;
    }

    if (pid <= 0) {
        return;
    }

    if (kill(pid, SIGTERM) < 0) {
        ret = ERROR_SYSTEM_KILL;
        srs_warn("ignore fast stop process failed, pid=%d. ret=%d", pid, ret);
        return;
    }

    return;
}

<|endoftext|>