<commit_before>#include "gui_web_cam_main_window.h"
#include "ui_gui_web_cam_main_window.h"

#include "../qt_utils/invoke_in_thread.h"
#include "../qt_utils/loop_thread.h"

#include <cassert>
#include <QGraphicsScene>
#include <QGraphicsVideoItem>
#include <QtMultimedia/QCameraInfo>

namespace gui {

struct WebCamMainWindow::Impl
{
    Ui::WebCamMainWindow ui;
    std::unique_ptr<QCamera> cam;
    QGraphicsScene scene;

    qu::LoopThread worker;
};

WebCamMainWindow::WebCamMainWindow(QWidget *parent) :
    QMainWindow(parent),
    m(new Impl)
{
    m->ui.setupUi(this);

    // switch to worker thread.
    qu::invokeInThread( &m->worker, [this](){

    const auto cams = QCameraInfo::availableCameras();
    const auto nCams = cams.count();

    // show number of cameras in statusbar.
    qu::invokeInGuiThread( [this,nCams](){
        m->ui.statusbar->showMessage(
                    QString("Found %1 camera(s).").arg(nCams) );
    } );

    if ( nCams > 0 )
    {
        // initialize camera.
        m->cam.reset( new QCamera(cams.front()) );
        m->cam->moveToThread( QCoreApplication::instance()->thread() );

        // switch to gui thread
        qu::invokeInGuiThread( [this,nCams](){

        // set QGraphicsItem as view finder and start capturing images.
        auto item = std::make_unique<QGraphicsVideoItem>();
        m->cam->setViewfinder( item.get() );
        m->cam->start();

        // put mirrored item into a QGraphicsScene.
        item->setMatrix( QMatrix(-1,0,0,1,0,0),true );
        m->scene.addItem(item.get());
        item.release();
        m->ui.graphicsView->setScene(&m->scene);

        } ); // end of gui thread execution
    }
    } ); // end of worker thread execution
}

WebCamMainWindow::~WebCamMainWindow()
{
}

} // namespace gui
<commit_msg>Frames are fitted to the size of the view.<commit_after>#include "gui_web_cam_main_window.h"
#include "ui_gui_web_cam_main_window.h"

#include "../qt_utils/event_filter.h"
#include "../qt_utils/invoke_in_thread.h"
#include "../qt_utils/loop_thread.h"

#include <cassert>
#include <QGraphicsScene>
#include <QGraphicsVideoItem>
#include <QPointer>
#include <QtMultimedia/QCameraInfo>

namespace gui {

struct WebCamMainWindow::Impl
{
    Ui::WebCamMainWindow ui;
    std::unique_ptr<QCamera> cam;
    QGraphicsScene scene;
    qu::LoopThread worker;

    // Makes sure the scene is always shown as big as possible.
    void makeVideoFitToView();

    // Puts a video display into the scene.
    void putVideoItemIntoScene();
};

WebCamMainWindow::WebCamMainWindow(QWidget *parent) :
    QMainWindow(parent),
    m(new Impl)
{
    m->ui.setupUi(this);
    m->makeVideoFitToView();
    m->putVideoItemIntoScene();
    m->ui.graphicsView->setScene(&m->scene);
}

WebCamMainWindow::~WebCamMainWindow()
{
}

void WebCamMainWindow::Impl::makeVideoFitToView()
{
    auto view = QPointer<QGraphicsView>(ui.graphicsView);
    qu::installEventFilter( ui.graphicsView,
                            [view]( QObject *, QEvent * event )
    {
        if ( event->type() == QEvent::Paint
             && view->scene() )
        {
            view->fitInView( view->sceneRect(),
                             Qt::KeepAspectRatio );
        }

        return false;
    });
}

void WebCamMainWindow::Impl::putVideoItemIntoScene()
{
    // switch to worker thread.
    qu::invokeInThread( &worker, [this](){

    const auto cams = QCameraInfo::availableCameras();
    const auto nCams = cams.count();

    // show number of cameras in statusbar.
    qu::invokeInGuiThread( [this,nCams](){
        ui.statusbar->showMessage(
                    QString("Found %1 camera(s).").arg(nCams) );
    } );

    if ( nCams > 0 )
    {
        // initialize camera.
        cam.reset( new QCamera(cams.front()) );
        cam->moveToThread( QCoreApplication::instance()->thread() );

        // switch to gui thread
        qu::invokeInGuiThread( [this,nCams](){

        // set QGraphicsItem as view finder and start capturing images.
        auto item = std::make_unique<QGraphicsVideoItem>();
        cam->setViewfinder( item.get() );
        cam->start();

        // put mirrored item into a QGraphicsScene.
        item->setMatrix( QMatrix(-1,0,0,1,0,0),true );
        scene.addItem(item.get());
        item.release();

        } ); // end of gui thread execution
    }
    } ); // end of worker thread execution
}

} // namespace gui
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "messagesender.h"

#include <QDateTime>
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QListWidget>
#include <QMessageBox>
#include <QPushButton>
#include <QTextEdit>
#include <QTimer>
#include <QDebug>

MessageSender::MessageSender(QWidget *parent, Qt::WindowFlags flags)
    : QWidget(parent, flags),
      toEdit(0),
      subjectEdit(0),
      textEdit(0),
      sendButton(0),
      removeButton(0),
      addButton(0),
      attachmentsList(0)
{
    setWindowTitle(tr("Send Message"));

    toEdit = new QLineEdit;

    subjectEdit = new QLineEdit;

    QLabel *toLabel = new QLabel(tr("To"));
    toLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    QLabel *subjectLabel = new QLabel(tr("Subject"));
    subjectLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    QGridLayout *metaDataLayout = new QGridLayout;
    metaDataLayout->addWidget(toLabel, 0, 0);
    metaDataLayout->setAlignment(toLabel, Qt::AlignRight);
    metaDataLayout->addWidget(subjectLabel, 1, 0);
    metaDataLayout->setAlignment(subjectLabel, Qt::AlignRight);
    metaDataLayout->addWidget(toEdit, 0, 1);
    metaDataLayout->addWidget(subjectEdit, 1, 1);

    removeButton = new QPushButton(tr("Remove"));
    removeButton->setEnabled(false);

    connect(removeButton, SIGNAL(clicked()), this, SLOT(removeAttachment()));

    addButton = new QPushButton(tr("Add"));

    connect(addButton, SIGNAL(clicked()), this, SLOT(addAttachment()));

    QVBoxLayout *buttonLayout = new QVBoxLayout;
    buttonLayout->addStretch();
    buttonLayout->addWidget(removeButton);
    buttonLayout->addWidget(addButton);

    attachmentsList = new QListWidget;
    attachmentsList->setSelectionMode(QAbstractItemView::SingleSelection);

    connect(attachmentsList, SIGNAL(currentRowChanged(int)), this, SLOT(attachmentSelected(int)));

    QHBoxLayout *attachmentsLayout = new QHBoxLayout;
    attachmentsLayout->addWidget(attachmentsList);
    attachmentsLayout->addLayout(buttonLayout);

    QGroupBox *attachmentsGroup = new QGroupBox(tr("Attachments"));
    attachmentsGroup->setLayout(attachmentsLayout);

    textEdit = new QTextEdit;

    sendButton = new QPushButton(tr("Send"));

    connect(sendButton, SIGNAL(clicked()), this, SLOT(send()), Qt::QueuedConnection);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addLayout(metaDataLayout, 0);
    mainLayout->addWidget(textEdit, 2);
    mainLayout->addWidget(attachmentsGroup, 1);
    mainLayout->addWidget(sendButton, 0);
    mainLayout->setAlignment(sendButton, Qt::AlignRight);

    connect(&service, SIGNAL(stateChanged(QMessageServiceAction::State)), this, SLOT(stateChanged(QMessageServiceAction::State)));
}

MessageSender::~MessageSender()
{
}

void MessageSender::removeAttachment()
{
    delete attachmentsList->takeItem(attachmentsList->currentRow());
    if (attachmentsList->count() == 0) {
        removeButton->setEnabled(false);
    }
}

void MessageSender::addAttachment()
{
    QString path(QFileDialog::getOpenFileName());
    if (!path.isEmpty()) {
        attachmentsList->addItem(new QListWidgetItem(path));
    }
}

void MessageSender::attachmentSelected(int)
{
    removeButton->setEnabled(true);
}

void MessageSender::send()
{
    QString to(toEdit->text());
    if (to.isEmpty()) {
        QMessageBox::warning(0, "Missing information", "Please enter a recipient address");
        return;
    }

    QString subject(subjectEdit->text());
    if (subject.isEmpty()) {
        QMessageBox::warning(0, "Missing information", "Please enter a subject");
        return;
    }

    QString text(textEdit->toPlainText());
    if (text.isEmpty()) {
        QMessageBox::warning(0, "Missing information", "Please enter a message");
        return;
    }

    QMessage message;
    message.setType(QMessage::Email);
    message.setTo(QMessageAddress(to, QMessageAddress::Email));
    message.setSubject(subject);

#ifdef QMESSAGING_OPTIONAL
    if (attachmentsList->count()) {
        QMessageContentContainer textPart;
        textPart.setContentType("text");
        textPart.setContentSubType("plain");
        textPart.setContentCharset("UTF-8");
        textPart.setContent(text);

        message.appendContent(textPart);

        QStringList paths;
        for (int i = 0; i < attachmentsList->count(); ++i) {
            paths.append(attachmentsList->item(i)->text());
        }

        message.appendAttachments(paths);
    } else {
        message.setContent(text);
    }
#endif

    if (service.send(message)) {
        sendButton->setEnabled(false);
        sendId = message.id();
    } else {
        QMessageBox::warning(0, "Failed", "Unable to send message");
    }
}

void MessageSender::stateChanged(QMessageServiceAction::State s)
{
    if (s == QMessageServiceAction::Successful) {
        QMessageBox::information(0, "Success", "Message sent successfully");
        sendButton->setEnabled(true);
    } else if (s == QMessageServiceAction::Failed) {
        QMessageBox::warning(0, "Failed", "Unable to send message");

        if (!QMessageStore::instance()->removeMessage(sendId)) {
            qWarning() << "Unable to remove failed message:" << sendId.toString();
        }

        sendButton->setEnabled(true);
        sendId = QMessageId();
    }
}

<commit_msg>Use the updated message construction interface.<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "messagesender.h"

#include <QDateTime>
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QListWidget>
#include <QMessageBox>
#include <QPushButton>
#include <QTextEdit>
#include <QTimer>
#include <QDebug>

MessageSender::MessageSender(QWidget *parent, Qt::WindowFlags flags)
    : QWidget(parent, flags),
      toEdit(0),
      subjectEdit(0),
      textEdit(0),
      sendButton(0),
      removeButton(0),
      addButton(0),
      attachmentsList(0)
{
    setWindowTitle(tr("Send Message"));

    toEdit = new QLineEdit;

    subjectEdit = new QLineEdit;

    QLabel *toLabel = new QLabel(tr("To"));
    toLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    QLabel *subjectLabel = new QLabel(tr("Subject"));
    subjectLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    QGridLayout *metaDataLayout = new QGridLayout;
    metaDataLayout->addWidget(toLabel, 0, 0);
    metaDataLayout->setAlignment(toLabel, Qt::AlignRight);
    metaDataLayout->addWidget(subjectLabel, 1, 0);
    metaDataLayout->setAlignment(subjectLabel, Qt::AlignRight);
    metaDataLayout->addWidget(toEdit, 0, 1);
    metaDataLayout->addWidget(subjectEdit, 1, 1);

    removeButton = new QPushButton(tr("Remove"));
    removeButton->setEnabled(false);

    connect(removeButton, SIGNAL(clicked()), this, SLOT(removeAttachment()));

    addButton = new QPushButton(tr("Add"));

    connect(addButton, SIGNAL(clicked()), this, SLOT(addAttachment()));

    QVBoxLayout *buttonLayout = new QVBoxLayout;
    buttonLayout->addStretch();
    buttonLayout->addWidget(removeButton);
    buttonLayout->addWidget(addButton);

    attachmentsList = new QListWidget;
    attachmentsList->setSelectionMode(QAbstractItemView::SingleSelection);

    connect(attachmentsList, SIGNAL(currentRowChanged(int)), this, SLOT(attachmentSelected(int)));

    QHBoxLayout *attachmentsLayout = new QHBoxLayout;
    attachmentsLayout->addWidget(attachmentsList);
    attachmentsLayout->addLayout(buttonLayout);

    QGroupBox *attachmentsGroup = new QGroupBox(tr("Attachments"));
    attachmentsGroup->setLayout(attachmentsLayout);

    textEdit = new QTextEdit;

    sendButton = new QPushButton(tr("Send"));

    connect(sendButton, SIGNAL(clicked()), this, SLOT(send()), Qt::QueuedConnection);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addLayout(metaDataLayout, 0);
    mainLayout->addWidget(textEdit, 2);
    mainLayout->addWidget(attachmentsGroup, 1);
    mainLayout->addWidget(sendButton, 0);
    mainLayout->setAlignment(sendButton, Qt::AlignRight);

    connect(&service, SIGNAL(stateChanged(QMessageServiceAction::State)), this, SLOT(stateChanged(QMessageServiceAction::State)));
}

MessageSender::~MessageSender()
{
}

void MessageSender::removeAttachment()
{
    delete attachmentsList->takeItem(attachmentsList->currentRow());
    if (attachmentsList->count() == 0) {
        removeButton->setEnabled(false);
    }
}

void MessageSender::addAttachment()
{
    QString path(QFileDialog::getOpenFileName());
    if (!path.isEmpty()) {
        attachmentsList->addItem(new QListWidgetItem(path));
    }
}

void MessageSender::attachmentSelected(int)
{
    removeButton->setEnabled(true);
}

void MessageSender::send()
{
    QString to(toEdit->text());
    if (to.isEmpty()) {
        QMessageBox::warning(0, "Missing information", "Please enter a recipient address");
        return;
    }

    QString subject(subjectEdit->text());
    if (subject.isEmpty()) {
        QMessageBox::warning(0, "Missing information", "Please enter a subject");
        return;
    }

    QString text(textEdit->toPlainText());
    if (text.isEmpty()) {
        QMessageBox::warning(0, "Missing information", "Please enter a message");
        return;
    }

    QMessage message;
    message.setType(QMessage::Email);
    message.setTo(QMessageAddress(to, QMessageAddress::Email));
    message.setSubject(subject);

    message.setBody(text);

    if (attachmentsList->count()) {
        QStringList paths;
        for (int i = 0; i < attachmentsList->count(); ++i) {
            paths.append(attachmentsList->item(i)->text());
        }

        message.appendAttachments(paths);
    }

    if (service.send(message)) {
        sendButton->setEnabled(false);
        sendId = message.id();
    } else {
        QMessageBox::warning(0, "Failed", "Unable to send message");
    }
}

void MessageSender::stateChanged(QMessageServiceAction::State s)
{
    if (s == QMessageServiceAction::Successful) {
        QMessageBox::information(0, "Success", "Message sent successfully");
        sendButton->setEnabled(true);
    } else if (s == QMessageServiceAction::Failed) {
        QMessageBox::warning(0, "Failed", "Unable to send message");

        if (!QMessageStore::instance()->removeMessage(sendId)) {
            qWarning() << "Unable to remove failed message:" << sendId.toString();
        }

        sendButton->setEnabled(true);
        sendId = QMessageId();
    }
}

<|endoftext|>


<commit_before>#include "events-impl.h"

#include "protocol/stress.pb.h"
#include "vtrc-client-base/vtrc-client.h"

#include "vtrc-common/vtrc-closure-holder.h"
#include "vtrc-common/vtrc-call-context.h"

#include "vtrc-chrono.h"
#include "vtrc-thread.h"

namespace stress {

    using namespace vtrc;
    namespace gpb = google::protobuf;

namespace {

    typedef vtrc::chrono::high_resolution_clock high_resolution_clock;
    typedef high_resolution_clock::time_point   time_point;

    size_t get_micro( const time_point &f, const time_point &l )
    {
        return chrono::duration_cast<chrono::microseconds>( l - f ).count( );
    }

    class events_impl: public vtrc_example::stress_events {

        client::vtrc_client_wptr client_;

        time_point last_event_point_;

    public:
        events_impl( vtrc::shared_ptr<vtrc::client::vtrc_client> c )
            :client_(c)
            ,last_event_point_(high_resolution_clock::now( ))
        { }
    private:

        void event(::google::protobuf::RpcController* controller,
                 const ::vtrc_example::event_req* request,
                 ::vtrc_example::event_res* response,
                 ::google::protobuf::Closure* done)
        {
            common::closure_holder holder( done );

            time_point this_event_point = high_resolution_clock::now( );

            std::cout << "Event id '" << request->id( ) << "'"
                      << "; "
                      << "previous: "
                      << get_micro( last_event_point_, this_event_point )
                      << " microseconds ago;"
                      << "; thread " << this_thread::get_id( )
                      << "\n";

            last_event_point_ = this_event_point;
        }

    };
}

    gpb::Service *create_events( vtrc::shared_ptr<client::vtrc_client> c )
    {
        return new events_impl( c );
    }

}
<commit_msg>examples<commit_after>#include "events-impl.h"

#include "protocol/stress.pb.h"
#include "vtrc-client-base/vtrc-client.h"

#include "vtrc-common/vtrc-closure-holder.h"
#include "vtrc-common/vtrc-call-context.h"

#include "vtrc-chrono.h"
#include "vtrc-thread.h"

namespace stress {

    using namespace vtrc;
    namespace gpb = google::protobuf;

namespace {

    typedef vtrc::chrono::high_resolution_clock high_resolution_clock;
    typedef high_resolution_clock::time_point   time_point;

    size_t get_micro( const time_point &f, const time_point &l )
    {
        return chrono::duration_cast<chrono::microseconds>( l - f ).count( );
    }

    class events_impl: public vtrc_example::stress_events {

        client::vtrc_client_wptr client_;

        time_point last_event_point_;

    public:
        events_impl( vtrc::shared_ptr<vtrc::client::vtrc_client> c )
            :client_(c)
            ,last_event_point_(high_resolution_clock::now( ))
        { }
    private:

        void event(::google::protobuf::RpcController* controller,
                 const ::vtrc_example::event_req* request,
                 ::vtrc_example::event_res* response,
                 ::google::protobuf::Closure* done)
        {
            common::closure_holder holder( done );

            time_point this_event_point = high_resolution_clock::now( );

            std::cout << "Event id '" << request->id( ) << "'"
                      << "; "
                      << "previous: "
                      << get_micro( last_event_point_, this_event_point )
                      << " microseconds ago"
                      << "; thread " << this_thread::get_id( )
                      << "\n";

            last_event_point_ = this_event_point;
        }

    };
}

    gpb::Service *create_events( vtrc::shared_ptr<client::vtrc_client> c )
    {
        return new events_impl( c );
    }

}
<|endoftext|>


<commit_before>/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*/

#include "HAL/Notifier.h"
#include <atomic>
#include <cstdlib>
#include <mutex>
#include "ChipObject.h"
#include "HAL/HAL.h"
#include "HAL/cpp/priority_mutex.h"

static const uint32_t kTimerInterruptNumber = 28;

static priority_mutex notifierInterruptMutex;
static priority_recursive_mutex notifierMutex;
static tAlarm* notifierAlarm = nullptr;
static tInterruptManager* notifierManager = nullptr;
static uint64_t closestTrigger = UINT64_MAX;
struct Notifier {
  Notifier *prev, *next;
  void* param;
  void (*process)(uint64_t, void*);
  uint64_t triggerTime = UINT64_MAX;
};
static Notifier* notifiers = nullptr;
static std::atomic_flag notifierAtexitRegistered = ATOMIC_FLAG_INIT;
static std::atomic_int notifierRefCount{0};

static void alarmCallback(uint32_t, void*) {
  std::unique_lock<priority_recursive_mutex> sync(notifierMutex);

  int32_t status = 0;
  uint64_t currentTime = 0;

  // the hardware disables itself after each alarm
  closestTrigger = UINT64_MAX;

  // process all notifiers
  Notifier* notifier = notifiers;
  while (notifier) {
    if (notifier->triggerTime != UINT64_MAX) {
      if (currentTime == 0) currentTime = getFPGATime(&status);
      if (notifier->triggerTime < currentTime) {
        notifier->triggerTime = UINT64_MAX;
        auto process = notifier->process;
        auto param = notifier->param;
        sync.unlock();
        process(currentTime, param);
        sync.lock();
      } else if (notifier->triggerTime < closestTrigger) {
        updateNotifierAlarm(notifier, notifier->triggerTime, &status);
      }
    }
    notifier = notifier->next;
  }
}

static void cleanupNotifierAtExit() {
  notifierAlarm = nullptr;
  notifierManager = nullptr;
}

extern "C" {

void* initializeNotifier(void (*process)(uint64_t, void*), void* param,
                         int32_t* status) {
  if (!process) {
    *status = NULL_PARAMETER;
    return nullptr;
  }
  if (!notifierAtexitRegistered.test_and_set())
    std::atexit(cleanupNotifierAtExit);
  if (notifierRefCount.fetch_add(1) == 0) {
    std::lock_guard<priority_mutex> sync(notifierInterruptMutex);
    // create manager and alarm if not already created
    if (!notifierManager) {
      notifierManager =
          new tInterruptManager(1 << kTimerInterruptNumber, false, status);
      notifierManager->registerHandler(alarmCallback, NULL, status);
      notifierManager->enable(status);
    }
    if (!notifierAlarm) notifierAlarm = tAlarm::create(status);
  }

  std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
  // create notifier structure and add to list
  Notifier* notifier = new Notifier();
  notifier->prev = nullptr;
  notifier->next = notifiers;
  if (notifier->next) notifier->next->prev = notifier;
  notifier->param = param;
  notifier->process = process;
  notifiers = notifier;
  return notifier;
}

void cleanNotifier(void* notifier_pointer, int32_t* status) {
  {
    std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
    Notifier* notifier = (Notifier*)notifier_pointer;

    // remove from list and delete
    if (notifier->prev) notifier->prev->next = notifier->next;
    if (notifier->next) notifier->next->prev = notifier->prev;
    if (notifiers == notifier) notifiers = notifier->next;
    delete notifier;
  }

  if (notifierRefCount.fetch_sub(1) == 1) {
    std::lock_guard<priority_mutex> sync(notifierInterruptMutex);
    // if this was the last notifier, clean up alarm and manager
    if (notifierAlarm) {
      notifierAlarm->writeEnable(false, status);
      delete notifierAlarm;
      notifierAlarm = nullptr;
    }
    if (notifierManager) {
      notifierManager->disable(status);
      delete notifierManager;
      notifierManager = nullptr;
    }
    closestTrigger = UINT64_MAX;
  }
}

void* getNotifierParam(void* notifier_pointer, int32_t* status) {
  return ((Notifier*)notifier_pointer)->param;
}

void updateNotifierAlarm(void* notifier_pointer, uint64_t triggerTime,
                         int32_t* status) {
  std::lock_guard<priority_recursive_mutex> sync(notifierMutex);

  Notifier* notifier = (Notifier*)notifier_pointer;
  notifier->triggerTime = triggerTime;
  bool wasActive = (closestTrigger != UINT64_MAX);

  if (!notifierInterruptMutex.try_lock() || notifierRefCount == 0 ||
      !notifierAlarm)
    return;

  // Update alarm time if closer than current.
  if (triggerTime < closestTrigger) {
    closestTrigger = triggerTime;
    // Simply truncate the hardware trigger time to 32-bit.
    notifierAlarm->writeTriggerTime((uint32_t)triggerTime, status);
  }
  // Enable the alarm.  The hardware disables itself after each alarm.
  if (!wasActive) notifierAlarm->writeEnable(true, status);

  notifierInterruptMutex.unlock();
}

void stopNotifierAlarm(void* notifier_pointer, int32_t* status) {
  std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
  Notifier* notifier = (Notifier*)notifier_pointer;
  notifier->triggerTime = UINT64_MAX;
}

}  // extern "C"
<commit_msg>HAL Notifier: Use freelist to avoid use-after-free race. (#50)<commit_after>/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2016. All Rights Reserved.                             */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*/

#include "HAL/Notifier.h"
#include <atomic>
#include <cstdlib>
#include <mutex>
#include "ChipObject.h"
#include "HAL/HAL.h"
#include "HAL/cpp/priority_mutex.h"

static const uint32_t kTimerInterruptNumber = 28;

static priority_mutex notifierInterruptMutex;
static priority_recursive_mutex notifierMutex;
static tAlarm* notifierAlarm = nullptr;
static tInterruptManager* notifierManager = nullptr;
static uint64_t closestTrigger = UINT64_MAX;
struct Notifier {
  Notifier *prev, *next, *freeNext;
  bool freed;
  void* param;
  void (*process)(uint64_t, void*);
  uint64_t triggerTime = UINT64_MAX;
};
static Notifier* notifiers = nullptr;
static Notifier* notifiersFreeList = nullptr;
static std::atomic_flag notifierAtexitRegistered = ATOMIC_FLAG_INIT;
static std::atomic_int notifierRefCount{0};

static void alarmCallback(uint32_t, void*) {
  std::unique_lock<priority_recursive_mutex> sync(notifierMutex);

  int32_t status = 0;
  uint64_t currentTime = 0;

  // the hardware disables itself after each alarm
  closestTrigger = UINT64_MAX;

  // process all notifiers
  Notifier* notifier = notifiers;
  while (notifier) {
    if (!notifier->freed && notifier->triggerTime != UINT64_MAX) {
      if (currentTime == 0) currentTime = getFPGATime(&status);
      if (notifier->triggerTime < currentTime) {
        notifier->triggerTime = UINT64_MAX;
        auto process = notifier->process;
        auto param = notifier->param;
        sync.unlock();
        process(currentTime, param);
        sync.lock();
      } else if (notifier->triggerTime < closestTrigger) {
        updateNotifierAlarm(notifier, notifier->triggerTime, &status);
      }
    }
    notifier = notifier->next;
  }

  // clean up freelist
  notifier = notifiersFreeList;
  while (notifier) {
    Notifier* next = notifier->freeNext;
    delete notifier;
    notifier = next;
  }
  notifiersFreeList = nullptr;
}

static void cleanupNotifierAtExit() {
  notifierAlarm = nullptr;
  notifierManager = nullptr;
}

extern "C" {

void* initializeNotifier(void (*process)(uint64_t, void*), void* param,
                         int32_t* status) {
  if (!process) {
    *status = NULL_PARAMETER;
    return nullptr;
  }
  if (!notifierAtexitRegistered.test_and_set())
    std::atexit(cleanupNotifierAtExit);
  if (notifierRefCount.fetch_add(1) == 0) {
    std::lock_guard<priority_mutex> sync(notifierInterruptMutex);
    // create manager and alarm if not already created
    if (!notifierManager) {
      notifierManager =
          new tInterruptManager(1 << kTimerInterruptNumber, false, status);
      notifierManager->registerHandler(alarmCallback, NULL, status);
      notifierManager->enable(status);
    }
    if (!notifierAlarm) notifierAlarm = tAlarm::create(status);
  }

  std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
  // create notifier structure and add to list
  Notifier* notifier = new Notifier();
  notifier->prev = nullptr;
  notifier->next = notifiers;
  notifier->freeNext = nullptr;
  if (notifier->next) notifier->next->prev = notifier;
  notifier->freed = false;
  notifier->param = param;
  notifier->process = process;
  notifiers = notifier;
  return notifier;
}

void cleanNotifier(void* notifier_pointer, int32_t* status) {
  {
    std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
    Notifier* notifier = (Notifier*)notifier_pointer;

    // ignore double-free
    if (notifier->freed) return;
    notifier->freed = true;

    // remove from list
    if (notifier->prev) notifier->prev->next = notifier->next;
    if (notifier->next) notifier->next->prev = notifier->prev;
    if (notifiers == notifier) notifiers = notifier->next;

    // add to freelist
    notifier->freeNext = notifiersFreeList;
    notifiersFreeList = notifier;
  }

  if (notifierRefCount.fetch_sub(1) == 1) {
    std::lock_guard<priority_mutex> sync(notifierInterruptMutex);
    // if this was the last notifier, clean up alarm and manager
    if (notifierAlarm) {
      notifierAlarm->writeEnable(false, status);
      delete notifierAlarm;
      notifierAlarm = nullptr;
    }
    if (notifierManager) {
      notifierManager->disable(status);
      delete notifierManager;
      notifierManager = nullptr;
    }
    closestTrigger = UINT64_MAX;
  }
}

void* getNotifierParam(void* notifier_pointer, int32_t* status) {
  return ((Notifier*)notifier_pointer)->param;
}

void updateNotifierAlarm(void* notifier_pointer, uint64_t triggerTime,
                         int32_t* status) {
  std::lock_guard<priority_recursive_mutex> sync(notifierMutex);

  Notifier* notifier = (Notifier*)notifier_pointer;
  if (notifier->freed) return;
  notifier->triggerTime = triggerTime;
  bool wasActive = (closestTrigger != UINT64_MAX);

  if (!notifierInterruptMutex.try_lock() || notifierRefCount == 0 ||
      !notifierAlarm)
    return;

  // Update alarm time if closer than current.
  if (triggerTime < closestTrigger) {
    closestTrigger = triggerTime;
    // Simply truncate the hardware trigger time to 32-bit.
    notifierAlarm->writeTriggerTime((uint32_t)triggerTime, status);
  }
  // Enable the alarm.  The hardware disables itself after each alarm.
  if (!wasActive) notifierAlarm->writeEnable(true, status);

  notifierInterruptMutex.unlock();
}

void stopNotifierAlarm(void* notifier_pointer, int32_t* status) {
  std::lock_guard<priority_recursive_mutex> sync(notifierMutex);
  Notifier* notifier = (Notifier*)notifier_pointer;
  notifier->triggerTime = UINT64_MAX;
}

}  // extern "C"
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <map>

#ifdef _WIN32
	#include <windows.h>
#else
	#include <stdint.h>
	#include <unistd.h>
	#include <cstdarg>
	#include <cstddef>
#endif

#include "module.h"
#include "robot_module.h"

#include "test_robot_module.h"

/* GLOBALS CONFIG */
const unsigned int COUNT_ROBOTS = 99;
const unsigned int COUNT_FUNCTIONS = 5;
const unsigned int COUNT_AXIS = 3;

#define DEFINE_ALL_AXIS \
	ADD_ROBOT_AXIS("X", 100, -100)\
	ADD_ROBOT_AXIS("Y", 1, 0)\
	ADD_ROBOT_AXIS("Z", 100, 0)

TestRobotModule::TestRobotModule() {
	{
		robot_functions = new FunctionData*[COUNT_FUNCTIONS];
		system_value function_id = 0;
		FunctionData::ParamTypes *pt;

		robot_functions[function_id] = new FunctionData(function_id + 1, 0, NULL, "none");
		function_id++;

		pt = new FunctionData::ParamTypes[1];
		pt[0] = FunctionData::ParamTypes::FLOAT;
		robot_functions[function_id] = new FunctionData(function_id + 1, 1, pt, "do_something");
		function_id++;

		pt = new FunctionData::ParamTypes[1];
		pt[0] = FunctionData::ParamTypes::FLOAT;
		robot_functions[function_id] = new FunctionData(function_id + 1, 1, pt, "get_some_value");
		function_id++;

		robot_functions[function_id] = new FunctionData(function_id + 1, 0, NULL, "throw_exception");
		function_id++;

		pt = new FunctionData::ParamTypes[2];
		pt[0] = FunctionData::ParamTypes::STRING;
		pt[1] = FunctionData::ParamTypes::FLOAT;
		robot_functions[function_id] = new FunctionData(function_id + 1, 2, pt, "print");
		function_id++;
	}
	{
		robot_axis = new AxisData*[COUNT_AXIS];
		system_value axis_id = 0;
		DEFINE_ALL_AXIS
	}
}

const char *TestRobotModule::getUID() {
	return "Test_robot_module_v107";
}

void TestRobotModule::prepare(colorPrintf_t *colorPrintf_p, colorPrintfVA_t *colorPrintfVA_p) {
	this->colorPrintf_p = colorPrintfVA_p;
}

FunctionData** TestRobotModule::getFunctions(unsigned int *count_functions) {
	(*count_functions) = COUNT_FUNCTIONS;
	return robot_functions;
}

AxisData** TestRobotModule::getAxis(unsigned int *count_axis) {
	(*count_axis) = COUNT_AXIS;
	return robot_axis;
}

void *TestRobotModule::writePC(unsigned int *buffer_length) {
	(*buffer_length) = 0;
	return NULL;
}

int TestRobotModule::init() {
	for (unsigned int i = 0; i < COUNT_ROBOTS; ++i) {
		TestRobot *test_robot = new TestRobot(this);
		aviable_connections[i] = test_robot;
	}
	return 0;
}

Robot* TestRobotModule::robotRequire() {
	//colorPrintf(ConsoleColor(), "new robot require\n");

	for (m_connections::iterator i = aviable_connections.begin(); i != aviable_connections.end(); ++i) {
		if (i->second->isAviable) {
			//colorPrintf(ConsoleColor(ConsoleColor::green), "finded free robot\n");

			TestRobot *tr = i->second;
			tr->isAviable = false;

			return tr;
		}
	}
	return NULL;
}

void TestRobotModule::robotFree(Robot *robot) {
	TestRobot *test_robot = reinterpret_cast<TestRobot*>(robot);

	for (m_connections::iterator i = aviable_connections.begin(); i != aviable_connections.end(); ++i) {
		if (i->second == test_robot) {
			//colorPrintf(ConsoleColor(), "free robot\n");
			test_robot->isAviable = true;
			return;
		}
	}
}

void TestRobotModule::final() {
	for (m_connections::iterator i = aviable_connections.begin(); i != aviable_connections.end(); ++i) {
		delete i->second;
	}
	aviable_connections.clear();
}

int TestRobotModule::startProgram(int uniq_index) {
	return 0;
}

int TestRobotModule::endProgram(int uniq_index) {
	return 0;
}

void TestRobotModule::destroy() {
	for (unsigned int j = 0; j < COUNT_FUNCTIONS; ++j) {
		if (robot_functions[j]->count_params) {
			delete[] robot_functions[j]->params;
		}
		delete robot_functions[j];
	}
	for (unsigned int j = 0; j < COUNT_AXIS; ++j) {
		delete robot_axis[j];
	}
	delete[] robot_functions;
	delete[] robot_axis;
	delete this;
}

void TestRobotModule::colorPrintf(ConsoleColor colors, const char *mask, ...) {
	va_list args;
	va_start(args, mask);
	(*colorPrintf_p)(this, colors, mask, args);
	va_end(args);
}

FunctionResult* TestRobot::executeFunction(system_value command_index, void **args) {
	FunctionResult *fr = NULL;

	switch (command_index) {
		case 1: { // none
			break;
		}
		case 2: { // do_something
			variable_value *vv = (variable_value*) args[0];
#ifdef _WIN32
			Sleep((DWORD) *vv);
#else
			usleep(((uint32_t) *vv)*1000);
#endif
			break;
		}
		case 3: { // get_some_value
			variable_value *vv = (variable_value*) args[0];
			fr = new FunctionResult(1,  *vv);
			break;
		}
		case 4: { // throw_exception
			fr = new FunctionResult(0);
			break;
		}
		case 5: { // print
			variable_value *vv = (variable_value*)args[1];
#ifdef _WIN32
			Sleep((DWORD)*vv);
#else
			usleep(((uint32_t)*vv) * 1000);
#endif
			puts((const char *) args[0]);
			break;
		}
		default: break;
	}

	return fr;
}

void TestRobot::axisControl(system_value axis_index, variable_value value) {
	const char *name;
	switch (axis_index) {
		case 1: { name = "X"; break; }
		case 2: { name = "Y"; break; }
		case 3: { name = "Z"; break; }
		default: { name = "O_o"; break; };
	}
	parent->colorPrintf(ConsoleColor(ConsoleColor::green), "change axis value: %s = %d\n", name, (int) value);
}

PREFIX_FUNC_DLL RobotModule* getRobotModuleObject() {
	return new TestRobotModule();
}<commit_msg>Fixed bug with rand of axis values.<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <map>

#ifdef _WIN32
	#include <windows.h>
#else
	#include <stdint.h>
	#include <unistd.h>
	#include <cstdarg>
	#include <cstddef>
#endif

#include "module.h"
#include "robot_module.h"

#include "test_robot_module.h"

/* GLOBALS CONFIG */
const unsigned int COUNT_ROBOTS = 99;
const unsigned int COUNT_FUNCTIONS = 5;
const unsigned int COUNT_AXIS = 3;

#define DEFINE_ALL_AXIS \
	ADD_ROBOT_AXIS("X", 100, -100)\
	ADD_ROBOT_AXIS("Y", 1, 0)\
	ADD_ROBOT_AXIS("Z", 100, 0)

TestRobotModule::TestRobotModule() {
	{
		robot_functions = new FunctionData*[COUNT_FUNCTIONS];
		system_value function_id = 0;
		FunctionData::ParamTypes *pt;

		robot_functions[function_id] = new FunctionData(function_id + 1, 0, NULL, "none");
		function_id++;

		pt = new FunctionData::ParamTypes[1];
		pt[0] = FunctionData::ParamTypes::FLOAT;
		robot_functions[function_id] = new FunctionData(function_id + 1, 1, pt, "do_something");
		function_id++;

		pt = new FunctionData::ParamTypes[1];
		pt[0] = FunctionData::ParamTypes::FLOAT;
		robot_functions[function_id] = new FunctionData(function_id + 1, 1, pt, "get_some_value");
		function_id++;

		robot_functions[function_id] = new FunctionData(function_id + 1, 0, NULL, "throw_exception");
		function_id++;

		pt = new FunctionData::ParamTypes[2];
		pt[0] = FunctionData::ParamTypes::STRING;
		pt[1] = FunctionData::ParamTypes::FLOAT;
		robot_functions[function_id] = new FunctionData(function_id + 1, 2, pt, "print");
		function_id++;
	}
	{
		robot_axis = new AxisData*[COUNT_AXIS];
		system_value axis_id = 0;
		DEFINE_ALL_AXIS
	}
}

const char *TestRobotModule::getUID() {
	return "Test_robot_module_v107";
}

void TestRobotModule::prepare(colorPrintf_t *colorPrintf_p, colorPrintfVA_t *colorPrintfVA_p) {
	this->colorPrintf_p = colorPrintfVA_p;
}

FunctionData** TestRobotModule::getFunctions(unsigned int *count_functions) {
	(*count_functions) = COUNT_FUNCTIONS;
	return robot_functions;
}

AxisData** TestRobotModule::getAxis(unsigned int *count_axis) {
	(*count_axis) = COUNT_AXIS;
	return robot_axis;
}

void *TestRobotModule::writePC(unsigned int *buffer_length) {
	(*buffer_length) = 0;
	return NULL;
}

int TestRobotModule::init() {
	for (unsigned int i = 0; i < COUNT_ROBOTS; ++i) {
		TestRobot *test_robot = new TestRobot(this);
		aviable_connections[i] = test_robot;
	}
	return 0;
}

Robot* TestRobotModule::robotRequire() {
	//colorPrintf(ConsoleColor(), "new robot require\n");

	for (m_connections::iterator i = aviable_connections.begin(); i != aviable_connections.end(); ++i) {
		if (i->second->isAviable) {
			//colorPrintf(ConsoleColor(ConsoleColor::green), "finded free robot\n");

			TestRobot *tr = i->second;
			tr->isAviable = false;

			return tr;
		}
	}
	return NULL;
}

void TestRobotModule::robotFree(Robot *robot) {
	TestRobot *test_robot = reinterpret_cast<TestRobot*>(robot);

	for (m_connections::iterator i = aviable_connections.begin(); i != aviable_connections.end(); ++i) {
		if (i->second == test_robot) {
			//colorPrintf(ConsoleColor(), "free robot\n");
			test_robot->isAviable = true;
			return;
		}
	}
}

void TestRobotModule::final() {
	for (m_connections::iterator i = aviable_connections.begin(); i != aviable_connections.end(); ++i) {
		delete i->second;
	}
	aviable_connections.clear();
}

int TestRobotModule::startProgram(int uniq_index) {
	return 0;
}

int TestRobotModule::endProgram(int uniq_index) {
	return 0;
}

void TestRobotModule::destroy() {
	for (unsigned int j = 0; j < COUNT_FUNCTIONS; ++j) {
		if (robot_functions[j]->count_params) {
			delete[] robot_functions[j]->params;
		}
		delete robot_functions[j];
	}
	for (unsigned int j = 0; j < COUNT_AXIS; ++j) {
		delete robot_axis[j];
	}
	delete[] robot_functions;
	delete[] robot_axis;
	delete this;
}

void TestRobotModule::colorPrintf(ConsoleColor colors, const char *mask, ...) {
	va_list args;
	va_start(args, mask);
	(*colorPrintf_p)(this, colors, mask, args);
	va_end(args);
}

FunctionResult* TestRobot::executeFunction(system_value command_index, void **args) {
	FunctionResult *fr = NULL;

	switch (command_index) {
		case 1: { // none
			break;
		}
		case 2: { // do_something
			variable_value *vv = (variable_value*) args[0];
#ifdef _WIN32
			Sleep((DWORD) *vv);
#else
			usleep(((uint32_t) *vv)*1000);
#endif
			break;
		}
		case 3: { // get_some_value
			variable_value *vv = (variable_value*) args[0];
			fr = new FunctionResult(1,  *vv);
			break;
		}
		case 4: { // throw_exception
			fr = new FunctionResult(0);
			break;
		}
		case 5: { // print
			variable_value *vv = (variable_value*)args[1];
#ifdef _WIN32
			Sleep((DWORD)*vv);
#else
			usleep(((uint32_t)*vv) * 1000);
#endif
			puts((const char *) args[0]);
			break;
		}
		default: break;
	}

	return fr;
}

void TestRobot::axisControl(system_value axis_index, variable_value value) {
	const char *name;
	switch (axis_index) {
		case 1: { name = "X"; break; }
		case 2: { name = "Y"; break; }
		case 3: { name = "Z"; break; }
		default: { name = "O_o"; break; };
	}
	parent->colorPrintf(ConsoleColor(ConsoleColor::green), "change axis value: %s = %f\n", name, value);
}

PREFIX_FUNC_DLL RobotModule* getRobotModuleObject() {
	return new TestRobotModule();
}<|endoftext|>


<commit_before>/**
 * @file   RandomTest.cpp
 * @brief  Random class tester.
 * @author zer0
 * @date   2016-04-07
 */

#include <gtest/gtest.h>
#include <libtbag/Random.hpp>

using namespace libtbag;

TEST(RandomTest, gen)
{
    int min = 0;
    int max = 10;
    int current = 0;
    int test_count = 200;

    for (int i = 0; i < test_count; ++i) {
        current = Random::gen(min, max);
        ASSERT_GE(current, min);
        ASSERT_LE(current, max);
    }
}

#include <libtbag/Log.hpp>

TEST(RandomTest, gen2)
{
    Log::getInstance()->trace("Trace");
}

<commit_msg>Remove unused test code.<commit_after>/**
 * @file   RandomTest.cpp
 * @brief  Random class tester.
 * @author zer0
 * @date   2016-04-07
 */

#include <gtest/gtest.h>
#include <libtbag/Random.hpp>

using namespace libtbag;

TEST(RandomTest, gen)
{
    int min = 0;
    int max = 10;
    int current = 0;
    int test_count = 200;

    for (int i = 0; i < test_count; ++i) {
        current = Random::gen(min, max);
        ASSERT_GE(current, min);
        ASSERT_LE(current, max);
    }
}

<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2007      Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

#include <KApplication>
#include <KLocale>
#include <KAboutData>
#include <KCmdLineArgs>

#include <QtCore/QFile>

#include "KdeMainWindow.h"

#include "MarbleTest.h"

#if STATIC_BUILD
 #include <QtCore/QtPlugin>
 Q_IMPORT_PLUGIN(qjpeg)
 Q_IMPORT_PLUGIN(qsvg)
#endif

int main (int argc, char *argv[])
{
    KAboutData aboutData( "marble", 0,
        ki18n("Marble Desktop Globe"), "0.3.8", ki18n("A World Atlas."),
        KAboutData::License_LGPL, ki18n("(c) 2007") );
    aboutData.addAuthor(ki18n("Torsten Rahn"), ki18n("Original author and maintainer"), "rahn@kde.org");
    aboutData.addAuthor(ki18n("Inge Wallin"), ki18n("co-maintainer"), "inge@lysator.liu.se");
    aboutData.setHomepage("http://edu.kde.org/marble");

    KCmdLineArgs::init( argc, argv, &aboutData );

    KCmdLineOptions  options;
    options.add( "timedemo", ki18n( "Make a time measurement to check performance" ) );
    KCmdLineArgs::addCmdLineOptions( options );
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

    KApplication app;

    MainWindow *window = new MainWindow();
    MarbleTest *marbleTest = new MarbleTest( window->marbleWidget() );

    window->resize(680, 640);
    window->show();

    if ( args->isSet( "timedemo" ) ) {
        window->resize(900, 640);
        marbleTest->timeDemo();
        return 0;
    }

    if ( args->isSet( "gpsDemo" ) ) {
        window->resize( 900, 640 );
        marbleTest->gpsDemo();
        return 0;
    }

    if ( args->isSet( "enableCurrentLocation" ) ) {
        window->marbleControl()->setCurrentLocationTabShown(true);
    }

    // Read the files that are given on the command line.
    // FIXME: What should the '1' below really be?
    // Command line arguments, i.e. files to open
    for (int i = 0; i < args->count(); i++) {

        // FIXME: Use openUrl( args->url(i)) instead?
        if ( QFile::exists( args->arg( i ) ) )
            ( window->marbleControl() )->addPlaceMarkFile( args->arg( i ) );
    }

    delete marbleTest;

    return app.exec();
}
<commit_msg>fixed the gpsdemo test <commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2007      Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

#include <KApplication>
#include <KLocale>
#include <KAboutData>
#include <KCmdLineArgs>

#include <QtCore/QFile>

#include "KdeMainWindow.h"

#include "MarbleTest.h"

#if STATIC_BUILD
 #include <QtCore/QtPlugin>
 Q_IMPORT_PLUGIN(qjpeg)
 Q_IMPORT_PLUGIN(qsvg)
#endif

int main (int argc, char *argv[])
{
    KAboutData aboutData( "marble", 0,
        ki18n("Marble Desktop Globe"), "0.3.8", ki18n("A World Atlas."),
        KAboutData::License_LGPL, ki18n("(c) 2007") );
    aboutData.addAuthor(ki18n("Torsten Rahn"), ki18n("Original author and maintainer"), "rahn@kde.org");
    aboutData.addAuthor(ki18n("Inge Wallin"), ki18n("co-maintainer"), "inge@lysator.liu.se");
    aboutData.setHomepage("http://edu.kde.org/marble");

    KCmdLineArgs::init( argc, argv, &aboutData );

    KCmdLineOptions  options;
    options.add( "timedemo", ki18n( "Make a time measurement to check performance" ) );
    options.add( "gpsdemo", ki18n( "Check speed of gps drawing" ) );
    KCmdLineArgs::addCmdLineOptions( options );
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

    KApplication app;

    MainWindow *window = new MainWindow();
    MarbleTest *marbleTest = new MarbleTest( window->marbleWidget() );

    window->resize(680, 640);
    window->show();

    if ( args->isSet( "timedemo" ) ) {
        window->resize(900, 640);
        marbleTest->timeDemo();
        return 0;
    }

    if ( args->isSet( "gpsdemo" ) ) {
        window->resize( 900, 640 );
        marbleTest->gpsDemo();
        return 0;
    }

    if ( args->isSet( "enableCurrentLocation" ) ) {
        window->marbleControl()->setCurrentLocationTabShown(true);
    }

    // Read the files that are given on the command line.
    // FIXME: What should the '1' below really be?
    // Command line arguments, i.e. files to open
    for (int i = 0; i < args->count(); i++) {

        // FIXME: Use openUrl( args->url(i)) instead?
        if ( QFile::exists( args->arg( i ) ) )
            ( window->marbleControl() )->addPlaceMarkFile( args->arg( i ) );
    }

    delete marbleTest;

    return app.exec();
}
<|endoftext|>


<commit_before>#ifndef _SDD_HOM_SUM_HH_
#define _SDD_HOM_SUM_HH_

#include <algorithm>  // all_of, copy, equal
#include <initializer_list>
#include <iosfwd>
#include <unordered_map>
#include <vector>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"
#include "sdd/hom/local.hh"

namespace sdd { namespace hom {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Sum homomorphism.
template <typename C>
class sum
{
public:

  /// @brief The type of the homomorphism operands' set.
  typedef boost::container::flat_set<homomorphism<C>> operands_type;

private:

  /// @brief The homomorphism operands' set.
  const operands_type operands_;

public:

  /// @brief Constructor.
  sum(operands_type&& operands)
    : operands_(std::move(operands))
  {
  }

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const SDD<C>& x)
  const
  {
    sum_builder<C, SDD<C>> sum_operands(operands_.size());
    for (const auto& op : operands_)
    {
      sum_operands.add(op(cxt, x));
    }
    try
    {
      return sdd::sum(cxt.sdd_context(), std::move(sum_operands));
    }
    catch (top<C>& t)
    {
      evaluation_error<C> e(x);
      e.add_top(t);
      throw e;
    }
  }

  /// @brief Skip variable predicate.
  bool
  skip(const typename C::Variable& v)
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&](const homomorphism<C>& h){return h.skip(v);});
  }

  /// @brief Selector predicate
  bool
  selector()
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&](const homomorphism<C>& h){return h.selector();});
  }

  const operands_type&
  operands()
  const noexcept
  {
    return operands_;
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Equality of two sum.
/// @related sum
template <typename C>
inline
bool
operator==(const sum<C>& lhs, const sum<C>& rhs)
noexcept
{
  return lhs.operands().size() == rhs.operands().size()
     and std::equal(lhs.operands().begin(), lhs.operands().end(), rhs.operands().begin());
}

/// @related sum
template <typename C>
std::ostream&
operator<<(std::ostream& os, const sum<C>& s)
{
  os << "(";
  std::copy( s.operands().begin(), std::prev(s.operands().end())
           , std::ostream_iterator<homomorphism<C>>(os, " + "));
  return os << *std::prev(s.operands().end()) << ")";
}

/*-------------------------------------------------------------------------------------------*/

/// @brief Help optimize an union's operands.
template <typename C>
struct sum_builder_helper
{
  typedef void result_type;
  typedef typename sum<C>::operands_type operands_type;
  typedef std::vector<homomorphism<C>> hom_list_type;
  typedef std::unordered_map<typename C::Variable, hom_list_type> locals_type;

  /// @brief Flatten nested sums.
  void
  operator()( const sum<C>& s
            , const homomorphism<C>& h, operands_type& operands, locals_type& locals)
  const
  {
    for (const auto& op : s.operands())
    {
      apply_visitor(*this, op->data(), op, operands, locals);
    }
  }

  /// @brief Regroup locals.
  void
  operator()( const local<C>& l
            , const homomorphism<C>& h, operands_type& operands, locals_type& locals)
  const
  {
    auto insertion = locals.emplace(l.variable(), hom_list_type());
    insertion.first->second.emplace_back(l.hom());
  }

  /// @brief Insert normally all other operands.
  template <typename T>
  void
  operator()(const T&, const homomorphism<C>& h, operands_type& operands, locals_type&)
  const
  {
    operands.insert(h);
  }

};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C, typename InputIterator>
homomorphism<C>
Sum(InputIterator begin, InputIterator end)
{
  const std::size_t size = std::distance(begin, end);

  if (size == 0)
  {
    return Id<C>();
  }

  typename sum<C>::operands_type operands;
  operands.reserve(size);

  sum_builder_helper<C> sbv;
  typename sum_builder_helper<C>::locals_type locals;
  for (; begin != end; ++begin)
  {
    apply_visitor(sbv, (*begin)->data(), *begin, operands, locals);
  }

  // insert remaining locals
  for (const auto& l : locals)
  {
    operands.insert(Local<C>(l.first, Sum<C>(l.second.begin(), l.second.end())));
  }

  if (operands.size() == 1)
  {
    return *operands.begin();
  }
  else
  {
    operands.shrink_to_fit();
    return homomorphism<C>::create(internal::mem::construct<sum<C>>(), std::move(operands));
  }
}

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Sum(std::initializer_list<homomorphism<C>> operands)
{
  return Sum<C>(operands.begin(), operands.end());
}

/*-------------------------------------------------------------------------------------------*/

}} // namespace sdd::hom

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Hash specialization for sdd::hom::sum.
template <typename C>
struct hash<sdd::hom::sum<C>>
{
  std::size_t
  operator()(const sdd::hom::sum<C>& s)
  const noexcept
  {
    std::size_t seed = 0;
    for (const auto& op : s.operands())
    {
      sdd::internal::util::hash_combine(seed, op);
    }
    return seed;
  }
};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_SUM_HH_
<commit_msg>Use boost::container::flat_set::operator==.<commit_after>#ifndef _SDD_HOM_SUM_HH_
#define _SDD_HOM_SUM_HH_

#include <algorithm>  // all_of, copy
#include <initializer_list>
#include <iosfwd>
#include <unordered_map>
#include <vector>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"
#include "sdd/hom/local.hh"

namespace sdd { namespace hom {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Sum homomorphism.
template <typename C>
class sum
{
public:

  /// @brief The type of the homomorphism operands' set.
  typedef boost::container::flat_set<homomorphism<C>> operands_type;

private:

  /// @brief The homomorphism operands' set.
  const operands_type operands_;

public:

  /// @brief Constructor.
  sum(operands_type&& operands)
    : operands_(std::move(operands))
  {
  }

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const SDD<C>& x)
  const
  {
    sum_builder<C, SDD<C>> sum_operands(operands_.size());
    for (const auto& op : operands_)
    {
      sum_operands.add(op(cxt, x));
    }
    try
    {
      return sdd::sum(cxt.sdd_context(), std::move(sum_operands));
    }
    catch (top<C>& t)
    {
      evaluation_error<C> e(x);
      e.add_top(t);
      throw e;
    }
  }

  /// @brief Skip variable predicate.
  bool
  skip(const typename C::Variable& v)
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&](const homomorphism<C>& h){return h.skip(v);});
  }

  /// @brief Selector predicate
  bool
  selector()
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&](const homomorphism<C>& h){return h.selector();});
  }

  const operands_type&
  operands()
  const noexcept
  {
    return operands_;
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Equality of two sum.
/// @related sum
template <typename C>
inline
bool
operator==(const sum<C>& lhs, const sum<C>& rhs)
noexcept
{
  return lhs.operands() == rhs.operands();
}

/// @related sum
template <typename C>
std::ostream&
operator<<(std::ostream& os, const sum<C>& s)
{
  os << "(";
  std::copy( s.operands().begin(), std::prev(s.operands().end())
           , std::ostream_iterator<homomorphism<C>>(os, " + "));
  return os << *std::prev(s.operands().end()) << ")";
}

/*-------------------------------------------------------------------------------------------*/

/// @brief Help optimize an union's operands.
template <typename C>
struct sum_builder_helper
{
  typedef void result_type;
  typedef typename sum<C>::operands_type operands_type;
  typedef std::vector<homomorphism<C>> hom_list_type;
  typedef std::unordered_map<typename C::Variable, hom_list_type> locals_type;

  /// @brief Flatten nested sums.
  void
  operator()( const sum<C>& s
            , const homomorphism<C>& h, operands_type& operands, locals_type& locals)
  const
  {
    for (const auto& op : s.operands())
    {
      apply_visitor(*this, op->data(), op, operands, locals);
    }
  }

  /// @brief Regroup locals.
  void
  operator()( const local<C>& l
            , const homomorphism<C>& h, operands_type& operands, locals_type& locals)
  const
  {
    auto insertion = locals.emplace(l.variable(), hom_list_type());
    insertion.first->second.emplace_back(l.hom());
  }

  /// @brief Insert normally all other operands.
  template <typename T>
  void
  operator()(const T&, const homomorphism<C>& h, operands_type& operands, locals_type&)
  const
  {
    operands.insert(h);
  }

};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C, typename InputIterator>
homomorphism<C>
Sum(InputIterator begin, InputIterator end)
{
  const std::size_t size = std::distance(begin, end);

  if (size == 0)
  {
    return Id<C>();
  }

  typename sum<C>::operands_type operands;
  operands.reserve(size);

  sum_builder_helper<C> sbv;
  typename sum_builder_helper<C>::locals_type locals;
  for (; begin != end; ++begin)
  {
    apply_visitor(sbv, (*begin)->data(), *begin, operands, locals);
  }

  // insert remaining locals
  for (const auto& l : locals)
  {
    operands.insert(Local<C>(l.first, Sum<C>(l.second.begin(), l.second.end())));
  }

  if (operands.size() == 1)
  {
    return *operands.begin();
  }
  else
  {
    operands.shrink_to_fit();
    return homomorphism<C>::create(internal::mem::construct<sum<C>>(), std::move(operands));
  }
}

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Sum(std::initializer_list<homomorphism<C>> operands)
{
  return Sum<C>(operands.begin(), operands.end());
}

/*-------------------------------------------------------------------------------------------*/

}} // namespace sdd::hom

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Hash specialization for sdd::hom::sum.
template <typename C>
struct hash<sdd::hom::sum<C>>
{
  std::size_t
  operator()(const sdd::hom::sum<C>& s)
  const noexcept
  {
    std::size_t seed = 0;
    for (const auto& op : s.operands())
    {
      sdd::internal::util::hash_combine(seed, op);
    }
    return seed;
  }
};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_SUM_HH_
<|endoftext|>


<commit_before>#include "chromosome.h"

namespace ceno {
using ufunc = unary_func<double>;
using bfunc = binary_func<double>;
using tfunc = ternary_func<double>;
using f_t  = typename tfunc::f_t;
using ntides_t = Nucleotides<double>;
using allele_t = Allele<double>;

ntides_t g;
template<> ntides_t* allele_t::ntides = &g;

}

using namespace ceno;

int main(int argc, char**) {
	//no output w/o argument
	if (argc < 2) {
		std::cout.setstate(std::ios::failbit);
	}
	g.term_names = {"x", "y", "z"};
	g.terms = { 2., 4.5, 7.6, .34 };
	g.funcs.push_back(std::unique_ptr<bfunc>(new bfunc([](double a, double b) {
		return a * b;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](double a, double b, double c) {
		return a + b + c;
	})));
	g.funcs.push_back(std::unique_ptr<bfunc>(new bfunc([](double a, double b) {
		return a - b;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](double a, double b, double c) {
	return a > b ? a > c ? a : c : b > c ? b : c;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](double a, double b, double c) {
	return a < b ? a < c ? a : c : b < c ? b : c;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](double a, double b, double c) {
	return a > b ? a < c ? a : b < c ? b : c : a > c ? c : a;
	})));
	g.funcs.push_back(std::unique_ptr<ufunc>(new ufunc([](double a) {
		return a * a;
	})));
	g.func_names.push_back("mult");
	g.func_names.push_back("add");
	g.func_names.push_back("sub");
	g.func_names.push_back("max");
	g.func_names.push_back("min");
	g.func_names.push_back("middle");
	g.func_names.push_back("square");
	Genome<double> cgrow, cfull;
	for (int i = 1; i < 5; i++) {
		cfull.clear();
		allele_t::build(back_inserter(cfull), CREATE_FULL, i);
		std::cout << "Depth: " << i << "\nFULL:\n\n";
		std::cout << sexp << cfull << std::endl << std::endl;
		std::cout << postfix << cfull << std::endl << std::endl;
		std::cout << "evals to " << allele_t::eval(cfull.begin()) << std::endl;
		cgrow.clear();
		allele_t::build(back_inserter(cgrow), CREATE_GROW, i);
		std::cout << "\nGROW:\n\n";
		std::cout << sexp << cgrow << std::endl << std::endl;
		std::cout << postfix << cgrow << std::endl << std::endl;
		std::cout << "evals to " << allele_t::eval(cgrow.begin()) << std::endl;
		Genome<double> jr, sis;
		breed(cfull, cgrow, std::back_inserter(jr), std::back_inserter(sis), .5);
		std::cout << sexp << "OFFSPRING: " << jr << std::endl << sis << std::endl;
	}
}
<commit_msg>some typedef clarity and consistency<commit_after>#include "chromosome.h"

namespace ceno {
using T = double;
using U = unsigned char;
using ufunc = unary_func<T>;
using bfunc = binary_func<T>;
using tfunc = ternary_func<T>;
//using f_t  = typename tfunc::f_t;
using ntides_t = Nucleotides<T>;
using allele_t = Allele<T, U>;
using chromosome_t = Chromosome<T, U>;
using genome_t = Genome<T, U>;
ntides_t g;
template<> ntides_t* allele_t::ntides = &g;

}

using namespace ceno;

int main(int argc, char**) {
	//no output w/o argument
	if (argc < 2) {
		std::cout.setstate(std::ios::failbit);
	}
	g.term_names = {"x", "y", "z"};
	g.terms = { 2., 4.5, 7.6, .34 };
	g.funcs.push_back(std::unique_ptr<bfunc>(new bfunc([](T a, T b) {
		return a * b;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](T a, T b, T c) {
		return a + b + c;
	})));
	g.funcs.push_back(std::unique_ptr<bfunc>(new bfunc([](T a, T b) {
		return a - b;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](T a, T b, T c) {
	return a > b ? a > c ? a : c : b > c ? b : c;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](T a, T b, T c) {
	return a < b ? a < c ? a : c : b < c ? b : c;
	})));
	g.funcs.push_back(std::unique_ptr<tfunc>(new tfunc([](T a, T b, T c) {
	return a > b ? a < c ? a : b < c ? b : c : a > c ? c : a;
	})));
	g.funcs.push_back(std::unique_ptr<ufunc>(new ufunc([](T a) {
		return a * a;
	})));
	g.func_names.push_back("mult");
	g.func_names.push_back("add");
	g.func_names.push_back("sub");
	g.func_names.push_back("max");
	g.func_names.push_back("min");
	g.func_names.push_back("middle");
	g.func_names.push_back("square");
	genome_t grow, full;
	for (int i = 1; i < 5; i++) {
		full.clear();
		allele_t::build(back_inserter(full), CREATE_FULL, i);
		std::cout << "Depth: " << i << "\nFULL:\n\n";
		std::cout << sexp << full << std::endl << std::endl;
		std::cout << postfix << full << std::endl << std::endl;
		std::cout << "evals to " << allele_t::eval(full.begin()) << std::endl;
		grow.clear();
		allele_t::build(back_inserter(grow), CREATE_GROW, i);
		std::cout << "\nGROW:\n\n";
		std::cout << sexp << grow << std::endl << std::endl;
		std::cout << postfix << grow << std::endl << std::endl;
		std::cout << "evals to " << allele_t::eval(grow.begin()) << std::endl;
		genome_t jr, sis;
		breed(full, grow, std::back_inserter(jr), std::back_inserter(sis), .5);
		std::cout << sexp << "OFFSPRING: " << jr << std::endl << sis << std::endl;
	}
}
<|endoftext|>


<commit_before>#include "config.h"

#include "selutility.hpp"

#include <charconv>
#include <chrono>
#include <filesystem>
#include <ipmid/api.hpp>
#include <ipmid/types.hpp>
#include <ipmid/utils.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <vector>
#include <xyz/openbmc_project/Common/error.hpp>

extern const ipmi::sensor::InvObjectIDMap invSensors;
using namespace phosphor::logging;
using InternalFailure =
    sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;

namespace
{

constexpr auto systemEventRecord = 0x02;

constexpr auto propAdditionalData = "AdditionalData";
constexpr auto strEventDir = "EVENT_DIR";
constexpr auto strGenerateId = "GENERATOR_ID";
constexpr auto strRecordType = "RECORD_TYPE";
constexpr auto strSensorData = "SENSOR_DATA";
constexpr auto strSensorPath = "SENSOR_PATH";

} // namespace

namespace ipmi
{

namespace sel
{

namespace internal
{

inline bool isRecordOEM(uint8_t recordType)
{
    return recordType != systemEventRecord;
}

using additionalDataMap = std::map<std::string, std::string>;
/** Parse the entry with format like key=val */
std::pair<std::string, std::string> parseEntry(const std::string& entry)
{
    constexpr auto equalSign = "=";
    auto pos = entry.find(equalSign);
    assert(pos != std::string::npos);
    auto key = entry.substr(0, pos);
    auto val = entry.substr(pos + 1);
    return {key, val};
}

additionalDataMap parseAdditionalData(const AdditionalData& data)
{
    std::map<std::string, std::string> ret;

    for (const auto& d : data)
    {
        ret.insert(parseEntry(d));
    }
    return ret;
}

uint8_t convert(const std::string_view& str, int base = 10)
{
    int ret;
    std::from_chars(str.data(), str.data() + str.size(), ret, base);
    return static_cast<uint8_t>(ret);
}

// Convert the string to a vector of uint8_t, where the str is formatted as hex
std::vector<uint8_t> convertVec(const std::string_view& str)
{
    std::vector<uint8_t> ret;
    auto len = str.size() / 2;
    ret.reserve(len);
    for (size_t i = 0; i < len; ++i)
    {
        ret.emplace_back(convert(str.substr(i * 2, 2), 16));
    }
    return ret;
}

/** Construct OEM SEL record according to IPMI spec 32.2, 32.3. */
void constructOEMSel(uint8_t recordType, std::chrono::milliseconds timestamp,
                     const additionalDataMap& m, GetSELEntryResponse& record)
{
    auto dataIter = m.find(strSensorData);
    assert(dataIter != m.end());
    auto sensorData = convertVec(dataIter->second);
    if (recordType >= 0xC0 && recordType < 0xE0)
    {
        record.event.oemCD.timeStamp = static_cast<uint32_t>(
            std::chrono::duration_cast<std::chrono::seconds>(timestamp)
                .count());
        record.event.oemCD.recordType = recordType;
        // The ManufactureID and OEM Defined are packed in the sensor data
        // Fill the 9 bytes of Manufacture ID and oemDefined
        memcpy(&record.event.oemCD.manufacturerID, sensorData.data(),
               std::min(sensorData.size(), static_cast<size_t>(9)));
    }
    else if (recordType >= 0xE0)
    {
        record.event.oemEF.recordType = recordType;
        // The remaining 13 bytes are the OEM Defined data
        memcpy(&record.event.oemEF.oemDefined, sensorData.data(),
               std::min(sensorData.size(), static_cast<size_t>(13)));
    }
}

GetSELEntryResponse
    prepareSELEntry(const std::string& objPath,
                    ipmi::sensor::InvObjectIDMap::const_iterator iter)
{
    GetSELEntryResponse record{};

    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
    auto service = ipmi::getService(bus, logEntryIntf, objPath);

    // Read all the log entry properties.
    auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
                                          propIntf, "GetAll");
    methodCall.append(logEntryIntf);

    auto reply = bus.call(methodCall);
    if (reply.is_method_error())
    {
        log<level::ERR>("Error in reading logging property entries");
        elog<InternalFailure>();
    }

    std::map<PropertyName, PropertyType> entryData;
    reply.read(entryData);

    // Read Id from the log entry.
    static constexpr auto propId = "Id";
    auto iterId = entryData.find(propId);
    if (iterId == entryData.end())
    {
        log<level::ERR>("Error in reading Id of logging entry");
        elog<InternalFailure>();
    }

    // Read Timestamp from the log entry.
    static constexpr auto propTimeStamp = "Timestamp";
    auto iterTimeStamp = entryData.find(propTimeStamp);
    if (iterTimeStamp == entryData.end())
    {
        log<level::ERR>("Error in reading Timestamp of logging entry");
        elog<InternalFailure>();
    }
    std::chrono::milliseconds chronoTimeStamp(
        std::get<uint64_t>(iterTimeStamp->second));

    if (iter == invSensors.end())
    {
        // It is expected to be a custom SEL entry
        record.event.oemCD.recordID =
            static_cast<uint16_t>(std::get<uint32_t>(iterId->second));
        iterId = entryData.find(propAdditionalData);
        if (iterId == entryData.end())
        {
            log<level::ERR>("Error finding AdditionalData");
            elog<InternalFailure>();
        }
        const auto& addData = std::get<AdditionalData>(iterId->second);
        auto m = parseAdditionalData(addData);
        auto recordType = convert(m[strRecordType]);
        auto isOEM = isRecordOEM(recordType);
        if (isOEM)
        {
            constructOEMSel(recordType, chronoTimeStamp, m, record);
        }
        else
        {
            // TODO
        }
    }
    else
    {

        record.event.eventRecord.recordID =
            static_cast<uint16_t>(std::get<uint32_t>(iterId->second));
        record.event.eventRecord.timeStamp = static_cast<uint32_t>(
            std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
                .count());

        static constexpr auto generatorID = 0x2000;
        static constexpr auto eventMsgRevision = 0x04;

        record.event.eventRecord.recordType = systemEventRecord;
        record.event.eventRecord.generatorID = generatorID;
        record.event.eventRecord.eventMsgRevision = eventMsgRevision;

        record.event.eventRecord.sensorType = iter->second.sensorType;
        record.event.eventRecord.sensorNum = iter->second.sensorID;
        record.event.eventRecord.eventData1 = iter->second.eventOffset;

        // Read Resolved from the log entry.
        static constexpr auto propResolved = "Resolved";
        auto iterResolved = entryData.find(propResolved);
        if (iterResolved == entryData.end())
        {
            log<level::ERR>("Error in reading Resolved field of logging entry");
            elog<InternalFailure>();
        }

        static constexpr auto deassertEvent = 0x80;

        // Evaluate if the event is assertion or deassertion event
        if (std::get<bool>(iterResolved->second))
        {
            record.event.eventRecord.eventType =
                deassertEvent | iter->second.eventReadingType;
        }
        else
        {
            record.event.eventRecord.eventType = iter->second.eventReadingType;
        }
    }

    return record;
}

} // namespace internal

GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
{
    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};

    static constexpr auto assocIntf =
        "xyz.openbmc_project.Association.Definitions";
    static constexpr auto assocProp = "Associations";

    auto service = ipmi::getService(bus, assocIntf, objPath);

    // Read the Associations interface.
    auto methodCall =
        bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
    methodCall.append(assocIntf);
    methodCall.append(assocProp);

    auto reply = bus.call(methodCall);
    if (reply.is_method_error())
    {
        log<level::ERR>("Error in reading Associations interface");
        elog<InternalFailure>();
    }

    using AssociationList =
        std::vector<std::tuple<std::string, std::string, std::string>>;

    std::variant<AssociationList> list;
    reply.read(list);

    auto& assocs = std::get<AssociationList>(list);

    /*
     * Check if the log entry has any callout associations, if there is a
     * callout association try to match the inventory path to the corresponding
     * IPMI sensor.
     */
    for (const auto& item : assocs)
    {
        if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
        {
            auto iter = invSensors.find(std::get<2>(item));
            if (iter == invSensors.end())
            {
                iter = invSensors.find(BOARD_SENSOR);
                if (iter == invSensors.end())
                {
                    log<level::ERR>("Motherboard sensor not found");
                    elog<InternalFailure>();
                }
            }

            return internal::prepareSELEntry(objPath, iter);
        }
    }

    // If there are no callout associations link the log entry to system event
    // sensor
    auto iter = invSensors.find(SYSTEM_SENSOR);
    return internal::prepareSELEntry(objPath, iter);
}

std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
{
    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};

    auto service = ipmi::getService(bus, logEntryIntf, objPath);

    using namespace std::string_literals;
    static const auto propTimeStamp = "Timestamp"s;

    auto methodCall =
        bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
    methodCall.append(logEntryIntf);
    methodCall.append(propTimeStamp);

    auto reply = bus.call(methodCall);
    if (reply.is_method_error())
    {
        log<level::ERR>("Error in reading Timestamp from Entry interface");
        elog<InternalFailure>();
    }

    std::variant<uint64_t> timeStamp;
    reply.read(timeStamp);

    std::chrono::milliseconds chronoTimeStamp(std::get<uint64_t>(timeStamp));

    return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
}

void readLoggingObjectPaths(ObjectPaths& paths)
{
    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
    auto depth = 0;
    paths.clear();

    auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
                                          mapperIntf, "GetSubTreePaths");
    mapperCall.append(logBasePath);
    mapperCall.append(depth);
    mapperCall.append(ObjectPaths({logEntryIntf}));

    auto reply = bus.call(mapperCall);
    if (reply.is_method_error())
    {
        log<level::INFO>("Error in reading logging entry object paths");
    }
    else
    {
        reply.read(paths);

        std::sort(paths.begin(), paths.end(),
                  [](const std::string& a, const std::string& b) {
                      namespace fs = std::filesystem;
                      fs::path pathA(a);
                      fs::path pathB(b);
                      auto idA = std::stoul(pathA.filename().string());
                      auto idB = std::stoul(pathB.filename().string());

                      return idA < idB;
                  });
    }
}

} // namespace sel

} // namespace ipmi
<commit_msg>sel: Support regular SEL record<commit_after>#include "config.h"

#include "selutility.hpp"

#include <charconv>
#include <chrono>
#include <filesystem>
#include <ipmid/api.hpp>
#include <ipmid/types.hpp>
#include <ipmid/utils.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <vector>
#include <xyz/openbmc_project/Common/error.hpp>

extern const ipmi::sensor::InvObjectIDMap invSensors;
using namespace phosphor::logging;
using InternalFailure =
    sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;

namespace
{

constexpr auto systemEventRecord = 0x02;
constexpr auto generatorID = 0x2000;
constexpr auto eventMsgRevision = 0x04;
constexpr auto assertEvent = 0x00;
constexpr auto deassertEvent = 0x80;
constexpr auto selDataSize = 3;
constexpr auto oemCDDataSize = 9;
constexpr auto oemEFDataSize = 13;

constexpr auto propAdditionalData = "AdditionalData";
constexpr auto propResolved = "Resolved";

constexpr auto strEventDir = "EVENT_DIR";
constexpr auto strGenerateId = "GENERATOR_ID";
constexpr auto strRecordType = "RECORD_TYPE";
constexpr auto strSensorData = "SENSOR_DATA";
constexpr auto strSensorPath = "SENSOR_PATH";

} // namespace

namespace ipmi
{

namespace sel
{

namespace internal
{

inline bool isRecordOEM(uint8_t recordType)
{
    return recordType != systemEventRecord;
}

using additionalDataMap = std::map<std::string, std::string>;
using entryDataMap = std::map<PropertyName, PropertyType>;
/** Parse the entry with format like key=val */
std::pair<std::string, std::string> parseEntry(const std::string& entry)
{
    constexpr auto equalSign = "=";
    auto pos = entry.find(equalSign);
    assert(pos != std::string::npos);
    auto key = entry.substr(0, pos);
    auto val = entry.substr(pos + 1);
    return {key, val};
}

additionalDataMap parseAdditionalData(const AdditionalData& data)
{
    std::map<std::string, std::string> ret;

    for (const auto& d : data)
    {
        ret.insert(parseEntry(d));
    }
    return ret;
}

int convert(const std::string_view& str, int base = 10)
{
    int ret;
    std::from_chars(str.data(), str.data() + str.size(), ret, base);
    return ret;
}

// Convert the string to a vector of uint8_t, where the str is formatted as hex
std::vector<uint8_t> convertVec(const std::string_view& str)
{
    std::vector<uint8_t> ret;
    auto len = str.size() / 2;
    ret.reserve(len);
    for (size_t i = 0; i < len; ++i)
    {
        ret.emplace_back(
            static_cast<uint8_t>(convert(str.substr(i * 2, 2), 16)));
    }
    return ret;
}

/** Construct OEM SEL record according to IPMI spec 32.2, 32.3. */
void constructOEMSEL(uint8_t recordType, std::chrono::milliseconds timestamp,
                     const additionalDataMap& m, GetSELEntryResponse& record)
{
    auto dataIter = m.find(strSensorData);
    assert(dataIter != m.end());
    auto sensorData = convertVec(dataIter->second);
    if (recordType >= 0xC0 && recordType < 0xE0)
    {
        record.event.oemCD.timeStamp = static_cast<uint32_t>(
            std::chrono::duration_cast<std::chrono::seconds>(timestamp)
                .count());
        record.event.oemCD.recordType = recordType;
        // The ManufactureID and OEM Defined are packed in the sensor data
        // Fill the 9 bytes of Manufacture ID and oemDefined
        memcpy(&record.event.oemCD.manufacturerID, sensorData.data(),
               std::min(sensorData.size(), static_cast<size_t>(oemCDDataSize)));
    }
    else if (recordType >= 0xE0)
    {
        record.event.oemEF.recordType = recordType;
        // The remaining 13 bytes are the OEM Defined data
        memcpy(&record.event.oemEF.oemDefined, sensorData.data(),
               std::min(sensorData.size(), static_cast<size_t>(oemEFDataSize)));
    }
}

void constructSEL(uint8_t recordType, std::chrono::milliseconds timestamp,
                  const additionalDataMap& m, const entryDataMap& entryData,
                  GetSELEntryResponse& record)
{
    if (recordType != systemEventRecord)
    {
        log<level::ERR>("Invalid recordType");
        elog<InternalFailure>();
    }

    // Default values when there is no matched sensor
    record.event.eventRecord.sensorType = 0;
    record.event.eventRecord.sensorNum = 0xFF;
    record.event.eventRecord.eventType = 0;

    auto iter = m.find(strSensorPath);
    assert(iter != m.end());
    const auto& sensorPath = iter->second;
    auto sensorIter = invSensors.find(sensorPath);

    if (sensorIter != invSensors.end())
    {
        // There is a matched sensor
        record.event.eventRecord.sensorType = sensorIter->second.sensorType;
        record.event.eventRecord.sensorNum = sensorIter->second.sensorID;

        iter = m.find(strEventDir);
        assert(iter != m.end());
        auto eventDir = static_cast<uint8_t>(convert(iter->second));
        uint8_t assert = eventDir ? assertEvent : deassertEvent;
        record.event.eventRecord.eventType =
            assert | sensorIter->second.eventReadingType;
    }
    record.event.eventRecord.recordType = recordType;
    record.event.eventRecord.timeStamp = static_cast<uint32_t>(
        std::chrono::duration_cast<std::chrono::seconds>(timestamp).count());
    iter = m.find(strGenerateId);
    assert(iter != m.end());
    record.event.eventRecord.generatorID =
        static_cast<uint16_t>(convert(iter->second));
    record.event.eventRecord.eventMsgRevision = eventMsgRevision;
    iter = m.find(strSensorData);
    assert(iter != m.end());
    auto sensorData = convertVec(iter->second);
    // The remaining 3 bytes are the sensor data
    memcpy(&record.event.eventRecord.eventData1, sensorData.data(),
           std::min(sensorData.size(), static_cast<size_t>(selDataSize)));
}

GetSELEntryResponse
    prepareSELEntry(const std::string& objPath,
                    ipmi::sensor::InvObjectIDMap::const_iterator iter)
{
    GetSELEntryResponse record{};

    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
    auto service = ipmi::getService(bus, logEntryIntf, objPath);

    // Read all the log entry properties.
    auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
                                          propIntf, "GetAll");
    methodCall.append(logEntryIntf);

    auto reply = bus.call(methodCall);
    if (reply.is_method_error())
    {
        log<level::ERR>("Error in reading logging property entries");
        elog<InternalFailure>();
    }

    entryDataMap entryData;
    reply.read(entryData);

    // Read Id from the log entry.
    static constexpr auto propId = "Id";
    auto iterId = entryData.find(propId);
    if (iterId == entryData.end())
    {
        log<level::ERR>("Error in reading Id of logging entry");
        elog<InternalFailure>();
    }

    // Read Timestamp from the log entry.
    static constexpr auto propTimeStamp = "Timestamp";
    auto iterTimeStamp = entryData.find(propTimeStamp);
    if (iterTimeStamp == entryData.end())
    {
        log<level::ERR>("Error in reading Timestamp of logging entry");
        elog<InternalFailure>();
    }
    std::chrono::milliseconds chronoTimeStamp(
        std::get<uint64_t>(iterTimeStamp->second));

    if (iter == invSensors.end())
    {
        // It is expected to be a custom SEL entry
        // The recordID are with the same offset between different types,
        // so we are safe to set the recordID here
        record.event.eventRecord.recordID =
            static_cast<uint16_t>(std::get<uint32_t>(iterId->second));
        iterId = entryData.find(propAdditionalData);
        if (iterId == entryData.end())
        {
            log<level::ERR>("Error finding AdditionalData");
            elog<InternalFailure>();
        }
        const auto& addData = std::get<AdditionalData>(iterId->second);
        auto m = parseAdditionalData(addData);
        auto recordType = static_cast<uint8_t>(convert(m[strRecordType]));
        auto isOEM = isRecordOEM(recordType);
        if (isOEM)
        {
            constructOEMSEL(recordType, chronoTimeStamp, m, record);
        }
        else
        {
            constructSEL(recordType, chronoTimeStamp, m, entryData, record);
        }
    }
    else
    {

        record.event.eventRecord.recordID =
            static_cast<uint16_t>(std::get<uint32_t>(iterId->second));
        record.event.eventRecord.timeStamp = static_cast<uint32_t>(
            std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
                .count());

        record.event.eventRecord.recordType = systemEventRecord;
        record.event.eventRecord.generatorID = generatorID;
        record.event.eventRecord.eventMsgRevision = eventMsgRevision;

        record.event.eventRecord.sensorType = iter->second.sensorType;
        record.event.eventRecord.sensorNum = iter->second.sensorID;
        record.event.eventRecord.eventData1 = iter->second.eventOffset;

        // Read Resolved from the log entry.
        auto iterResolved = entryData.find(propResolved);
        if (iterResolved == entryData.end())
        {
            log<level::ERR>("Error in reading Resolved field of logging entry");
            elog<InternalFailure>();
        }

        // Evaluate if the event is assertion or deassertion event
        if (std::get<bool>(iterResolved->second))
        {
            record.event.eventRecord.eventType =
                deassertEvent | iter->second.eventReadingType;
        }
        else
        {
            record.event.eventRecord.eventType = iter->second.eventReadingType;
        }
    }

    return record;
}

} // namespace internal

GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
{
    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};

    static constexpr auto assocIntf =
        "xyz.openbmc_project.Association.Definitions";
    static constexpr auto assocProp = "Associations";

    auto service = ipmi::getService(bus, assocIntf, objPath);

    // Read the Associations interface.
    auto methodCall =
        bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
    methodCall.append(assocIntf);
    methodCall.append(assocProp);

    auto reply = bus.call(methodCall);
    if (reply.is_method_error())
    {
        log<level::ERR>("Error in reading Associations interface");
        elog<InternalFailure>();
    }

    using AssociationList =
        std::vector<std::tuple<std::string, std::string, std::string>>;

    std::variant<AssociationList> list;
    reply.read(list);

    auto& assocs = std::get<AssociationList>(list);

    /*
     * Check if the log entry has any callout associations, if there is a
     * callout association try to match the inventory path to the corresponding
     * IPMI sensor.
     */
    for (const auto& item : assocs)
    {
        if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
        {
            auto iter = invSensors.find(std::get<2>(item));
            if (iter == invSensors.end())
            {
                iter = invSensors.find(BOARD_SENSOR);
                if (iter == invSensors.end())
                {
                    log<level::ERR>("Motherboard sensor not found");
                    elog<InternalFailure>();
                }
            }

            return internal::prepareSELEntry(objPath, iter);
        }
    }

    // If there are no callout associations link the log entry to system event
    // sensor
    auto iter = invSensors.find(SYSTEM_SENSOR);
    return internal::prepareSELEntry(objPath, iter);
}

std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
{
    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};

    auto service = ipmi::getService(bus, logEntryIntf, objPath);

    using namespace std::string_literals;
    static const auto propTimeStamp = "Timestamp"s;

    auto methodCall =
        bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
    methodCall.append(logEntryIntf);
    methodCall.append(propTimeStamp);

    auto reply = bus.call(methodCall);
    if (reply.is_method_error())
    {
        log<level::ERR>("Error in reading Timestamp from Entry interface");
        elog<InternalFailure>();
    }

    std::variant<uint64_t> timeStamp;
    reply.read(timeStamp);

    std::chrono::milliseconds chronoTimeStamp(std::get<uint64_t>(timeStamp));

    return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
}

void readLoggingObjectPaths(ObjectPaths& paths)
{
    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
    auto depth = 0;
    paths.clear();

    auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
                                          mapperIntf, "GetSubTreePaths");
    mapperCall.append(logBasePath);
    mapperCall.append(depth);
    mapperCall.append(ObjectPaths({logEntryIntf}));

    auto reply = bus.call(mapperCall);
    if (reply.is_method_error())
    {
        log<level::INFO>("Error in reading logging entry object paths");
    }
    else
    {
        reply.read(paths);

        std::sort(paths.begin(), paths.end(),
                  [](const std::string& a, const std::string& b) {
                      namespace fs = std::filesystem;
                      fs::path pathA(a);
                      fs::path pathB(b);
                      auto idA = std::stoul(pathA.filename().string());
                      auto idB = std::stoul(pathB.filename().string());

                      return idA < idB;
                  });
    }
}

} // namespace sel

} // namespace ipmi
<|endoftext|>