<commit_before>/******************************************************************************

  This source file is part of the Avogadro project.

  Copyright 2013 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "xyzformat.h"

#include <avogadro/core/elements.h>
#include <avogadro/core/molecule.h>
#include <avogadro/core/utilities.h>
#include <avogadro/core/vector.h>

#include <iomanip>
#include <istream>
#include <ostream>
#include <string>
#include <sstream>

using std::string;
using std::endl;
using std::getline;
using std::string;
using std::vector;

namespace Avogadro {
namespace Io {

using Core::Array;
using Core::Atom;
using Core::Elements;
using Core::Molecule;
using Core::lexicalCast;
using Core::split;
using Core::trimmed;

#ifndef _WIN32
using std::isalpha;
#endif

XyzFormat::XyzFormat()
{
}

XyzFormat::~XyzFormat()
{
}

bool XyzFormat::read(std::istream &inStream, Core::Molecule &mol)
{
  size_t numAtoms = 0;
  if (!(inStream >> numAtoms)) {
    appendError("Error parsing number of atoms.");
    return false;
  }

  string buffer;
  getline(inStream, buffer); // Finish the first line
  getline(inStream, buffer);
  if (!buffer.empty())
    mol.setData("name", trimmed(buffer));

  // Parse atoms
  for (size_t i = 0; i < numAtoms; ++i) {
    getline(inStream, buffer);
    vector<string> tokens(split(buffer, ' '));

    if (tokens.size() < 4) {
      appendError("Not enough tokens in this line: " + buffer);
      return false;
    }

    unsigned char atomicNum(0);
    if (isalpha(tokens[0][0]))
      atomicNum = Elements::atomicNumberFromSymbol(tokens[0]);
    else
      atomicNum = static_cast<unsigned char>(lexicalCast<short int>(tokens[0]));

    Vector3 pos(lexicalCast<double>(tokens[1]),
                lexicalCast<double>(tokens[2]),
                lexicalCast<double>(tokens[3]));

    Atom newAtom = mol.addAtom(atomicNum);
    newAtom.setPosition3d(pos);
  }

  // Check that all atoms were handled.
  if (mol.atomCount() != numAtoms) {
    std::ostringstream errorStream;
    errorStream << "Error parsing atom at index " << mol.atomCount()
                << " (line " << 3 + mol.atomCount() << ").\n" << buffer;
    appendError(errorStream.str());
    return false;
  }

  // Do we have an animation?
  size_t numAtoms2;
  if (getline(inStream, buffer) && (numAtoms2 = lexicalCast<int>(buffer))
      && numAtoms == numAtoms2) {
    getline(inStream, buffer); // Skip the blank
    mol.setCoordinate3d(mol.atomPositions3d(), 0);
    int coordSet = 1;
    while (numAtoms == numAtoms2) {
      Array<Vector3> positions;
      positions.reserve(numAtoms);

      for (size_t i = 0; i < numAtoms; ++i) {
        getline(inStream, buffer);
        vector<string> tokens(split(buffer, ' '));
        if (tokens.size() < 4) {
          appendError("Not enough tokens in this line: " + buffer);
          return false;
        }
        Vector3 pos(lexicalCast<double>(tokens[1]),
                    lexicalCast<double>(tokens[2]),
                    lexicalCast<double>(tokens[3]));
        positions.push_back(pos);
      }

      mol.setCoordinate3d(positions, coordSet++);

      if (!getline(inStream, buffer)) {
        numAtoms2 = lexicalCast<int>(buffer);
        if (numAtoms == numAtoms2)
          break;
      }

      std::getline(inStream, buffer); // Skip the blank
      positions.clear();
    }
  }

  return true;
}

bool XyzFormat::write(std::ostream &outStream, const Core::Molecule &mol)
{
  size_t numAtoms = mol.atomCount();

  outStream << numAtoms << std::endl;
  if (mol.data("name").toString().length())
    outStream << mol.data("name").toString() << endl;
  else
    outStream << "XYZ file generated by Avogadro.\n";

  for (size_t i = 0; i < numAtoms; ++i) {
    Atom atom = mol.atom(i);
    if (!atom.isValid()) {
      appendError("Internal error: Atom invalid.");
      return false;
    }

    outStream << std::setw(3) << std::left
              << Elements::symbol(atom.atomicNumber()) << " "
              << std::setw(10) << std::right << std::fixed
              << std::setprecision(5)
              << atom.position3d().x() << " "
              << std::setw(10) << std::right << std::fixed
              << std::setprecision(5)
              << atom.position3d().y() << " "
              << std::setw(10) << std::right << std::fixed
              << std::setprecision(5)
              << atom.position3d().z() << "\n";
  }

  return true;
}

std::vector<std::string> XyzFormat::fileExtensions() const
{
  std::vector<std::string> ext;
  ext.push_back("xyz");
  return ext;
}

std::vector<std::string> XyzFormat::mimeTypes() const
{
  std::vector<std::string> mime;
  mime.push_back("chemical/x-xyz");
  return mime;
}

} // end Io namespace
} // end Avogadro namespace
<commit_msg>Do simple bond perception for XYZ<commit_after>/******************************************************************************

  This source file is part of the Avogadro project.

  Copyright 2013 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "xyzformat.h"

#include <avogadro/core/elements.h>
#include <avogadro/core/molecule.h>
#include <avogadro/core/utilities.h>
#include <avogadro/core/vector.h>

#include <iomanip>
#include <istream>
#include <ostream>
#include <string>
#include <sstream>

using std::string;
using std::endl;
using std::getline;
using std::string;
using std::vector;

namespace Avogadro {
namespace Io {

using Core::Array;
using Core::Atom;
using Core::Elements;
using Core::Molecule;
using Core::lexicalCast;
using Core::split;
using Core::trimmed;

#ifndef _WIN32
using std::isalpha;
#endif

XyzFormat::XyzFormat()
{
}

XyzFormat::~XyzFormat()
{
}

bool XyzFormat::read(std::istream &inStream, Core::Molecule &mol)
{
  size_t numAtoms = 0;
  if (!(inStream >> numAtoms)) {
    appendError("Error parsing number of atoms.");
    return false;
  }

  string buffer;
  getline(inStream, buffer); // Finish the first line
  getline(inStream, buffer);
  if (!buffer.empty())
    mol.setData("name", trimmed(buffer));

  // Parse atoms
  for (size_t i = 0; i < numAtoms; ++i) {
    getline(inStream, buffer);
    vector<string> tokens(split(buffer, ' '));

    if (tokens.size() < 4) {
      appendError("Not enough tokens in this line: " + buffer);
      return false;
    }

    unsigned char atomicNum(0);
    if (isalpha(tokens[0][0]))
      atomicNum = Elements::atomicNumberFromSymbol(tokens[0]);
    else
      atomicNum = static_cast<unsigned char>(lexicalCast<short int>(tokens[0]));

    Vector3 pos(lexicalCast<double>(tokens[1]),
                lexicalCast<double>(tokens[2]),
                lexicalCast<double>(tokens[3]));

    Atom newAtom = mol.addAtom(atomicNum);
    newAtom.setPosition3d(pos);
  }

  // Check that all atoms were handled.
  if (mol.atomCount() != numAtoms) {
    std::ostringstream errorStream;
    errorStream << "Error parsing atom at index " << mol.atomCount()
                << " (line " << 3 + mol.atomCount() << ").\n" << buffer;
    appendError(errorStream.str());
    return false;
  }

  // Do we have an animation?
  size_t numAtoms2;
  if (getline(inStream, buffer) && (numAtoms2 = lexicalCast<int>(buffer))
      && numAtoms == numAtoms2) {
    getline(inStream, buffer); // Skip the blank
    mol.setCoordinate3d(mol.atomPositions3d(), 0);
    int coordSet = 1;
    while (numAtoms == numAtoms2) {
      Array<Vector3> positions;
      positions.reserve(numAtoms);

      for (size_t i = 0; i < numAtoms; ++i) {
        getline(inStream, buffer);
        vector<string> tokens(split(buffer, ' '));
        if (tokens.size() < 4) {
          appendError("Not enough tokens in this line: " + buffer);
          return false;
        }
        Vector3 pos(lexicalCast<double>(tokens[1]),
                    lexicalCast<double>(tokens[2]),
                    lexicalCast<double>(tokens[3]));
        positions.push_back(pos);
      }

      mol.setCoordinate3d(positions, coordSet++);

      if (!getline(inStream, buffer)) {
        numAtoms2 = lexicalCast<int>(buffer);
        if (numAtoms == numAtoms2)
          break;
      }

      std::getline(inStream, buffer); // Skip the blank
      positions.clear();
    }
  }

  // This format has no connectivity information, so perceive basics at least.
  mol.perceiveBondsSimple();

  return true;
}

bool XyzFormat::write(std::ostream &outStream, const Core::Molecule &mol)
{
  size_t numAtoms = mol.atomCount();

  outStream << numAtoms << std::endl;
  if (mol.data("name").toString().length())
    outStream << mol.data("name").toString() << endl;
  else
    outStream << "XYZ file generated by Avogadro.\n";

  for (size_t i = 0; i < numAtoms; ++i) {
    Atom atom = mol.atom(i);
    if (!atom.isValid()) {
      appendError("Internal error: Atom invalid.");
      return false;
    }

    outStream << std::setw(3) << std::left
              << Elements::symbol(atom.atomicNumber()) << " "
              << std::setw(10) << std::right << std::fixed
              << std::setprecision(5)
              << atom.position3d().x() << " "
              << std::setw(10) << std::right << std::fixed
              << std::setprecision(5)
              << atom.position3d().y() << " "
              << std::setw(10) << std::right << std::fixed
              << std::setprecision(5)
              << atom.position3d().z() << "\n";
  }

  return true;
}

std::vector<std::string> XyzFormat::fileExtensions() const
{
  std::vector<std::string> ext;
  ext.push_back("xyz");
  return ext;
}

std::vector<std::string> XyzFormat::mimeTypes() const
{
  std::vector<std::string> mime;
  mime.push_back("chemical/x-xyz");
  return mime;
}

} // end Io namespace
} // end Avogadro namespace
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "editorwidget.h"
#include "formeditorw.h"

#include <coreplugin/minisplitter.h>
#include <utils/qtcassert.h>

#include <QtCore/QEvent>
#include <QtGui/QVBoxLayout>
#include <QtGui/QTabWidget>

using namespace Designer::Constants;

enum { ActionEditorTab, SignalSlotEditorTab };

enum { wantSignalSlotEditor = 1 };

namespace Designer {
namespace Internal {

SharedSubWindow::SharedSubWindow(QWidget *shared, QWidget *parent) :
   QWidget(parent),
   m_shared(shared),
   m_layout(new QVBoxLayout)
{
    QTC_ASSERT(m_shared, /**/);
    m_layout->setContentsMargins(0, 0, 0, 0);
    setLayout(m_layout);
}

void SharedSubWindow::activate()
{
    // Take the widget off the other parent
    QTC_ASSERT(m_shared, return);
    QWidget *currentParent = m_shared->parentWidget();
    if (currentParent == this)
        return;

    if (currentParent) {
        QVBoxLayout *lt = qobject_cast<QVBoxLayout *>(currentParent->layout());
        QTC_ASSERT(lt, return);
        m_shared->setParent(0);
        delete lt->takeAt(0);
    }
    m_layout->addWidget(m_shared);
    m_layout->invalidate();
}

SharedSubWindow::~SharedSubWindow()
{
    // Do not destroy the shared sub window if we currently own it
    if (m_layout->count()) {
        m_shared->setParent(0);
        delete m_layout->takeAt(0);
    }
}

// ---------- Global EditorState
Q_GLOBAL_STATIC(EditorWidgetState, editorWidgetState)

enum { Version = 1 };
// Simple conversion of an int list to QVariantList, size as leading element
static void intToVariantList(const QList<int> &il, QVariantList& vl)
{
    const int size = il.size();
    vl.push_back(size);
    if (size != 0) {
        const QList<int>::const_iterator cend = il.constEnd();
        for (QList<int>::const_iterator it = il.constBegin(); it != cend; ++it)
            vl.push_back(QVariant(*it));
    }
}
// Simple conversion of a QVariantList portion saved by the above function to int list
bool variantListToIntList(const QVariantList& vl, int &index, QList<int> &list)
{
    list.clear();
    if (index >= vl.size())
        return false;
    const int size = vl.at(index++).toInt();
    const int end = index + size;
    if (end > vl.size())
        return false;
    if (size != 0) {
        for ( ; index < end; index++)
            list.push_back(vl.at(index).toInt());
    }
    return true;
}

// ------------------ EditorWidgetState
QVariant EditorWidgetState::toVariant() const
{
    QVariantList rc;
    rc.push_back(Version);
    intToVariantList(horizontalSizes, rc);
    intToVariantList(centerVerticalSizes, rc);
    intToVariantList(rightVerticalSizes, rc);
    return QVariant(rc);
}

bool EditorWidgetState::fromVariant(const QVariant &v)
{
    // Restore state. The weird thing is that QSettings might return
    // a QStringList although it was saved as QVariantList<int>.
    if (v.type() != QVariant::List && v.type() != QVariant::StringList)
        return false;
    const QVariantList vl = v.toList();
    if (vl.empty())
        return false;
    int index = 0;
    const QVariant &versionV = vl.at(index++);
    if (versionV.type() != QVariant::Int && versionV.type() != QVariant::String)
        return false;
    if (versionV.toInt() > Version)
        return false;
    return variantListToIntList(vl, index, horizontalSizes) &&
           variantListToIntList(vl, index, centerVerticalSizes) &&
           variantListToIntList(vl, index, rightVerticalSizes);
}

// ---------- EditorWidget
EditorWidget::EditorWidget(QWidget *formWindow) :
    Core::MiniSplitter(Qt::Horizontal),
    m_centerVertSplitter(new Core::MiniSplitter(Qt::Vertical)),
    m_bottomTab(0),
    m_rightVertSplitter(new Core::MiniSplitter(Qt::Vertical))
{
    // Get shared sub windows from Form Editor
    FormEditorW *few = FormEditorW::instance();
    QWidget * const*subs = few->designerSubWindows();
    // Create shared sub windows except SignalSlotEditor
    qFill(m_designerSubWindows, m_designerSubWindows + DesignerSubWindowCount, static_cast<SharedSubWindow*>(0));
    for (int i=0; i < DesignerSubWindowCount; i++)
        if (wantSignalSlotEditor || i != SignalSlotEditorSubWindow)
            m_designerSubWindows[i] = new SharedSubWindow(subs[i]);
    // Create splitter
    addWidget(m_designerSubWindows[WidgetBoxSubWindow]);

    // center
    m_centerVertSplitter->addWidget(formWindow);

    if (wantSignalSlotEditor) {
        m_bottomTab = new QTabWidget;
        m_bottomTab->setTabPosition(QTabWidget::South);
        m_bottomTab->addTab(m_designerSubWindows[ActionEditorSubWindow], tr("Action editor"));
        m_bottomTab->addTab(m_designerSubWindows[SignalSlotEditorSubWindow], tr("Signals and slots editor"));
        m_centerVertSplitter->addWidget(m_bottomTab);
    } else {
        m_centerVertSplitter->addWidget(m_designerSubWindows[ActionEditorSubWindow]);
    }

    addWidget(m_centerVertSplitter);

    m_rightVertSplitter->addWidget(m_designerSubWindows[ObjectInspectorSubWindow]);
    m_rightVertSplitter->addWidget(m_designerSubWindows[PropertyEditorSubWindow]);
    addWidget(m_rightVertSplitter);
}

void EditorWidget::setInitialSizes()
{
    QList<int> sizes;
    // center vertical. Either the tab containing signal slot editor/
    // action editor or the action editor itself
    const QWidget *bottomWidget = m_bottomTab;
    if (!bottomWidget)
        bottomWidget = m_designerSubWindows[ActionEditorSubWindow];
    const int tabHeight = bottomWidget->sizeHint().height();
    sizes.push_back(height() - handleWidth() -  tabHeight);
    sizes.push_back( tabHeight);
    m_centerVertSplitter->setSizes(sizes);
    // right vert
    sizes.clear();
    sizes.push_back(height() /2 - (handleWidth() / 2));
    sizes.push_back(height() / 2 - (handleWidth() / 2));
    m_rightVertSplitter->setSizes(sizes);
    // horiz sizes
    sizes.clear();
    const int wboxWidth = m_designerSubWindows[WidgetBoxSubWindow]->sizeHint().width();
    const int vSplitterWidth = m_rightVertSplitter->sizeHint().width();
    sizes.push_back(wboxWidth);
    sizes.push_back(width() - 2 * handleWidth() -  wboxWidth - vSplitterWidth);
    sizes.push_back(vSplitterWidth);
    setSizes(sizes);
}

void EditorWidget::activate()
{
    for (int i=0; i < DesignerSubWindowCount; i++)
        if (SharedSubWindow *sw = m_designerSubWindows[i]) // Signal slot might be deactivated
            sw->activate();
    if (!restore(*editorWidgetState()))
        setInitialSizes();
}

bool EditorWidget::event(QEvent * e)
{
    if (e->type() == QEvent::Hide)
        *editorWidgetState() = save();
    return QSplitter::event(e);
}

EditorWidgetState EditorWidget::save() const
{
    EditorWidgetState rc;
    rc.horizontalSizes = sizes();
    rc.centerVerticalSizes = m_centerVertSplitter->sizes();
    rc.rightVerticalSizes = m_rightVertSplitter->sizes();
    return rc;
}

bool EditorWidget::restore(const EditorWidgetState &s)
{
    if (s.horizontalSizes.size() != count() ||
        s.centerVerticalSizes.size() != m_centerVertSplitter->count() ||
        s.rightVerticalSizes.size() != m_rightVertSplitter->count())
        return false;
    m_centerVertSplitter->setSizes(s.centerVerticalSizes);
    m_rightVertSplitter->setSizes(s.rightVerticalSizes);
    setSizes(s.horizontalSizes);
    return true;
}

void EditorWidget::toolChanged(int i)
{
    if (m_bottomTab)
        m_bottomTab->setCurrentIndex(i == EditModeSignalsSlotEditor ? SignalSlotEditorTab : ActionEditorTab);
}

EditorWidgetState EditorWidget::state()
{
    return *editorWidgetState();
}

void EditorWidget::setState(const EditorWidgetState& st)
{
    *editorWidgetState() = st;
}

} // namespace Internal
} // namespace Designer
<commit_msg>Set document mode on tab widget to hide ugly frame<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "editorwidget.h"
#include "formeditorw.h"

#include <coreplugin/minisplitter.h>
#include <utils/qtcassert.h>

#include <QtCore/QEvent>
#include <QtGui/QVBoxLayout>
#include <QtGui/QTabWidget>

using namespace Designer::Constants;

enum { ActionEditorTab, SignalSlotEditorTab };

enum { wantSignalSlotEditor = 1 };

namespace Designer {
namespace Internal {

SharedSubWindow::SharedSubWindow(QWidget *shared, QWidget *parent) :
   QWidget(parent),
   m_shared(shared),
   m_layout(new QVBoxLayout)
{
    QTC_ASSERT(m_shared, /**/);
    m_layout->setContentsMargins(0, 0, 0, 0);
    setLayout(m_layout);
}

void SharedSubWindow::activate()
{
    // Take the widget off the other parent
    QTC_ASSERT(m_shared, return);
    QWidget *currentParent = m_shared->parentWidget();
    if (currentParent == this)
        return;

    if (currentParent) {
        QVBoxLayout *lt = qobject_cast<QVBoxLayout *>(currentParent->layout());
        QTC_ASSERT(lt, return);
        m_shared->setParent(0);
        delete lt->takeAt(0);
    }
    m_layout->addWidget(m_shared);
    m_layout->invalidate();
}

SharedSubWindow::~SharedSubWindow()
{
    // Do not destroy the shared sub window if we currently own it
    if (m_layout->count()) {
        m_shared->setParent(0);
        delete m_layout->takeAt(0);
    }
}

// ---------- Global EditorState
Q_GLOBAL_STATIC(EditorWidgetState, editorWidgetState)

enum { Version = 1 };
// Simple conversion of an int list to QVariantList, size as leading element
static void intToVariantList(const QList<int> &il, QVariantList& vl)
{
    const int size = il.size();
    vl.push_back(size);
    if (size != 0) {
        const QList<int>::const_iterator cend = il.constEnd();
        for (QList<int>::const_iterator it = il.constBegin(); it != cend; ++it)
            vl.push_back(QVariant(*it));
    }
}
// Simple conversion of a QVariantList portion saved by the above function to int list
bool variantListToIntList(const QVariantList& vl, int &index, QList<int> &list)
{
    list.clear();
    if (index >= vl.size())
        return false;
    const int size = vl.at(index++).toInt();
    const int end = index + size;
    if (end > vl.size())
        return false;
    if (size != 0) {
        for ( ; index < end; index++)
            list.push_back(vl.at(index).toInt());
    }
    return true;
}

// ------------------ EditorWidgetState
QVariant EditorWidgetState::toVariant() const
{
    QVariantList rc;
    rc.push_back(Version);
    intToVariantList(horizontalSizes, rc);
    intToVariantList(centerVerticalSizes, rc);
    intToVariantList(rightVerticalSizes, rc);
    return QVariant(rc);
}

bool EditorWidgetState::fromVariant(const QVariant &v)
{
    // Restore state. The weird thing is that QSettings might return
    // a QStringList although it was saved as QVariantList<int>.
    if (v.type() != QVariant::List && v.type() != QVariant::StringList)
        return false;
    const QVariantList vl = v.toList();
    if (vl.empty())
        return false;
    int index = 0;
    const QVariant &versionV = vl.at(index++);
    if (versionV.type() != QVariant::Int && versionV.type() != QVariant::String)
        return false;
    if (versionV.toInt() > Version)
        return false;
    return variantListToIntList(vl, index, horizontalSizes) &&
           variantListToIntList(vl, index, centerVerticalSizes) &&
           variantListToIntList(vl, index, rightVerticalSizes);
}

// ---------- EditorWidget
EditorWidget::EditorWidget(QWidget *formWindow) :
    Core::MiniSplitter(Qt::Horizontal),
    m_centerVertSplitter(new Core::MiniSplitter(Qt::Vertical)),
    m_bottomTab(0),
    m_rightVertSplitter(new Core::MiniSplitter(Qt::Vertical))
{
    // Get shared sub windows from Form Editor
    FormEditorW *few = FormEditorW::instance();
    QWidget * const*subs = few->designerSubWindows();
    // Create shared sub windows except SignalSlotEditor
    qFill(m_designerSubWindows, m_designerSubWindows + DesignerSubWindowCount, static_cast<SharedSubWindow*>(0));
    for (int i=0; i < DesignerSubWindowCount; i++)
        if (wantSignalSlotEditor || i != SignalSlotEditorSubWindow)
            m_designerSubWindows[i] = new SharedSubWindow(subs[i]);
    // Create splitter
    addWidget(m_designerSubWindows[WidgetBoxSubWindow]);

    // center
    m_centerVertSplitter->addWidget(formWindow);

    if (wantSignalSlotEditor) {
        m_bottomTab = new QTabWidget;
        m_bottomTab->setTabPosition(QTabWidget::South);
        m_bottomTab->setDocumentMode(true);
        m_bottomTab->addTab(m_designerSubWindows[ActionEditorSubWindow], tr("Action editor"));
        m_bottomTab->addTab(m_designerSubWindows[SignalSlotEditorSubWindow], tr("Signals and slots editor"));
        m_centerVertSplitter->addWidget(m_bottomTab);
    } else {
        m_centerVertSplitter->addWidget(m_designerSubWindows[ActionEditorSubWindow]);
    }

    addWidget(m_centerVertSplitter);

    m_rightVertSplitter->addWidget(m_designerSubWindows[ObjectInspectorSubWindow]);
    m_rightVertSplitter->addWidget(m_designerSubWindows[PropertyEditorSubWindow]);
    addWidget(m_rightVertSplitter);
}

void EditorWidget::setInitialSizes()
{
    QList<int> sizes;
    // center vertical. Either the tab containing signal slot editor/
    // action editor or the action editor itself
    const QWidget *bottomWidget = m_bottomTab;
    if (!bottomWidget)
        bottomWidget = m_designerSubWindows[ActionEditorSubWindow];
    const int tabHeight = bottomWidget->sizeHint().height();
    sizes.push_back(height() - handleWidth() -  tabHeight);
    sizes.push_back( tabHeight);
    m_centerVertSplitter->setSizes(sizes);
    // right vert
    sizes.clear();
    sizes.push_back(height() /2 - (handleWidth() / 2));
    sizes.push_back(height() / 2 - (handleWidth() / 2));
    m_rightVertSplitter->setSizes(sizes);
    // horiz sizes
    sizes.clear();
    const int wboxWidth = m_designerSubWindows[WidgetBoxSubWindow]->sizeHint().width();
    const int vSplitterWidth = m_rightVertSplitter->sizeHint().width();
    sizes.push_back(wboxWidth);
    sizes.push_back(width() - 2 * handleWidth() -  wboxWidth - vSplitterWidth);
    sizes.push_back(vSplitterWidth);
    setSizes(sizes);
}

void EditorWidget::activate()
{
    for (int i=0; i < DesignerSubWindowCount; i++)
        if (SharedSubWindow *sw = m_designerSubWindows[i]) // Signal slot might be deactivated
            sw->activate();
    if (!restore(*editorWidgetState()))
        setInitialSizes();
}

bool EditorWidget::event(QEvent * e)
{
    if (e->type() == QEvent::Hide)
        *editorWidgetState() = save();
    return QSplitter::event(e);
}

EditorWidgetState EditorWidget::save() const
{
    EditorWidgetState rc;
    rc.horizontalSizes = sizes();
    rc.centerVerticalSizes = m_centerVertSplitter->sizes();
    rc.rightVerticalSizes = m_rightVertSplitter->sizes();
    return rc;
}

bool EditorWidget::restore(const EditorWidgetState &s)
{
    if (s.horizontalSizes.size() != count() ||
        s.centerVerticalSizes.size() != m_centerVertSplitter->count() ||
        s.rightVerticalSizes.size() != m_rightVertSplitter->count())
        return false;
    m_centerVertSplitter->setSizes(s.centerVerticalSizes);
    m_rightVertSplitter->setSizes(s.rightVerticalSizes);
    setSizes(s.horizontalSizes);
    return true;
}

void EditorWidget::toolChanged(int i)
{
    if (m_bottomTab)
        m_bottomTab->setCurrentIndex(i == EditModeSignalsSlotEditor ? SignalSlotEditorTab : ActionEditorTab);
}

EditorWidgetState EditorWidget::state()
{
    return *editorWidgetState();
}

void EditorWidget::setState(const EditorWidgetState& st)
{
    *editorWidgetState() = st;
}

} // namespace Internal
} // namespace Designer
<|endoftext|>


<commit_before>/* Nom: main.cpp
 * Description: Sous-système de contrôle: responsable de la gestion du dialogue avec l'utilisateur et de l'interface graphique
 * Date: 07.03.2015
 * version : 1.1
 * auteur : PROG II
 */

extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error.h"
#include "sim.h"
#include "main.h"
}

int main (int argc, char *argv[])
{
	enum Mode mode;
    mode = read_mode(argv[1]);

	if(argc!=3)
	{
		printf("syntaxe attendue : sim.x [Error|Force|Integration|Graphic|Simulation,nom_fichier]\n");
	}
	else
	{
		switch(mode)
		{
			case ERROR: sim_error(argv[2]);
			break;
			case FORCE: sim_force(argv[2]);
			break;
			case INTEGRATION: sim_integration(argv[2]);
			break;
			case GRAPHIC: sim_graphic(argv[2]);
			break;
			case SIMULATION: sim_simulation(argv[2]);
			break;
			case MODE_UNSET: printf("syntaxe attendue : sim.x [Error|Force|Integration|Graphic|Simulation,nom_fichier]\n");
			break;
		}
	}
	return EXIT_SUCCESS;
}

MODE read_mode(char string[])
{
	MODE mode;
	if(strcmp(argv[1], "Error" ) == 0)
    {
		mode = ERROR;
    }
    else if (strcmp(argv[1], "Force" ) == 0)
    {
		mode = FORCE;
    }
    else if (strcmp(argv[1], "Integration" ) == 0)
    {
		mode = INTEGRATION;
    }
    else if (strcmp(argv[1], "Graphic" ) == 0)
    {
		mode = GRAPHIC;
    }
    else if (strcmp(argv[1], "Simulation" ) == 0)
    {
		mode = SIMULATION;
    }
    else
    {
		mode = MODE_UNSET;
    }
    return mode;
}

<commit_msg>in main.cpp erreur del'argument résolue<commit_after>/* Nom: main.cpp
 * Description: Sous-système de contrôle: responsable de la gestion du dialogue avec l'utilisateur et de l'interface graphique
 * Date: 07.03.2015
 * version : 1.1
 * auteur : PROG II
 */

extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error.h"
#include "sim.h"
#include "main.h"
}

int main (int argc, char *argv[])
{
	enum Mode mode;
    mode = read_mode(argv[1]);

	if(argc!=3)
	{
		printf("syntaxe attendue : sim.x [Error|Force|Integration|Graphic|Simulation,nom_fichier]\n");
	}
	else
	{
		switch(mode)
		{
			case ERROR: sim_error(argv[2]);
			break;
			case FORCE: sim_force(argv[2]);
			break;
			case INTEGRATION: sim_integration(argv[2]);
			break;
			case GRAPHIC: sim_graphic(argv[2]);
			break;
			case SIMULATION: sim_simulation(argv[2]);
			break;
			case MODE_UNSET: printf("syntaxe attendue : sim.x [Error|Force|Integration|Graphic|Simulation,nom_fichier]\n");
			break;
		}
	}
	return EXIT_SUCCESS;
}

MODE read_mode(char string[])
{
	MODE mode;
	if(strcmp(string, "Error" ) == 0)
    {
		mode = ERROR;
    }
    else if (strcmp(string, "Force" ) == 0)
    {
		mode = FORCE;
    }
    else if (strcmp(string, "Integration" ) == 0)
    {
		mode = INTEGRATION;
    }
    else if (strcmp(string, "Graphic" ) == 0)
    {
		mode = GRAPHIC;
    }
    else if (strcmp(string, "Simulation" ) == 0)
    {
		mode = SIMULATION;
    }
    else
    {
		mode = MODE_UNSET;
    }
    return mode;
}

<|endoftext|>


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

#include "mbed-drivers/mbed.h"
#include "ble/BLE.h"
#include "EddystoneService.h"

#include "PersistentStorageHelper/ConfigParamsPersistence.h"
// #include "stdio.h"

// Instantiation of the main event loop for this program

#ifdef YOTTA_CFG_MBED_OS  // use minar on mbed OS
#include "EventQueue/EventQueueMinar.h"
typedef eq::EventQueueMinar event_queue_t;

#else      // otherwise use the event classic queue
#include "EventQueue/EventQueueClassic.h"
typedef eq::EventQueueClassic<
    /* event count */ 10
> event_queue_t;

#endif

static event_queue_t eventQueue;

EddystoneService *eddyServicePtr;

/* Duration after power-on that config service is available. */
static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = YOTTA_CFG_EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS;

/* Values for ADV packets related to firmware levels, calibrated based on measured values at 1m */
static const PowerLevels_t advTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS;
/* Values for radio power levels, provided by manufacturer. */
static const PowerLevels_t radioTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS;

// This allows a quick switch between targets without changing the 'platform'
// settings in config.json each time. If you do change target to nrf51dk-gcc,
// note you will still need to change 'softdevice' to 's130'
//
 #define QUICK_SWITCH_TO_NRF51DK 1
#ifdef QUICK_SWITCH_TO_NRF51DK
    #define LED_OFF 1
    #define CONFIG_LED LED3
    #define SHUTDOWN_LED LED1
    #define RESET_BUTTON BUTTON1
#else
    #define LED_OFF YOTTA_CFG_PLATFORM_LED_OFF
    #define CONFIG_LED YOTTA_CFG_PLATFORM_CONFIG_LED
    #define SHUTDOWN_LED YOTTA_CFG_PLATFORM_SHUTDOWN_LED
    #define RESET_BUTTON YOTTA_CFG_PLATFORM_RESET_BUTTON
#endif

DigitalOut configLED(CONFIG_LED, LED_OFF);
DigitalOut shutdownLED(SHUTDOWN_LED, LED_OFF);
InterruptIn button(RESET_BUTTON);

static int buttonBusy;                                    // semaphore to make prevent switch bounce problems

static const int BLINKY_MSEC = 500;                       // How long to cycle config LED on/off
static int beaconIsOn = 1;                                // Button handler boolean to switch on or off
static event_queue_t::event_handle_t handle = 0;         // For the config mode timeout
static event_queue_t::event_handle_t BlinkyHandle = 0;   // For the blinking LED when in config mode

static void blinky(void)  { configLED = !configLED; }
static void shutdownLED_on(void) { shutdownLED = !LED_OFF; }
static void shutdownLED_off(void) { shutdownLED = LED_OFF; }
static void freeButtonBusy(void) { buttonBusy = false; }

static void configLED_on(void) {
    configLED = !LED_OFF;
    BlinkyHandle = eventQueue.post_every(blinky, BLINKY_MSEC);
}
static void configLED_off(void) {
    configLED = LED_OFF;
    if (BlinkyHandle) {
        eventQueue.cancel(BlinkyHandle);
        BlinkyHandle = NULL;
    }
}

/**
 * Callback triggered some time after application started to switch to beacon mode.
 */
static void timeoutToStartEddystoneBeaconAdvertisements(void)
{
    Gap::GapState_t state;
    state = BLE::Instance().gap().getState();
    if (!state.connected) { /* don't switch if we're in a connected state. */
        eddyServicePtr->startEddystoneBeaconAdvertisements();
        configLED_off();
    }
}

/**
 * Callback triggered for a connection event.
 */
static void connectionCallback(const Gap::ConnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    // Stop advertising whatever the current mode
    eddyServicePtr->stopEddystoneBeaconAdvertisements();
}

/**
 * Callback triggered for a disconnection event.
 */
static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    BLE::Instance().gap().startAdvertising();
    // Save params in persistent storage
    EddystoneService::EddystoneParams_t params;
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);
    // Ensure LED is off at the end of Config Mode or during a connection
    configLED_off();
    // 0.5 Second callback to rapidly re-establish Beaconing Service
    // (because it needs to be executed outside of disconnect callback)
    eventQueue.post_in(timeoutToStartEddystoneBeaconAdvertisements, 500 /* ms */);
}

// Callback used to handle button presses from thread mode (not IRQ)
static void button_task(void) {
    eventQueue.cancel(handle);   // kill any pending callback tasks

    if (beaconIsOn) {
        beaconIsOn = 0;
        eddyServicePtr->stopEddystoneBeaconAdvertisements();
        configLED_off();    // just in case it's still running...
        shutdownLED_on();   // Flash shutdownLED to let user know we're turning off
        eventQueue.post_in(shutdownLED_off, 1000);
    } else {

        beaconIsOn = 1;
        eddyServicePtr->startEddystoneConfigAdvertisements();
        configLED_on();
        handle = eventQueue.post_in(
            timeoutToStartEddystoneBeaconAdvertisements,
            CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
        );
    }
    eventQueue.post_in(freeButtonBusy, 750 /* ms */);
}

/**
 * Raw IRQ handler for the reset button. We don't want to actually do any work here.
 * Instead, we queue work to happen later using an event queue, by posting a callback.
 * This has the added avantage of serialising actions, so if the button press happens
 * during the config->beacon mode transition timeout, the button_task won't happen
 * until the previous task has finished.
 *
 * If your buttons aren't debounced, you should do this in software, or button_task
 * might get queued multiple times.
 */
static void reset_rise(void)
{
    if (!buttonBusy) {
        buttonBusy = true;
        eventQueue.post(button_task);
    }
}

static void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext)
{
    /* Initialization error handling goes here... */
    (void) initContext;
}

static void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
{
    BLE         &ble  = initContext->ble;
    ble_error_t error = initContext->error;

    if (error != BLE_ERROR_NONE) {
        onBleInitError(initContext);
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);

    ble.gap().onConnection(connectionCallback);

    EddystoneService::EddystoneParams_t params;

    // Determine if booting directly after re-Flash or not
    if (loadEddystoneServiceConfigParams(&params)) {
        // 2+ Boot after reflash, so get parms from Persistent Storage
        eddyServicePtr = new EddystoneService(ble, params, radioTxPowerLevels, eventQueue);
    } else {
        // 1st Boot after reflash, so reset everything to defaults
        /* NOTE: slots are initialized in the constructor from the config.json file */
        eddyServicePtr = new EddystoneService(ble, advTxPowerLevels, radioTxPowerLevels, eventQueue);
    }

    // Save Default params in persistent storage ready for next boot event
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);

    // Start the Eddystone Config service - This will never stop (only connectability will change)
    eddyServicePtr->startEddystoneConfigService();

    /* Start Eddystone config Advertizements (to initialize everything properly) */
    configLED_on();
    eddyServicePtr->startEddystoneConfigAdvertisements();
    handle = eventQueue.post_in(
        timeoutToStartEddystoneBeaconAdvertisements,
        CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
    );

   // now shut everything off (used for final beacon that ships w/ battery)
   eventQueue.post_in(button_task, 2000 /* ms */);
}

void app_start(int, char *[])
{
    /* Tell standard C library to not allocate large buffers for these streams */
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    setbuf(stdin, NULL);

    beaconIsOn = 1;             // Booting up, initialize for button handler
    buttonBusy = false;         // software debouncing of the reset button
    button.rise(&reset_rise);   // setup reset button

    BLE &ble = BLE::Instance();
    ble.init(bleInitComplete);
}

#if !defined(YOTTA_CFG_MBED_OS)

int main() {

    app_start(0, NULL);

    while (true) {
       eventQueue.dispatch();
       BLE::Instance().waitForEvent();
    }

    return 0;
}

#endif
<commit_msg>Fix inclusion of mbed.h on mbed-classic.<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef YOTTA_CFG_MBED_OS  // use minar on mbed OS
#   include "mbed-drivers/mbed.h"
#else
#   include "mbed.h"
#endif

#include "ble/BLE.h"
#include "EddystoneService.h"

#include "PersistentStorageHelper/ConfigParamsPersistence.h"
// #include "stdio.h"

// Instantiation of the main event loop for this program

#ifdef YOTTA_CFG_MBED_OS  // use minar on mbed OS
#include "EventQueue/EventQueueMinar.h"
typedef eq::EventQueueMinar event_queue_t;

#else      // otherwise use the event classic queue
#include "EventQueue/EventQueueClassic.h"
typedef eq::EventQueueClassic<
    /* event count */ 10
> event_queue_t;

#endif

static event_queue_t eventQueue;

EddystoneService *eddyServicePtr;

/* Duration after power-on that config service is available. */
static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = YOTTA_CFG_EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS;

/* Values for ADV packets related to firmware levels, calibrated based on measured values at 1m */
static const PowerLevels_t advTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS;
/* Values for radio power levels, provided by manufacturer. */
static const PowerLevels_t radioTxPowerLevels = YOTTA_CFG_EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS;

// This allows a quick switch between targets without changing the 'platform'
// settings in config.json each time. If you do change target to nrf51dk-gcc,
// note you will still need to change 'softdevice' to 's130'
//
 #define QUICK_SWITCH_TO_NRF51DK 1
#ifdef QUICK_SWITCH_TO_NRF51DK
    #define LED_OFF 1
    #define CONFIG_LED LED3
    #define SHUTDOWN_LED LED1
    #define RESET_BUTTON BUTTON1
#else
    #define LED_OFF YOTTA_CFG_PLATFORM_LED_OFF
    #define CONFIG_LED YOTTA_CFG_PLATFORM_CONFIG_LED
    #define SHUTDOWN_LED YOTTA_CFG_PLATFORM_SHUTDOWN_LED
    #define RESET_BUTTON YOTTA_CFG_PLATFORM_RESET_BUTTON
#endif

DigitalOut configLED(CONFIG_LED, LED_OFF);
DigitalOut shutdownLED(SHUTDOWN_LED, LED_OFF);
InterruptIn button(RESET_BUTTON);

static int buttonBusy;                                    // semaphore to make prevent switch bounce problems

static const int BLINKY_MSEC = 500;                       // How long to cycle config LED on/off
static int beaconIsOn = 1;                                // Button handler boolean to switch on or off
static event_queue_t::event_handle_t handle = 0;         // For the config mode timeout
static event_queue_t::event_handle_t BlinkyHandle = 0;   // For the blinking LED when in config mode

static void blinky(void)  { configLED = !configLED; }
static void shutdownLED_on(void) { shutdownLED = !LED_OFF; }
static void shutdownLED_off(void) { shutdownLED = LED_OFF; }
static void freeButtonBusy(void) { buttonBusy = false; }

static void configLED_on(void) {
    configLED = !LED_OFF;
    BlinkyHandle = eventQueue.post_every(blinky, BLINKY_MSEC);
}
static void configLED_off(void) {
    configLED = LED_OFF;
    if (BlinkyHandle) {
        eventQueue.cancel(BlinkyHandle);
        BlinkyHandle = NULL;
    }
}

/**
 * Callback triggered some time after application started to switch to beacon mode.
 */
static void timeoutToStartEddystoneBeaconAdvertisements(void)
{
    Gap::GapState_t state;
    state = BLE::Instance().gap().getState();
    if (!state.connected) { /* don't switch if we're in a connected state. */
        eddyServicePtr->startEddystoneBeaconAdvertisements();
        configLED_off();
    }
}

/**
 * Callback triggered for a connection event.
 */
static void connectionCallback(const Gap::ConnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    // Stop advertising whatever the current mode
    eddyServicePtr->stopEddystoneBeaconAdvertisements();
}

/**
 * Callback triggered for a disconnection event.
 */
static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams)
{
    (void) cbParams;
    BLE::Instance().gap().startAdvertising();
    // Save params in persistent storage
    EddystoneService::EddystoneParams_t params;
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);
    // Ensure LED is off at the end of Config Mode or during a connection
    configLED_off();
    // 0.5 Second callback to rapidly re-establish Beaconing Service
    // (because it needs to be executed outside of disconnect callback)
    eventQueue.post_in(timeoutToStartEddystoneBeaconAdvertisements, 500 /* ms */);
}

// Callback used to handle button presses from thread mode (not IRQ)
static void button_task(void) {
    eventQueue.cancel(handle);   // kill any pending callback tasks

    if (beaconIsOn) {
        beaconIsOn = 0;
        eddyServicePtr->stopEddystoneBeaconAdvertisements();
        configLED_off();    // just in case it's still running...
        shutdownLED_on();   // Flash shutdownLED to let user know we're turning off
        eventQueue.post_in(shutdownLED_off, 1000);
    } else {

        beaconIsOn = 1;
        eddyServicePtr->startEddystoneConfigAdvertisements();
        configLED_on();
        handle = eventQueue.post_in(
            timeoutToStartEddystoneBeaconAdvertisements,
            CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
        );
    }
    eventQueue.post_in(freeButtonBusy, 750 /* ms */);
}

/**
 * Raw IRQ handler for the reset button. We don't want to actually do any work here.
 * Instead, we queue work to happen later using an event queue, by posting a callback.
 * This has the added avantage of serialising actions, so if the button press happens
 * during the config->beacon mode transition timeout, the button_task won't happen
 * until the previous task has finished.
 *
 * If your buttons aren't debounced, you should do this in software, or button_task
 * might get queued multiple times.
 */
static void reset_rise(void)
{
    if (!buttonBusy) {
        buttonBusy = true;
        eventQueue.post(button_task);
    }
}

static void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext)
{
    /* Initialization error handling goes here... */
    (void) initContext;
}

static void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
{
    BLE         &ble  = initContext->ble;
    ble_error_t error = initContext->error;

    if (error != BLE_ERROR_NONE) {
        onBleInitError(initContext);
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);

    ble.gap().onConnection(connectionCallback);

    EddystoneService::EddystoneParams_t params;

    // Determine if booting directly after re-Flash or not
    if (loadEddystoneServiceConfigParams(&params)) {
        // 2+ Boot after reflash, so get parms from Persistent Storage
        eddyServicePtr = new EddystoneService(ble, params, radioTxPowerLevels, eventQueue);
    } else {
        // 1st Boot after reflash, so reset everything to defaults
        /* NOTE: slots are initialized in the constructor from the config.json file */
        eddyServicePtr = new EddystoneService(ble, advTxPowerLevels, radioTxPowerLevels, eventQueue);
    }

    // Save Default params in persistent storage ready for next boot event
    eddyServicePtr->getEddystoneParams(params);
    saveEddystoneServiceConfigParams(&params);

    // Start the Eddystone Config service - This will never stop (only connectability will change)
    eddyServicePtr->startEddystoneConfigService();

    /* Start Eddystone config Advertizements (to initialize everything properly) */
    configLED_on();
    eddyServicePtr->startEddystoneConfigAdvertisements();
    handle = eventQueue.post_in(
        timeoutToStartEddystoneBeaconAdvertisements,
        CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
    );

   // now shut everything off (used for final beacon that ships w/ battery)
   eventQueue.post_in(button_task, 2000 /* ms */);
}

void app_start(int, char *[])
{
    /* Tell standard C library to not allocate large buffers for these streams */
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    setbuf(stdin, NULL);

    beaconIsOn = 1;             // Booting up, initialize for button handler
    buttonBusy = false;         // software debouncing of the reset button
    button.rise(&reset_rise);   // setup reset button

    BLE &ble = BLE::Instance();
    ble.init(bleInitComplete);
}

#if !defined(YOTTA_CFG_MBED_OS)

int main() {

    app_start(0, NULL);

    while (true) {
       eventQueue.dispatch();
       BLE::Instance().waitForEvent();
    }

    return 0;
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2010,
 *
 * Francois Keith
 * Olivier Stasse
 *
 * JRL/LAAS, CNRS/AIST
 *
 * This file is part of dynamicsJRLJapan.
 * dynamicsJRLJapan 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 3 of the License, or
 * (at your option) any later version.
 *
 * dynamicsJRLJapan 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 General Lesser Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License
 * along with dynamicsJRLJapan.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Research carried out within the scope of the Associated
 *  International Laboratory: Joint Japanese-French Robotics
 *  Laboratory (JRL)
 *
 */
#include "Debug.h"

#include "JointPrivate.h"
#include "JointFreeFlyerPrivate.h"
#include "DynamicBodyPrivate.h"

using namespace dynamicsJRLJapan;

JointFreeflyerPrivate::JointFreeflyerPrivate()
  :JointPrivate()
{
  m_dof6D.resize(6,false);
  setnumberDof(6);
  CreateLimitsArray();
}

JointFreeflyerPrivate::JointFreeflyerPrivate(const JointFreeflyerPrivate &a)
  :JointPrivate(a)
{
  m_dof6D.resize(6,false);
  setnumberDof(6);
}

JointFreeflyerPrivate::JointFreeflyerPrivate(const MAL_S4x4_MATRIX_TYPE(double) &inInitialPosition)
{
  type(JointPrivate::FREE_JOINT);
  m_inGlobalFrame = true;
  m_globalPoseAtConstruction = inInitialPosition;

  ODEBUG2("freeflyer: inInitialPosition" << inInitialPosition);
  MAL_S3_VECTOR(laxis, double);

  MAL_S3_VECTOR_ACCESS(laxis,0) = 1.0;
  MAL_S3_VECTOR_ACCESS(laxis,1) = 0.0;
  MAL_S3_VECTOR_ACCESS(laxis,2) = 0.0;

  axis(laxis);
  m_dof6D.resize(6,false);
  setnumberDof(6);
}

JointFreeflyerPrivate::~JointFreeflyerPrivate()
{
}

bool JointFreeflyerPrivate::updateTransformation(const vectorN & inDofVector)
{

  for (unsigned int i=0; i<6; i++)
    m_dof6D(i) = inDofVector(rankInConfiguration() + i);

  UpdatePoseFrom6DOFsVector(m_dof6D);
  return true;
}

bool JointFreeflyerPrivate::updateVelocity(const vectorN &,
					   const vectorN & inRobotSpeedVector)
{
  DynamicBodyPrivate* currentBody = (DynamicBodyPrivate*)(linkedBody());

  for(unsigned int i=0;i<3;i++)
    {
      currentBody->v0[i] = inRobotSpeedVector(rankInConfiguration()+i);

      currentBody->w[i] =
	currentBody->lw[i] = inRobotSpeedVector(rankInConfiguration()+i+3);

    }
  return true;
}

bool JointFreeflyerPrivate::updateAcceleration(const vectorN & ,
					       const vectorN & ,
					       const vectorN & inRobotAccelerationVector)
{
  DynamicBodyPrivate* currentBody = (DynamicBodyPrivate*)(linkedBody());

  for(unsigned int i=0;i<3;i++)
    {
      currentBody->dv[i] =
	currentBody->ldv[i] = inRobotAccelerationVector(rankInConfiguration()+i);
      currentBody->dw[i] =
	currentBody->ldw[i] = inRobotAccelerationVector(rankInConfiguration()+i+3);
    }
  return true;
}

const matrixNxP & JointFreeflyerPrivate::pcalc(const vectorN & )
{
  MAL_S3_VECTOR(qlin,double);
  MAL_S3_VECTOR_FILL(qlin,0);
  MAL_MATRIX_RESIZE(m_phi,6,6);
  MAL_MATRIX_FILL(m_phi,0);

  DynamicBodyPrivate* CurrentBody = (DynamicBodyPrivate*)(linkedBody());
  MAL_S3x3_MATRIX_TYPE(double) currentBodyRt;
  currentBodyRt = MAL_S3x3_RET_TRANSPOSE(CurrentBody->R);
  for (unsigned int i=0;i<3;i++)
    {
      for (unsigned int j=0;j<3;j++)
	{
	  m_phi(i,j) = currentBodyRt(i,j);
	  m_phi(i+3,j+3) = currentBodyRt(i,j);
	}
    }

  return m_phi;
}

const matrixNxP & JointFreeflyerPrivate::pdcalc(const vectorN & )
{
  for(unsigned int i=0;i<6;i++)
    {
      MAL_MATRIX_RESIZE(m_dotphi,6,6);
      MAL_MATRIX_FILL(m_dotphi,0);
    }
  return m_dotphi;
}

<commit_msg>Remove useless code.<commit_after>/*
 * Copyright 2010,
 *
 * Francois Keith
 * Olivier Stasse
 *
 * JRL/LAAS, CNRS/AIST
 *
 * This file is part of dynamicsJRLJapan.
 * dynamicsJRLJapan 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 3 of the License, or
 * (at your option) any later version.
 *
 * dynamicsJRLJapan 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 General Lesser Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License
 * along with dynamicsJRLJapan.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Research carried out within the scope of the Associated
 *  International Laboratory: Joint Japanese-French Robotics
 *  Laboratory (JRL)
 *
 */
#include "Debug.h"

#include "JointPrivate.h"
#include "JointFreeFlyerPrivate.h"
#include "DynamicBodyPrivate.h"

using namespace dynamicsJRLJapan;

JointFreeflyerPrivate::JointFreeflyerPrivate()
  :JointPrivate()
{
  m_dof6D.resize(6,false);
  setnumberDof(6);
  CreateLimitsArray();
}

JointFreeflyerPrivate::JointFreeflyerPrivate(const JointFreeflyerPrivate &a)
  :JointPrivate(a)
{
  m_dof6D.resize(6,false);
  setnumberDof(6);
}

JointFreeflyerPrivate::JointFreeflyerPrivate(const MAL_S4x4_MATRIX_TYPE(double) &inInitialPosition)
{
  type(JointPrivate::FREE_JOINT);
  m_inGlobalFrame = true;
  m_globalPoseAtConstruction = inInitialPosition;

  ODEBUG2("freeflyer: inInitialPosition" << inInitialPosition);
  MAL_S3_VECTOR(laxis, double);

  MAL_S3_VECTOR_ACCESS(laxis,0) = 1.0;
  MAL_S3_VECTOR_ACCESS(laxis,1) = 0.0;
  MAL_S3_VECTOR_ACCESS(laxis,2) = 0.0;

  axis(laxis);
  m_dof6D.resize(6,false);
  setnumberDof(6);
}

JointFreeflyerPrivate::~JointFreeflyerPrivate()
{
}

bool JointFreeflyerPrivate::updateTransformation(const vectorN & inDofVector)
{

  for (unsigned int i=0; i<6; i++)
    m_dof6D(i) = inDofVector(rankInConfiguration() + i);

  UpdatePoseFrom6DOFsVector(m_dof6D);
  return true;
}

bool JointFreeflyerPrivate::updateVelocity(const vectorN &,
					   const vectorN & inRobotSpeedVector)
{
  DynamicBodyPrivate* currentBody = (DynamicBodyPrivate*)(linkedBody());

  for(unsigned int i=0;i<3;i++)
    {
      currentBody->v0[i] = inRobotSpeedVector(rankInConfiguration()+i);

      currentBody->w[i] =
	currentBody->lw[i] = inRobotSpeedVector(rankInConfiguration()+i+3);

    }
  return true;
}

bool JointFreeflyerPrivate::updateAcceleration(const vectorN & ,
					       const vectorN & ,
					       const vectorN & inRobotAccelerationVector)
{
  DynamicBodyPrivate* currentBody = (DynamicBodyPrivate*)(linkedBody());

  for(unsigned int i=0;i<3;i++)
    {
      currentBody->dv[i] =
	currentBody->ldv[i] = inRobotAccelerationVector(rankInConfiguration()+i);
      currentBody->dw[i] =
	currentBody->ldw[i] = inRobotAccelerationVector(rankInConfiguration()+i+3);
    }
  return true;
}

const matrixNxP & JointFreeflyerPrivate::pcalc(const vectorN & )
{
  MAL_S3_VECTOR(qlin,double);
  MAL_S3_VECTOR_FILL(qlin,0);
  MAL_MATRIX_RESIZE(m_phi,6,6);
  MAL_MATRIX_FILL(m_phi,0);

  DynamicBodyPrivate* CurrentBody = (DynamicBodyPrivate*)(linkedBody());
  MAL_S3x3_MATRIX_TYPE(double) currentBodyRt;
  currentBodyRt = MAL_S3x3_RET_TRANSPOSE(CurrentBody->R);
  for (unsigned int i=0;i<3;i++)
    {
      for (unsigned int j=0;j<3;j++)
	{
	  m_phi(i,j) = currentBodyRt(i,j);
	  m_phi(i+3,j+3) = currentBodyRt(i,j);
	}
    }

  return m_phi;
}

const matrixNxP & JointFreeflyerPrivate::pdcalc(const vectorN & )
{

  MAL_MATRIX_RESIZE(m_dotphi,6,6);
  MAL_MATRIX_FILL(m_dotphi,0);
  return m_dotphi;
}

<|endoftext|>


<commit_before>#include <fstream>
#include <mutex>
#include <thread>

#include "device_regs.h"
#include "simulator.h"
#include "utils.h"

using namespace lc3::core;

namespace lc3
{
namespace core
{
    std::mutex g_io_lock;
};
};

Simulator::Simulator(lc3::sim & simulator, lc3::utils::IPrinter & printer, lc3::utils::IInputter & inputter,
    uint32_t log_level) : state(simulator, logger), logger(printer, log_level), inputter(inputter),
    collecting_input(false)
{
    state.mem.resize(1 << 16);
    reset();

    state.pre_instruction_callback_v = false;
    state.post_instruction_callback_v = false;
    state.interrupt_enter_callback_v = false;
    state.interrupt_exit_callback_v = false;
}

void Simulator::loadObjectFile(std::string const & filename)
{
    std::ifstream file(filename);
    if(! file) {
        logger.printf(lc3::utils::PrintType::P_ERROR, true, "could not open file \'%s\' for reading",
            filename.c_str());
        throw utils::exception("could not open file");
    }

    uint32_t fill_pc = 0;
    uint32_t offset = 0;
    bool first_orig_set = false;
    while(! file.eof()) {
        MemEntry statement;
        file >> statement;

        if(file.eof()) {
            break;
        }

        if(statement.isOrig()) {
            if(! first_orig_set) {
                state.pc = statement.getValue();
                first_orig_set = true;
            }
            fill_pc = statement.getValue();
            offset = 0;
        } else {
            logger.printf(lc3::utils::PrintType::P_DEBUG, true, "0x%0.4x: %s (0x%0.4x)", fill_pc + offset,
                statement.getLine().c_str(), statement.getValue());
            state.mem[fill_pc + offset] = statement;
            offset += 1;
        }

    }
    uint16_t value = state.mem[MCR].getValue();
    state.mem[MCR].setValue(value | 0x8000);
}

void Simulator::loadOS(std::string const & os_path)
{
    loadObjectFile(os_path);
    state.pc = RESET_PC;
}

void Simulator::simulate(void)
{
    std::thread input_thread;
    utils::exception exception;
    bool exception_valid = false;

    try {
        state.running = true;
        collecting_input = true;
        inputter.beginInput();

        input_thread = std::thread(&core::Simulator::handleInput, this);
        while(state.running && (state.mem[MCR].getValue() & 0x8000) != 0) {
            if(! state.hit_breakpoint) {
                executeEvent(std::make_shared<CallbackEvent>(state.pre_instruction_callback_v,
                    state.pre_instruction_callback));
                if(state.hit_breakpoint) {
                    break;
                }
            }
            state.hit_breakpoint = false;

            std::vector<PIEvent> events = executeInstruction();
            events.push_back(std::make_shared<CallbackEvent>(state.post_instruction_callback_v,
                state.post_instruction_callback));
            executeEventChain(events);
            updateDevices();
            events = checkAndSetupInterrupts();
            executeEventChain(events);
        }
    } catch(utils::exception & e) {
        exception = e;
        exception_valid = true;
    } catch(std::exception & e) { }

    state.running = false;
    collecting_input = false;
    if(input_thread.joinable()) {
        input_thread.join();
    }
    inputter.endInput();

    if(exception_valid) {
        throw exception;
    }
}

void Simulator::pause(void)
{
    state.running = false;
}

std::vector<PIEvent> Simulator::executeInstruction(void)
{
    if((state.pc <= SYSTEM_END || state.pc >= MMIO_START) && (state.mem[PSR].getValue() & 0x8000) == 0x8000) {
        logger.printf(lc3::utils::PrintType::P_EXTRA, true, "illegal PC 0x%0.4x accessed", state.pc);
        return IInstruction::buildSysCallEnterHelper(state, INTEX_TABLE_START + 0x0, MachineState::SysCallType::INT);
    }
    uint32_t encoded_inst = state.mem[state.pc].getValue();

    bool valid;
    PIInstruction candidate = decoder.findInstructionByEncoding(encoded_inst, valid);
    if(! valid) {
        logger.printf(lc3::utils::PrintType::P_EXTRA, true, "illegal opcode");
        return IInstruction::buildSysCallEnterHelper(state, INTEX_TABLE_START + 0x1, MachineState::SysCallType::INT);
    }

    candidate->assignOperands(encoded_inst);
    logger.printf(lc3::utils::PrintType::P_EXTRA, true, "executing PC 0x%0.4x: %s (0x%0.4x)", state.pc,
        state.mem[state.pc].getLine().c_str(), encoded_inst);
    state.pc = (state.pc + 1) & 0xffff;
    std::vector<PIEvent> events = candidate->execute(state);

    return events;
}

void Simulator::updateDevices(void)
{
    uint16_t value = state.mem[DSR].getValue();
    state.mem[DSR].setValue(value | 0x8000);
}

std::vector<PIEvent> Simulator::checkAndSetupInterrupts(void)
{
    uint32_t value = state.mem[KBSR].getValue();

    if((value & 0xc000) == 0xc000) {
        logger.printf(lc3::utils::PrintType::P_EXTRA, true, "jumping to keyboard ISR");

        std::vector<PIEvent> ret = IInstruction::buildSysCallEnterHelper(state, INTEX_TABLE_START + 0x80,
            MachineState::SysCallType::INT, [](uint32_t psr_value) { return (psr_value & 0x78ff) | 0x0400; });
        ret.push_back(std::make_shared<MemWriteEvent>(KBSR, state.mem[KBSR].getValue() & 0x7fff));
    }

    return {};
}

void Simulator::executeEventChain(std::vector<PIEvent> & events)
{
    for(PIEvent event : events) {
        executeEvent(event);
    }

    events.clear();
}

void Simulator::executeEvent(PIEvent event)
{
    if(event->getOutputString(state) != "") {
        logger.printf(lc3::utils::PrintType::P_EXTRA, false, "  %s", event->getOutputString(state).c_str());
    }
    event->updateState(state);
}

void Simulator::reset(void)
{
    for(uint32_t i = 0; i < 8; i += 1) {
        state.regs[i] = 0;
    }

    state.pc = RESET_PC;
    state.backup_sp = 0x3000;

    for(uint32_t i = 0; i < (1 << 16); i += 1) {
        state.mem[i].setValue(0);
    }

    state.mem[PSR].setValue(0x8002);
    state.mem[MCR].setValue(0x8000);  // indicate the machine is running
    state.running = true;
    state.hit_breakpoint = false;
}

void Simulator::registerPreInstructionCallback(callback_func_t func)
{
    state.pre_instruction_callback_v = true;
    state.pre_instruction_callback = func;
}

void Simulator::registerPostInstructionCallback(callback_func_t func)
{
    state.post_instruction_callback_v = true;
    state.post_instruction_callback = func;
}

void Simulator::registerInterruptEnterCallback(callback_func_t func)
{
    state.interrupt_enter_callback_v = true;
    state.interrupt_enter_callback = func;
}

void Simulator::registerInterruptExitCallback(callback_func_t func)
{
    state.interrupt_exit_callback_v = true;
    state.interrupt_exit_callback = func;
}

void Simulator::registerSubEnterCallback(callback_func_t func)
{
    state.sub_enter_callback_v = true;
    state.sub_enter_callback = func;
}

void Simulator::registerSubExitCallback(callback_func_t func)
{
    state.sub_exit_callback_v = true;
    state.sub_exit_callback = func;
}

void Simulator::handleInput(void)
{
    while(collecting_input) {
        char c;
        if(inputter.getChar(c)) {
            std::lock_guard<std::mutex> guard(g_io_lock);
            state.mem[KBSR].setValue(state.mem[KBSR].getValue() | 0x8000);
            state.mem[KBDR].setValue(((uint32_t) c) & 0xFF);
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
<commit_msg>[sim] Fix typo in detecting interrupts<commit_after>#include <fstream>
#include <mutex>
#include <thread>

#include "device_regs.h"
#include "simulator.h"
#include "utils.h"

using namespace lc3::core;

namespace lc3
{
namespace core
{
    std::mutex g_io_lock;
};
};

Simulator::Simulator(lc3::sim & simulator, lc3::utils::IPrinter & printer, lc3::utils::IInputter & inputter,
    uint32_t log_level) : state(simulator, logger), logger(printer, log_level), inputter(inputter),
    collecting_input(false)
{
    state.mem.resize(1 << 16);
    reset();

    state.pre_instruction_callback_v = false;
    state.post_instruction_callback_v = false;
    state.interrupt_enter_callback_v = false;
    state.interrupt_exit_callback_v = false;
}

void Simulator::loadObjectFile(std::string const & filename)
{
    std::ifstream file(filename);
    if(! file) {
        logger.printf(lc3::utils::PrintType::P_ERROR, true, "could not open file \'%s\' for reading",
            filename.c_str());
        throw utils::exception("could not open file");
    }

    uint32_t fill_pc = 0;
    uint32_t offset = 0;
    bool first_orig_set = false;
    while(! file.eof()) {
        MemEntry statement;
        file >> statement;

        if(file.eof()) {
            break;
        }

        if(statement.isOrig()) {
            if(! first_orig_set) {
                state.pc = statement.getValue();
                first_orig_set = true;
            }
            fill_pc = statement.getValue();
            offset = 0;
        } else {
            logger.printf(lc3::utils::PrintType::P_DEBUG, true, "0x%0.4x: %s (0x%0.4x)", fill_pc + offset,
                statement.getLine().c_str(), statement.getValue());
            state.mem[fill_pc + offset] = statement;
            offset += 1;
        }

    }
    uint16_t value = state.mem[MCR].getValue();
    state.mem[MCR].setValue(value | 0x8000);
}

void Simulator::loadOS(std::string const & os_path)
{
    loadObjectFile(os_path);
    state.pc = RESET_PC;
}

void Simulator::simulate(void)
{
    std::thread input_thread;
    utils::exception exception;
    bool exception_valid = false;

    try {
        state.running = true;
        collecting_input = true;
        inputter.beginInput();

        input_thread = std::thread(&core::Simulator::handleInput, this);
        while(state.running && (state.mem[MCR].getValue() & 0x8000) != 0) {
            if(! state.hit_breakpoint) {
                executeEvent(std::make_shared<CallbackEvent>(state.pre_instruction_callback_v,
                    state.pre_instruction_callback));
                if(state.hit_breakpoint) {
                    break;
                }
            }
            state.hit_breakpoint = false;

            std::vector<PIEvent> events = executeInstruction();
            events.push_back(std::make_shared<CallbackEvent>(state.post_instruction_callback_v,
                state.post_instruction_callback));
            executeEventChain(events);
            updateDevices();
            events = checkAndSetupInterrupts();
            executeEventChain(events);
        }
    } catch(utils::exception & e) {
        exception = e;
        exception_valid = true;
    } catch(std::exception & e) { }

    state.running = false;
    collecting_input = false;
    if(input_thread.joinable()) {
        input_thread.join();
    }
    inputter.endInput();

    if(exception_valid) {
        throw exception;
    }
}

void Simulator::pause(void)
{
    state.running = false;
}

std::vector<PIEvent> Simulator::executeInstruction(void)
{
    if((state.pc <= SYSTEM_END || state.pc >= MMIO_START) && (state.mem[PSR].getValue() & 0x8000) == 0x8000) {
        logger.printf(lc3::utils::PrintType::P_EXTRA, true, "illegal PC 0x%0.4x accessed", state.pc);
        return IInstruction::buildSysCallEnterHelper(state, INTEX_TABLE_START + 0x0, MachineState::SysCallType::INT);
    }
    uint32_t encoded_inst = state.mem[state.pc].getValue();

    bool valid;
    PIInstruction candidate = decoder.findInstructionByEncoding(encoded_inst, valid);
    if(! valid) {
        logger.printf(lc3::utils::PrintType::P_EXTRA, true, "illegal opcode");
        return IInstruction::buildSysCallEnterHelper(state, INTEX_TABLE_START + 0x1, MachineState::SysCallType::INT);
    }

    candidate->assignOperands(encoded_inst);
    logger.printf(lc3::utils::PrintType::P_EXTRA, true, "executing PC 0x%0.4x: %s (0x%0.4x)", state.pc,
        state.mem[state.pc].getLine().c_str(), encoded_inst);
    state.pc = (state.pc + 1) & 0xffff;
    std::vector<PIEvent> events = candidate->execute(state);

    return events;
}

void Simulator::updateDevices(void)
{
    uint16_t value = state.mem[DSR].getValue();
    state.mem[DSR].setValue(value | 0x8000);
}

std::vector<PIEvent> Simulator::checkAndSetupInterrupts(void)
{
    uint32_t value = state.mem[KBSR].getValue();

    if((value & 0xc000) == 0xc000) {
        logger.printf(lc3::utils::PrintType::P_EXTRA, true, "jumping to keyboard ISR");

        std::vector<PIEvent> ret = IInstruction::buildSysCallEnterHelper(state, INTEX_TABLE_START + 0x80,
            MachineState::SysCallType::INT, [](uint32_t psr_value) { return (psr_value & 0x78ff) | 0x0400; });
        ret.push_back(std::make_shared<MemWriteEvent>(KBSR, state.mem[KBSR].getValue() & 0x7fff));
        return ret;
    }

    return {};
}

void Simulator::executeEventChain(std::vector<PIEvent> & events)
{
    for(PIEvent event : events) {
        executeEvent(event);
    }

    events.clear();
}

void Simulator::executeEvent(PIEvent event)
{
    if(event->getOutputString(state) != "") {
        logger.printf(lc3::utils::PrintType::P_EXTRA, false, "  %s", event->getOutputString(state).c_str());
    }
    event->updateState(state);
}

void Simulator::reset(void)
{
    for(uint32_t i = 0; i < 8; i += 1) {
        state.regs[i] = 0;
    }

    state.pc = RESET_PC;
    state.backup_sp = 0x3000;

    for(uint32_t i = 0; i < (1 << 16); i += 1) {
        state.mem[i].setValue(0);
    }

    state.mem[PSR].setValue(0x8002);
    state.mem[MCR].setValue(0x8000);  // indicate the machine is running
    state.running = true;
    state.hit_breakpoint = false;
}

void Simulator::registerPreInstructionCallback(callback_func_t func)
{
    state.pre_instruction_callback_v = true;
    state.pre_instruction_callback = func;
}

void Simulator::registerPostInstructionCallback(callback_func_t func)
{
    state.post_instruction_callback_v = true;
    state.post_instruction_callback = func;
}

void Simulator::registerInterruptEnterCallback(callback_func_t func)
{
    state.interrupt_enter_callback_v = true;
    state.interrupt_enter_callback = func;
}

void Simulator::registerInterruptExitCallback(callback_func_t func)
{
    state.interrupt_exit_callback_v = true;
    state.interrupt_exit_callback = func;
}

void Simulator::registerSubEnterCallback(callback_func_t func)
{
    state.sub_enter_callback_v = true;
    state.sub_enter_callback = func;
}

void Simulator::registerSubExitCallback(callback_func_t func)
{
    state.sub_exit_callback_v = true;
    state.sub_exit_callback = func;
}

void Simulator::handleInput(void)
{
    while(collecting_input) {
        char c;
        if(inputter.getChar(c)) {
            std::lock_guard<std::mutex> guard(g_io_lock);
            state.mem[KBSR].setValue(state.mem[KBSR].getValue() | 0x8000);
            state.mem[KBDR].setValue(((uint32_t) c) & 0xFF);
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2019-2021 Intel Corporation

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

//! \file test_arena_constraints.cpp
//! \brief Test for [info_namespace scheduler.task_arena] specifications

#include "common/common_arena_constraints.h"

#include "tbb/parallel_for.h"

#if __TBB_HWLOC_VALID_ENVIRONMENT
#if __HYBRID_CPUS_TESTING
//! Testing NUMA topology traversal correctness
//! \brief \ref interface \ref requirement
TEST_CASE("Test core types topology traversal correctness") {
    system_info::initialize();
    std::vector<index_info> core_types_info = system_info::get_cpu_kinds_info();
    std::vector<tbb::core_type_id> core_types = tbb::info::core_types();

    REQUIRE_MESSAGE(core_types_info.size() == core_types.size(), "Wrong core types number detected.");
    for (unsigned i = 0; i < core_types.size(); ++i) {
        REQUIRE_MESSAGE(core_types[i] == core_types_info[i].index, "Wrong core type index detected.");
    }
}
#endif /*__HYBRID_CPUS_TESTING*/

//! Test affinity and default_concurrency correctness for all available constraints.
//! \brief \ref error_guessing
TEST_CASE("Test affinity and default_concurrency correctness for all available constraints.") {
    system_info::initialize();
    for (const auto& constraints: generate_constraints_variety()) {
        tbb::task_arena ta{constraints};
        test_constraints_affinity_and_concurrency(constraints, get_arena_affinity(ta));
    }
}

bool is_observer_created(const tbb::task_arena::constraints& c) {
    std::vector<tbb::core_type_id> core_types = tbb::info::core_types();
    std::vector<tbb::numa_node_id> numa_nodes = tbb::info::numa_nodes();
    return
        (c.numa_id != tbb::task_arena::automatic && numa_nodes.size() > 1) ||
        (c.core_type != tbb::task_arena::automatic && core_types.size() > 1) ||
        c.max_threads_per_core != tbb::task_arena::automatic;
}

void recursive_arena_binding(constraints_container::iterator current_pos, constraints_container::iterator end_pos) {
    system_info::affinity_mask affinity_before = system_info::allocate_current_affinity_mask();

    if (current_pos != end_pos) {
        auto constraints = *current_pos;
        tbb::task_arena current_level_arena{constraints};

        if (is_observer_created(constraints)) {
            system_info::affinity_mask affinity = get_arena_affinity(current_level_arena);
            test_constraints_affinity_and_concurrency(constraints, affinity);
        }

        current_level_arena.execute(
            [&current_pos, &end_pos]() {
                recursive_arena_binding(++current_pos, end_pos);
            }
        );
    }

    system_info::affinity_mask affinity_after = system_info::allocate_current_affinity_mask();
    REQUIRE_MESSAGE(hwloc_bitmap_isequal(affinity_before, affinity_after),
        "After nested arena execution previous affinity mask was not restored.");
}

//! Testing binding correctness during passing through nested arenas
//! \brief \ref interface \ref error_guessing
TEST_CASE("Test binding with nested arenas") {
    system_info::initialize();
    auto constraints_variety = generate_constraints_variety();
    recursive_arena_binding(constraints_variety.begin(), constraints_variety.end());
}

//! Testing constraints propagation during arenas copy construction
//! \brief \ref regression
TEST_CASE("Test constraints propagation during arenas copy construction") {
    system_info::initialize();
    for (const auto& constraints: generate_constraints_variety()) {
        tbb::task_arena constructed{constraints};

        tbb::task_arena copied(constructed);
        system_info::affinity_mask copied_affinity = get_arena_affinity(copied);

        test_constraints_affinity_and_concurrency(constraints, copied_affinity);
    }
}
#endif /*__TBB_HWLOC_VALID_ENVIRONMENT*/

//! Testing memory leaks absence
//! \brief \ref resource_usage
TEST_CASE("Test memory leaks") {
    constexpr size_t num_trials = 1000;

    // To reduce the test session time only one constraints object is used inside this test.
    // This constraints should use all available settings to cover the most part of tbbbind functionality.
    auto constraints = tbb::task_arena::constraints{}
        .set_numa_id(tbb::info::numa_nodes().front())
        .set_core_type(tbb::info::core_types().front())
        .set_max_threads_per_core(1);

    size_t current_memory_usage = 0, previous_memory_usage = 0, stability_counter = 0;
    bool no_memory_leak = false;
    for (size_t i = 0; i < num_trials; i++) {
        { /* All DTORs must be called before GetMemoryUsage() call*/
            tbb::task_arena arena{constraints};
            arena.execute([]{
                utils::SpinBarrier barrier;
                barrier.initialize(tbb::this_task_arena::max_concurrency());
                tbb::parallel_for(
                    tbb::blocked_range<size_t>(0, tbb::this_task_arena::max_concurrency()),
                    [&barrier](const tbb::blocked_range<size_t>&) {
                        barrier.wait();
                    }
                );
            });
        }

        current_memory_usage = utils::GetMemoryUsage();
        stability_counter = current_memory_usage==previous_memory_usage ? stability_counter + 1 : 0;
        // If the amount of used memory has not changed during 5% of executions,
        // then we can assume that the check was successful
        if (stability_counter > num_trials / 20) {
            no_memory_leak = true;
            break;
        }
        previous_memory_usage = current_memory_usage;
    }
    REQUIRE_MESSAGE(no_memory_leak, "Seems we get memory leak here.");
}

//! Testing arena constraints setters
//! \brief \ref interface \ref requirement
TEST_CASE("Test arena constraints setters") {
    using constraints = tbb::task_arena::constraints;
    auto constraints_comparison = [](const constraints& c1, const constraints& c2) {
        REQUIRE_MESSAGE(constraints_equal{}(c1, c2),
            "Equal constraints settings specified by different interfaces shows different result.");
    };

    // NUMA node ID setter testing
    for(const auto& numa_index: tbb::info::numa_nodes()) {
        constraints setter_c = constraints{}.set_numa_id(numa_index);
        constraints assignment_c{}; assignment_c.numa_id = numa_index;

        constraints_comparison(setter_c, assignment_c);
    }

    // Core type setter testing
    for(const auto& core_type_index: tbb::info::core_types()) {
        constraints setter_c = constraints{}.set_core_type(core_type_index);
        constraints assignment_c{}; assignment_c.core_type = core_type_index;

        constraints_comparison(setter_c, assignment_c);
    }

    // Max concurrency setter testing
    {
        constraints setter_c = constraints{}.set_max_concurrency(1);
        constraints assignment_c{}; assignment_c.max_concurrency = 1;

        constraints_comparison(setter_c, assignment_c);
    }

    // Threads per core setter testing
    {
        constraints setter_c = constraints{}.set_max_threads_per_core(1);
        constraints assignment_c{}; assignment_c.max_threads_per_core = 1;

        constraints_comparison(setter_c, assignment_c);
    }
}

const int custom_concurrency_value = 42;
void check_concurrency_level(const tbb::task_arena::constraints& c) {
    REQUIRE_MESSAGE(tbb::info::default_concurrency(c) == custom_concurrency_value,
        "Custom arena concurrency was passed to constraints, but was not respected by default_concurrency() call.");
    REQUIRE_MESSAGE(tbb::task_arena{c}.max_concurrency() == custom_concurrency_value,
        "Custom arena concurrency was passed to constraints, but was not respected by default_concurrency() call.");
}

//! Testing concurrency getters output for constraints with custom concurrency value
//! \brief \ref interface \ref error_guessing
TEST_CASE("Test concurrency getters output for constraints with custom concurrency value") {
    tbb::task_arena::constraints c{};
    c.set_max_concurrency(custom_concurrency_value);
    check_concurrency_level(c);

    c.set_numa_id(tbb::info::numa_nodes().front());
    check_concurrency_level(c);

    c.set_core_type(tbb::info::core_types().front());
    check_concurrency_level(c);

    c.set_max_threads_per_core(1);
    check_concurrency_level(c);
}
<commit_msg>Cover the constraints_threads_per_core() reserved interface by testing (#544)<commit_after>/*
    Copyright (c) 2019-2021 Intel Corporation

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

//! \file test_arena_constraints.cpp
//! \brief Test for [info_namespace scheduler.task_arena] specifications

#include "common/common_arena_constraints.h"

#include "tbb/parallel_for.h"

#if __TBB_HWLOC_VALID_ENVIRONMENT
#if __HYBRID_CPUS_TESTING
//! Testing NUMA topology traversal correctness
//! \brief \ref interface \ref requirement
TEST_CASE("Test core types topology traversal correctness") {
    system_info::initialize();
    std::vector<index_info> core_types_info = system_info::get_cpu_kinds_info();
    std::vector<tbb::core_type_id> core_types = tbb::info::core_types();

    REQUIRE_MESSAGE(core_types_info.size() == core_types.size(), "Wrong core types number detected.");
    for (unsigned i = 0; i < core_types.size(); ++i) {
        REQUIRE_MESSAGE(core_types[i] == core_types_info[i].index, "Wrong core type index detected.");
    }
}
#endif /*__HYBRID_CPUS_TESTING*/

//! Test affinity and default_concurrency correctness for all available constraints.
//! \brief \ref error_guessing
TEST_CASE("Test affinity and default_concurrency correctness for all available constraints.") {
    system_info::initialize();
    for (const auto& constraints: generate_constraints_variety()) {
        tbb::task_arena ta{constraints};
        test_constraints_affinity_and_concurrency(constraints, get_arena_affinity(ta));
    }
}

bool is_observer_created(const tbb::task_arena::constraints& c) {
    std::vector<tbb::core_type_id> core_types = tbb::info::core_types();
    std::vector<tbb::numa_node_id> numa_nodes = tbb::info::numa_nodes();
    return
        (c.numa_id != tbb::task_arena::automatic && numa_nodes.size() > 1) ||
        (c.core_type != tbb::task_arena::automatic && core_types.size() > 1) ||
        c.max_threads_per_core != tbb::task_arena::automatic;
}

void recursive_arena_binding(constraints_container::iterator current_pos, constraints_container::iterator end_pos) {
    system_info::affinity_mask affinity_before = system_info::allocate_current_affinity_mask();

    if (current_pos != end_pos) {
        auto constraints = *current_pos;
        tbb::task_arena current_level_arena{constraints};

        if (is_observer_created(constraints)) {
            system_info::affinity_mask affinity = get_arena_affinity(current_level_arena);
            test_constraints_affinity_and_concurrency(constraints, affinity);
        }

        current_level_arena.execute(
            [&current_pos, &end_pos]() {
                recursive_arena_binding(++current_pos, end_pos);
            }
        );
    }

    system_info::affinity_mask affinity_after = system_info::allocate_current_affinity_mask();
    REQUIRE_MESSAGE(hwloc_bitmap_isequal(affinity_before, affinity_after),
        "After nested arena execution previous affinity mask was not restored.");
}

//! Testing binding correctness during passing through nested arenas
//! \brief \ref interface \ref error_guessing
TEST_CASE("Test binding with nested arenas") {
    system_info::initialize();
    auto constraints_variety = generate_constraints_variety();
    recursive_arena_binding(constraints_variety.begin(), constraints_variety.end());
}

//! Testing constraints propagation during arenas copy construction
//! \brief \ref regression
TEST_CASE("Test constraints propagation during arenas copy construction") {
    system_info::initialize();
    for (const auto& constraints: generate_constraints_variety()) {
        tbb::task_arena constructed{constraints};

        tbb::task_arena copied(constructed);
        system_info::affinity_mask copied_affinity = get_arena_affinity(copied);

        test_constraints_affinity_and_concurrency(constraints, copied_affinity);
    }
}
#endif /*__TBB_HWLOC_VALID_ENVIRONMENT*/

//! Testing memory leaks absence
//! \brief \ref resource_usage
TEST_CASE("Test memory leaks") {
    constexpr size_t num_trials = 1000;

    // To reduce the test session time only one constraints object is used inside this test.
    // This constraints should use all available settings to cover the most part of tbbbind functionality.
    auto constraints = tbb::task_arena::constraints{}
        .set_numa_id(tbb::info::numa_nodes().front())
        .set_core_type(tbb::info::core_types().front())
        .set_max_threads_per_core(1);

    size_t current_memory_usage = 0, previous_memory_usage = 0, stability_counter = 0;
    bool no_memory_leak = false;
    for (size_t i = 0; i < num_trials; i++) {
        { /* All DTORs must be called before GetMemoryUsage() call*/
            tbb::task_arena arena{constraints};
            arena.execute([]{
                utils::SpinBarrier barrier;
                barrier.initialize(tbb::this_task_arena::max_concurrency());
                tbb::parallel_for(
                    tbb::blocked_range<size_t>(0, tbb::this_task_arena::max_concurrency()),
                    [&barrier](const tbb::blocked_range<size_t>&) {
                        barrier.wait();
                    }
                );
            });
        }

        current_memory_usage = utils::GetMemoryUsage();
        stability_counter = current_memory_usage==previous_memory_usage ? stability_counter + 1 : 0;
        // If the amount of used memory has not changed during 5% of executions,
        // then we can assume that the check was successful
        if (stability_counter > num_trials / 20) {
            no_memory_leak = true;
            break;
        }
        previous_memory_usage = current_memory_usage;
    }
    REQUIRE_MESSAGE(no_memory_leak, "Seems we get memory leak here.");
}

//! Testing arena constraints setters
//! \brief \ref interface \ref requirement
TEST_CASE("Test arena constraints setters") {
    using constraints = tbb::task_arena::constraints;
    auto constraints_comparison = [](const constraints& c1, const constraints& c2) {
        REQUIRE_MESSAGE(constraints_equal{}(c1, c2),
            "Equal constraints settings specified by different interfaces shows different result.");
    };

    // NUMA node ID setter testing
    for(const auto& numa_index: tbb::info::numa_nodes()) {
        constraints setter_c = constraints{}.set_numa_id(numa_index);
        constraints assignment_c{}; assignment_c.numa_id = numa_index;

        constraints_comparison(setter_c, assignment_c);
    }

    // Core type setter testing
    for(const auto& core_type_index: tbb::info::core_types()) {
        constraints setter_c = constraints{}.set_core_type(core_type_index);
        constraints assignment_c{}; assignment_c.core_type = core_type_index;

        constraints_comparison(setter_c, assignment_c);
    }

    // Max concurrency setter testing
    {
        constraints setter_c = constraints{}.set_max_concurrency(1);
        constraints assignment_c{}; assignment_c.max_concurrency = 1;

        constraints_comparison(setter_c, assignment_c);
    }

    // Threads per core setter testing
    {
        constraints setter_c = constraints{}.set_max_threads_per_core(1);
        constraints assignment_c{}; assignment_c.max_threads_per_core = 1;

        constraints_comparison(setter_c, assignment_c);
    }
}

const int custom_concurrency_value = 42;
void check_concurrency_level(const tbb::task_arena::constraints& c) {
    REQUIRE_MESSAGE(tbb::info::default_concurrency(c) == custom_concurrency_value,
        "Custom arena concurrency was passed to constraints, but was not respected by default_concurrency() call.");
    REQUIRE_MESSAGE(tbb::task_arena{c}.max_concurrency() == custom_concurrency_value,
        "Custom arena concurrency was passed to constraints, but was not respected by default_concurrency() call.");
}

//! Testing concurrency getters output for constraints with custom concurrency value
//! \brief \ref interface \ref error_guessing
TEST_CASE("Test concurrency getters output for constraints with custom concurrency value") {
    tbb::task_arena::constraints c{};
    c.set_max_concurrency(custom_concurrency_value);
    check_concurrency_level(c);

    c.set_numa_id(tbb::info::numa_nodes().front());
    check_concurrency_level(c);

    c.set_core_type(tbb::info::core_types().front());
    check_concurrency_level(c);

    c.set_max_threads_per_core(1);
    check_concurrency_level(c);
}

//! Testing constraints_threads_per_core() reserved entry point
//! \brief \ref error_guessing
TEST_CASE("Testing constraints_threads_per_core() reserved entry point") {
    tbb::task_arena::constraints c{};
    tbb::detail::r1::constraints_threads_per_core(c);
}
<|endoftext|>


<commit_before>//===-- shm.cpp -----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Save/restore via shared memory to survive exec*()
//
//===----------------------------------------------------------------------===//

#include "shm.h"

#include "ipcreg_internal.h"
#include "magic_socket_nums.h"
#include "real.h"
#include "rename_fd.h"

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define UC(ret, msg) \
  unixCheck(ret, msg, __FILE__, __LINE__, __PRETTY_FUNCTION__);

void unixCheck(int ret, const char *msg, const char *file, unsigned line,
               const char *func, int err = errno) {
  if (ret == -1) {
    ipclog("Unix call failed in %s at %s:%u: %s - %s\n", func, file, line, msg,
           strerror(err));
    abort();
  }
}

static char buf[100];
const char *getShmName() {
  sprintf(buf, "/ipcd.%d\n", getpid());
  return buf;
}

int get_shm(int flags, mode_t mode) {
  int fd = shm_open(getShmName(), flags, mode);
  if (fd == -1 && errno == EEXIST) {
    ipclog("Shared memory segment exists, attempting to remove it...\n");
    int ret = shm_unlink(getShmName());
    UC(ret, "Closing existing shm");

    // Okay, let's try this again
    fd = shm_open(getShmName(), flags, mode);
  }
  UC(fd, "shm_open");
  UC(fchmod(fd, mode), "fchmod on shared memory segment");
  return fd;
}

void shm_state_save() {
  // Create shared memory segment
  int fd = get_shm(O_RDWR | O_CREAT | O_EXCL, 0600);
  UC(fd, "get_shm");

  bool success = rename_fd(fd, MAGIC_SHM_FD, /* cloexec */ false);
  assert(success && "Failed to rename SHM fd!");

  // Do *not* close on exec! :)
  int flags = __real_fcntl(MAGIC_SHM_FD, F_GETFD, /* kludge */ 0);
  assert(flags >= 0);
  flags &= ~FD_CLOEXEC;
  int ret = __real_fcntl_int(MAGIC_SHM_FD, F_SETFD, flags);
  UC(ret, "fcntl CLOEXEC on shared memory segment");

  // Size the memory segment:
  ret = ftruncate(MAGIC_SHM_FD, sizeof(libipc_state));
  UC(ret, "ftruncate on shm");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                  MAP_SHARED, MAGIC_SHM_FD, 0);
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  *(libipc_state*)stateptr = state;

  // Unmap, but don't unlink the shared memory
  ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  ipclog("State saved!\n");
}

bool is_valid_fd(int fd) {
  return __real_fcntl(fd, F_GETFD, /* kludge */ 0) >= 0;
}

void shm_state_restore() {
  // If we have memory to restore, it'll be in our magic FD!
  if (!is_valid_fd(MAGIC_SHM_FD))
    return;

  ipclog("Inherited ipc state FD, starting state restoration...\n");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                        MAP_SHARED, MAGIC_SHM_FD, 0);
  // If our FD is still open, the memory better still be there!
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  // Copy state from shared memory segment
  state = *(libipc_state*)stateptr;

  int ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  // Done with the shared segment, thank you!
  ret = __real_close(MAGIC_SHM_FD);
  UC(ret, "close shm");
  ret = shm_unlink(getShmName());
  UC(ret, "shm_unlink after close");

  ipclog("State restored!\n");
}

void shm_state_destroy() {
  // If we have memory to restore, it'll be in our magic FD!
  assert(is_valid_fd(MAGIC_SHM_FD));

  int ret = __real_close(MAGIC_SHM_FD);
  assert(ret == 0);

  ret = shm_unlink(getShmName());
  UC(ret, "shm_unlink");

  ipclog("Destroyed saved state!\n");
}
<commit_msg>libipc: For compat, give shm segments we create more liberal perms.<commit_after>//===-- shm.cpp -----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Save/restore via shared memory to survive exec*()
//
//===----------------------------------------------------------------------===//

#include "shm.h"

#include "ipcreg_internal.h"
#include "magic_socket_nums.h"
#include "real.h"
#include "rename_fd.h"

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define UC(ret, msg) \
  unixCheck(ret, msg, __FILE__, __LINE__, __PRETTY_FUNCTION__);

void unixCheck(int ret, const char *msg, const char *file, unsigned line,
               const char *func, int err = errno) {
  if (ret == -1) {
    ipclog("Unix call failed in %s at %s:%u: %s - %s\n", func, file, line, msg,
           strerror(err));
    abort();
  }
}

static char buf[100];
const char *getShmName() {
  sprintf(buf, "/ipcd.%d\n", getpid());
  return buf;
}

int get_shm(int flags, mode_t mode) {
  int fd = shm_open(getShmName(), flags, mode);
  if (fd == -1 && errno == EEXIST) {
    ipclog("Shared memory segment exists, attempting to remove it...\n");
    int ret = shm_unlink(getShmName());
    UC(ret, "Closing existing shm");

    // Okay, let's try this again
    fd = shm_open(getShmName(), flags, mode);
  }
  UC(fd, "shm_open");
  UC(fchmod(fd, mode), "fchmod on shared memory segment");
  return fd;
}

void shm_state_save() {
  // Create shared memory segment
  int fd = get_shm(O_RDWR | O_CREAT | O_EXCL, 0777);
  UC(fd, "get_shm");

  bool success = rename_fd(fd, MAGIC_SHM_FD, /* cloexec */ false);
  assert(success && "Failed to rename SHM fd!");

  // Do *not* close on exec! :)
  int flags = __real_fcntl(MAGIC_SHM_FD, F_GETFD, /* kludge */ 0);
  assert(flags >= 0);
  flags &= ~FD_CLOEXEC;
  int ret = __real_fcntl_int(MAGIC_SHM_FD, F_SETFD, flags);
  UC(ret, "fcntl CLOEXEC on shared memory segment");

  // Size the memory segment:
  ret = ftruncate(MAGIC_SHM_FD, sizeof(libipc_state));
  UC(ret, "ftruncate on shm");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                  MAP_SHARED, MAGIC_SHM_FD, 0);
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  *(libipc_state*)stateptr = state;

  // Unmap, but don't unlink the shared memory
  ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  ipclog("State saved!\n");
}

bool is_valid_fd(int fd) {
  return __real_fcntl(fd, F_GETFD, /* kludge */ 0) >= 0;
}

void shm_state_restore() {
  // If we have memory to restore, it'll be in our magic FD!
  if (!is_valid_fd(MAGIC_SHM_FD))
    return;

  ipclog("Inherited ipc state FD, starting state restoration...\n");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                        MAP_SHARED, MAGIC_SHM_FD, 0);
  // If our FD is still open, the memory better still be there!
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  // Copy state from shared memory segment
  state = *(libipc_state*)stateptr;

  int ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  // Done with the shared segment, thank you!
  ret = __real_close(MAGIC_SHM_FD);
  UC(ret, "close shm");
  ret = shm_unlink(getShmName());
  UC(ret, "shm_unlink after close");

  ipclog("State restored!\n");
}

void shm_state_destroy() {
  // If we have memory to restore, it'll be in our magic FD!
  assert(is_valid_fd(MAGIC_SHM_FD));

  int ret = __real_close(MAGIC_SHM_FD);
  assert(ret == 0);

  ret = shm_unlink(getShmName());
  UC(ret, "shm_unlink");

  ipclog("Destroyed saved state!\n");
}
<|endoftext|>