Commit f3b96b13 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

Merge branch 'orson-wic-sw'

parents 3af98e16 c41ce8b0
......@@ -17,12 +17,22 @@
*/
#include <QtWidgets/QPushButton>
#include <QtWidgets/QDialog>
#include <QtWidgets/QGroupBox>
#include <QBoxLayout>
#include <QLabel>
#include <QStatusBar>
#include "controller.h"
// Register custom type for Qt signals
static struct registerMetatypes {
registerMetatypes()
{
qRegisterMetaType<nanoFIP::DataStatusMap>("nanoFIP::DataStatusMap");
qRegisterMetaType<mstrfip_data_status>("mstrfip_data_status");
}
} _registerMetatypes;
DiotHardware::DiotHardware(int address, int slots_nr)
{
// Configure MasterFIP
......@@ -45,7 +55,13 @@ DiotHardware::DiotHardware(int address, int slots_nr)
crate.reset(new DIOT_Crate(address, slots_nr));
crate->AddVariables(cycle->GetPeriodicVarWindow());
crate->SetConsVarCb([&](nanoFIP &nf) {
crate->SetConsVarCb([&](nanoFIP &nf, mstrfip_data *data) {
emit StatusChanged(data->status, nf.GetDataStats());
// No more updates if the data is invalid
if(data->status != MSTRFIP_DATA_OK)
return;
// Report the crate state
DIOT_Crate* crate = static_cast<DIOT_Crate*>(&nf);
......@@ -86,7 +102,7 @@ void DiotHardware::SetOutput(int slot, unsigned int state)
}
DiotIOCard::DiotIOCard(QDialog* parent, DiotHardware& hw, int num, int idx)
DiotIOCard::DiotIOCard(QWidget* parent, const DiotHardware& hw, int num, int idx)
: QFrame(parent), inputs(num, true),
outputs(num, false), slot_nr(idx), io_count(num)
{
......@@ -167,7 +183,7 @@ void DiotIOCard::testBtn_click(int slot, int io) {
void DiotIOCard::update_inputs() {
for(int i = 0; i < io_count; ++i) {
if(inputs[i]) {
if(!inputs[i]) {
lbl_state[i]->setStyleSheet("background-color: green; color: white");
} else {
lbl_state[i]->setStyleSheet("background-color: maroon; color: white");
......@@ -210,7 +226,7 @@ bool DiotIOCard::int_to_vec(unsigned int integer, std::vector<bool>& vec)
}
DiotIOController::DiotIOController(QDialog* dialog, DiotHardware& hw, int slots_count)
DiotIOController::DiotIOController(QWidget* dialog, DiotHardware& hw, int slots_count)
: QFrame(dialog)
{
QHBoxLayout *boxLayout = new QHBoxLayout();
......@@ -244,11 +260,12 @@ void DiotIOController::UpdateInputErr(int slot, unsigned int state)
}
DiotDiag::DiotDiag(QDialog* parent, DiotHardware& hw)
DiotDiag::DiotDiag(QWidget* parent, const DiotHardware& hw)
: QFrame(parent)
{
DIOT_Crate* crate = hw.GetCrate();
QHBoxLayout *mainLayout = new QHBoxLayout();
QVBoxLayout *mainLayout = new QVBoxLayout();
QHBoxLayout *statsLayout = new QHBoxLayout();
// Fans
QGroupBox *fanBox = new QGroupBox(this);
......@@ -260,7 +277,7 @@ DiotDiag::DiotDiag(QDialog* parent, DiotHardware& hw)
}
fanBox->setTitle("Fans");
fanBox->setLayout(fanLayout);
mainLayout->addWidget(fanBox);
statsLayout->addWidget(fanBox);
// Temperature sensors
QGroupBox *tempBox = new QGroupBox(this);
......@@ -272,7 +289,7 @@ DiotDiag::DiotDiag(QDialog* parent, DiotHardware& hw)
}
tempBox->setTitle("Temperature");
tempBox->setLayout(tempLayout);
mainLayout->addWidget(tempBox);
statsLayout->addWidget(tempBox);
// Voltages
QGroupBox *voltBox = new QGroupBox(this);
......@@ -285,7 +302,25 @@ DiotDiag::DiotDiag(QDialog* parent, DiotHardware& hw)
}
voltBox->setTitle("Voltages");
voltBox->setLayout(voltLayout);
mainLayout->addWidget(voltBox);
statsLayout->addWidget(voltBox);
// Data statistics
QGroupBox *statBox = new QGroupBox(this);
QVBoxLayout *statLayout = new QVBoxLayout();
for(const auto& statType : hw.GetCrate()->GetDataStats()) {
auto statWidget = new QLabel(QString("%1: 0")
.arg(QString::fromStdString(nanoFIP::GetDataStatDesc(statType.first))));
statLayout->addWidget(statWidget);
stat_lbl.push_back(statWidget);
}
statBox->setTitle("Data statistics");
statBox->setLayout(statLayout);
statsLayout->addWidget(statBox);
mainLayout->addLayout(statsLayout, 1);
statusBar = new QStatusBar(this);
mainLayout->addWidget(statusBar);
setLayout(mainLayout);
......@@ -295,6 +330,8 @@ DiotDiag::DiotDiag(QDialog* parent, DiotHardware& hw)
this, &DiotDiag::UpdateTemperature);
QObject::connect(&hw, &DiotHardware::VoltageChanged,
this, &DiotDiag::UpdateVoltage);
QObject::connect(&hw, &DiotHardware::StatusChanged,
this, &DiotDiag::UpdateStatus);
}
......@@ -316,6 +353,48 @@ void DiotDiag::UpdateVoltage(unsigned int volt, bool state)
}
void DiotDiag::UpdateStatus(mstrfip_data_status status,
const nanoFIP::DataStatusMap& stats)
{
qDebug() << "status: " << status;
switch(status)
{
case MSTRFIP_DATA_OK:
statusBar->showMessage("Status: data OK");
break;
case MSTRFIP_DATA_FRAME_ERROR:
statusBar->showMessage("Status: frame error");
break;
case MSTRFIP_DATA_PAYLOAD_ERROR:
statusBar->showMessage("Status: payload error");
break;
case MSTRFIP_DATA_NOT_RECEIVED:
statusBar->showMessage("Status: data not received");
break;
}
if(status == MSTRFIP_DATA_OK) {
statusBar->setStyleSheet("color: green");
parentWidget()->setEnabled(true);
}
else {
statusBar->setStyleSheet("color: red");
parentWidget()->setEnabled(false);
}
for( const auto& stat : stats )
{
stat_lbl[static_cast<int>(stat.first)]->setText(QString("%1: %2")
.arg(QString::fromStdString(nanoFIP::GetDataStatDesc(stat.first)))
.arg(stat.second));
}
}
void DiotDiag::updateLabel(std::vector<QLabel*> labels, unsigned int idx,
bool state, const QString& desc, int val)
{
......
......@@ -28,9 +28,9 @@
#include <diot_crate.h>
class DiotIOController;
class QDialog;
class QLabel;
class QPushButton;
class QStatusBar;
/**
* Class representing the DIOT crate hardware in the Qt world.
......@@ -104,6 +104,15 @@ signals:
*/
void VoltageChanged(unsigned int volt, bool state);
/**
* Signal emitted to update the data status.
* @param status is the new data status.
* @param stats contains statistics.
* @see enum mstrfip_data_status
*/
void StatusChanged(mstrfip_data_status status,
const nanoFIP::DataStatusMap& stats);
private:
std::unique_ptr<MasterFIP> mfip;
std::unique_ptr<CycleSimple> cycle;
......@@ -120,7 +129,7 @@ class DiotIOCard : public QFrame {
Q_OBJECT
public:
DiotIOCard(QDialog* parent, DiotHardware& hw, int num, int idx);
DiotIOCard(QWidget* parent, const DiotHardware& hw, int num, int idx);
virtual ~DiotIOCard() {}
unsigned int GetInput() const {
......@@ -164,7 +173,7 @@ class DiotIOController : public QFrame {
Q_OBJECT
public:
DiotIOController(QDialog* dialog, DiotHardware& hw, int slots_count);
DiotIOController(QWidget* dialog, DiotHardware& hw, int slots_count);
public slots:
void UpdateInput(int slot, unsigned int state);
......@@ -183,7 +192,7 @@ class DiotDiag : public QFrame {
Q_OBJECT
public:
DiotDiag(QDialog* parent, DiotHardware& hw);
DiotDiag(QWidget* parent, const DiotHardware& hw);
virtual ~DiotDiag() {}
public slots:
......@@ -201,6 +210,8 @@ public slots:
void UpdateVoltage(unsigned int volt, bool state);
void UpdateStatus(mstrfip_data_status status, const nanoFIP::DataStatusMap& stats);
private:
// Helper function to update labels
void updateLabel(std::vector<QLabel*> labels,
......@@ -209,6 +220,8 @@ private:
std::vector<QLabel*> fan_lbl;
std::vector<QLabel*> temp_lbl;
std::vector<QLabel*> volt_lbl;
std::vector<QLabel*> stat_lbl;
QStatusBar* statusBar;
};
#endif /* CONTROLLER_H */
......@@ -18,9 +18,9 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
# Input
HEADERS += controller.h diot_crate.h
HEADERS += controller.h diot_crate.h diot_dialog.h
#FORMS += dialog.ui main_win.ui
SOURCES += main.cpp controller.cpp diot_crate.cpp
SOURCES += main.cpp controller.cpp diot_crate.cpp diot_dialog.cpp
# enable C++11
CONFIG += c++11
......
......@@ -265,7 +265,7 @@ private:
static constexpr unsigned int FAN_COUNT = 3;
///> Number of temperature sensors
static constexpr unsigned int TEMP_COUNT = 6;
static constexpr unsigned int TEMP_COUNT = 2;
///> Vector storing all voltages
static const std::vector<std::pair<VOLTAGE, std::string>> VOLTAGES;
......
/*
* Copyright (C) 2018 CERN
* Author: Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QBoxLayout>
#include "diot_dialog.h"
DIOT_Dialog::DIOT_Dialog(int address, int slots_nr)
: hw(address, slots_nr)
{
QVBoxLayout *mainLayout = new QVBoxLayout();
DiotIOController *controller = new DiotIOController(this, hw, slots_nr);
mainLayout->addWidget(controller);
DiotDiag *diag = new DiotDiag(this, hw);
mainLayout->addWidget(diag);
setLayout(mainLayout);
hw.Start();
}
/*
* Copyright (C) 2018 CERN
* Author: Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DIOT_DIALOG_H
#define DIOT_DIALOG_H
#include <QDialog>
#include "controller.h"
class DIOT_Dialog : public QDialog
{
public:
DIOT_Dialog(int address, int slots_nr);
protected:
DiotHardware hw;
};
#endif /* DIOT_DIALOG_H */
......@@ -18,9 +18,7 @@
#include <iostream>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>
#include <QBoxLayout>
#include "controller.h"
#include "diot_dialog.h"
// Argument values
constexpr int ADDRESS_DEFAULT = 1;
......@@ -40,7 +38,6 @@ static void usage() {
int main( int argc, char **argv ) {
QApplication a( argc, argv );
QDialog w;
// Process arguments
int address = ADDRESS_DEFAULT;
......@@ -69,18 +66,7 @@ int main( int argc, char **argv ) {
return 0;
}
DiotHardware hw(address, slots_nr);
QVBoxLayout *mainLayout = new QVBoxLayout();
DiotIOController *controller = new DiotIOController(&w, hw, slots_nr);
mainLayout->addWidget(controller);
DiotDiag *diag = new DiotDiag(&w, hw);
mainLayout->addWidget(diag);
w.setLayout(mainLayout);
DIOT_Dialog w(address, slots_nr);
w.show();
hw.Start();
return a.exec();
}
......@@ -48,6 +48,7 @@ MasterFIP::MasterFIP(struct mstrfip_dev *device)
throw std::runtime_error("Duplicate mstrfip_dev");
}
ClearErrors();
instances[dev] = this;
}
......@@ -136,7 +137,7 @@ void MasterFIP::StartCycle(CycleBase &cycle)
void MasterFIP::StopCycle()
{
if(state == STOPPED) {
DBG("No cycle to stop");
DBG("No cycle to stop\n");
return;
}
......@@ -148,12 +149,45 @@ void MasterFIP::StopCycle()
}
void MasterFIP::ClearErrors()
{
errors[MSTRFIP_INVALID_ANSWER_ACK] = 0;
errors[MSTRFIP_INVALID_BITRATE] = 0;
errors[MSTRFIP_INVALID_BA_INSTR_COUNT] = 0;
errors[MSTRFIP_BA_IS_NULL] = 0;
errors[MSTRFIP_BA_MAX_VAR] = 0;
errors[MSTRFIP_BA_INVALID_VAR_COUNT] = 0;
errors[MSTRFIP_BA_PER_WIND_CFG_BAD] = 0;
errors[MSTRFIP_BA_INVALID_INSTR_PARAM] = 0;
errors[MSTRFIP_BA_NOT_STOP_STATE] = 0;
errors[MSTRFIP_BA_INCONSISTENCY] = 0;
errors[MSTRFIP_BA_WRONG_CYCLE_LENGTH] = 0;
errors[MSTRFIP_BA_INCONSISTENT_INSTR_SET] = 0;
errors[MSTRFIP_BA_WAIT_WIND_INSTR_MISSING] = 0;
errors[MSTRFIP_BA_INVALID_MACROCYCLE] = 0;
errors[MSTRFIP_INVALID_HW_VERS] = 0;
errors[MSTRFIP_TRTL_MSG_COUNT_INCONSISTENCY] = 0;
errors[MSTRFIP_TRTL_MSG_COUNT_OVERFLOW] = 0;
errors[MSTRFIP_TRTL_MSG_OVERFLOW] = 0;
errors[MSTRFIP_TRTL_MSG_READ_ERR] = 0;
errors[MSTRFIP_TRTL_MSG_READ_NULL] = 0;
errors[MSTRFIP_POLL_TIMEOUT] = 0;
errors[MSTRFIP_POLL_ERROR] = 0;
errors[MSTRFIP_BA_APER_VAR_NO_CB] = 0;
errors[MSTRFIP_BA_APER_MSG_NO_CB] = 0;
errors[MSTRFIP_BA_PER_VAR_NO_CB] = 0;
errors[MSTRFIP_RESET_MOCKTRTL_ERR] = 0;
// initialize the sentinel, so there are no exceptions when it is accessed
errors[__MSTRFIP_MAX_ERROR_CODE] = 0;
}
void MasterFIP::error_handler(mstrfip_dev *dev, mstrfip_error_list error)
{
auto it = MasterFIP::instances.find(dev);
if (it == MasterFIP::instances.end()) {
DBG("error_handler could not find 0x%p device", dev);
DBG("error_handler could not find 0x%p device\n", dev);
return;
}
......@@ -315,7 +349,7 @@ CycleBase::CycleBase(const MasterFIP &mfip, int length_us)
CycleBase::~CycleBase()
{
if (mstrfip_macrocycle_delete(dev, mcycle))
DBG("Could not delete cycle");
DBG("Could not delete cycle\n");
}
......@@ -332,8 +366,7 @@ int CycleBase::ReadRespTime()
if (mstrfip_hw_response_time_get(dev, agents.size(),
addresses.data(), resp_time.data())) {
//DBG(MasterFIP::errStr("Read turn around time failed: "));
DBG("Read turn around time failed: ");
DBG(MasterFIP::errStr("Read turn around time failed: "));
return -1;
}
......@@ -366,7 +399,7 @@ int CycleSimple::Update()
}
if (empty) {
DBG("Empty macrocyle");
DBG("Empty macrocyle\n");
return -1;
}
......@@ -387,6 +420,8 @@ AgentBase::AgentBase(unsigned int addr)
{
if (addr >= 255)
throw std::runtime_error("Agent address must lower than 255");
ClearErrors();
}
......@@ -395,6 +430,21 @@ AgentBase::~AgentBase()
}
void AgentBase::ClearErrors()
{
errors[WRITE_FAILED] = 0;
errors[MISSED] = 0;
errors[NOT_FRESHED] = 0;
errors[NOT_SIGNIFICANT] = 0;
errors[TIMEOUT] = 0;
errors[HW_ERR] = 0;
errors[HW_BSZ] = 0;
errors[HW_CTRL] = 0;
errors[HW_PDU] = 0;
errors[UNKNOWN] = 0;
}
int WaitForSignal()
{
int signo;
......
......@@ -117,12 +117,12 @@ public:
return dev;
}
typedef std::unordered_map<mstrfip_error_list, int> ErrorMap;
typedef std::unordered_map<mstrfip_error_list, int> MasterErrorMap;
/**
* Returns error counters.
*/
const ErrorMap& GetErrorCount() const
const MasterErrorMap& GetErrors() const
{
return errors;
}
......@@ -130,10 +130,7 @@ public:
/**
* Resets error counters.
*/
void ClearErrors()
{
errors.clear();
}
void ClearErrors();
protected:
///> Error handler wrapper
......@@ -158,7 +155,7 @@ protected:
void (*orig_err_handler)(mstrfip_dev *dev, mstrfip_error_list error);
///> Error counter
ErrorMap errors;
MasterErrorMap errors;
///> MasterFIP instances to resolve handlers
static std::unordered_map<mstrfip_dev*, MasterFIP*> instances;
......@@ -366,6 +363,34 @@ protected:
};
///> Communication error types
enum AgentError {
WRITE_FAILED, ///< writing new value failed
MISSED, ///< missed data (not updated)
NOT_FRESHED, ///< other than 0x5 promptness & significance
NOT_SIGNIFICANT, ///< other than 0x4 promptness & significance
TIMEOUT, ///< time out, no reply from agent
HW_ERR, ///< hw bit error in the frame
HW_BSZ, ///< hw wrong number of bytes in the frame
HW_CTRL, ///< hw bad control byte in the frame
HW_PDU, ///< hw bad pdu byte in the frame
UNKNOWN
};
namespace std {
template<>
struct hash<AgentError>
{
size_t operator()(const AgentError& a) const noexcept
{
// no need for any fancy algorithm, enum values are already unique
return a;
}
};
} // namespace std
class AgentBase
{
public:
......@@ -377,12 +402,46 @@ public:
return address;
}
typedef std::unordered_map<AgentError, unsigned int> AgentErrorMap;
/**
* Returns error counters.
*/
const AgentErrorMap& GetErrors() const
{
return errors;
}
/**
* Resets error counters.
*/
void ClearErrors();
protected:
/**
* Reports an error occurence.
* @param AgentError is the error type.
*/
void reportError(AgentError error)
{
// TODO error handler callback?
++errors[error];
}
///> Agent address on the FIP bus.
const unsigned int address;
private:
AgentErrorMap errors;
};
///> Sleeps until a signal arrives
/**
* Sleeps until a signal arrives
*
* Helper function for user applications. It will suspend the current thread
* execution until a signal is received.
*/
int WaitForSignal();
......
......@@ -54,17 +54,21 @@ int main(int argc, char *argv[])
}
// Produced variable handler
agent1.SetProdVarCb([&](nanoFIP& nf) {
++prod;
agent1.SetProdVarCb([&](nanoFIP& nf, mstrfip_data* data) {
++prod; // Produce next value in sequence
for(int i = 0; i < VAR_SIZE; ++i) {
agent1.SetProdVarData(i, prod);
}
std::cout << "variable produced = " << (int) prod << std::endl;
if (data->status != MSTRFIP_DATA_OK) {
std::cout << "produced variable cb error " << data->status << std::endl;
}
} );
agent1.SetConsVarCb([&](nanoFIP& nf) {
agent1.SetConsVarCb([&](nanoFIP& nf, mstrfip_data* data) {
uint8_t cons = nf.GetConsVarData(0);
for(int i = 1; i < VAR_SIZE; ++i) {
......@@ -77,6 +81,10 @@ int main(int argc, char *argv[])
}
std::cout << "variable consumed = " << (int) cons << std::endl;
if (data->status != MSTRFIP_DATA_OK) {
std::cout << "produced variable cb error " << data->status << std::endl;
}
} );
mfip->Configure(hw_cfg, sw_cfg);
......@@ -85,6 +93,56 @@ int main(int argc, char *argv[])
// Keep running until a signal arrives
WaitForSignal();
std::cout << "--------------------------------------" << std::endl;
// Display statistics
const auto& mfipErrors = mfip->GetErrors();
std::cout << "MasterFIP interface errors:" << std::endl;
std::cout << "\tINVALID_ANSWER_ACK: " << mfipErrors.at(MSTRFIP_INVALID_ANSWER_ACK) << std::endl;
std::cout << "\tINVALID_BITRATE: " << mfipErrors.at(MSTRFIP_INVALID_BITRATE) << std::endl;
std::cout << "\tINVALID_BA_INSTR_COUNT: " << mfipErrors.at(MSTRFIP_INVALID_BA_INSTR_COUNT) << std::endl;
std::cout << "\tBA_IS_NULL: " << mfipErrors.at(MSTRFIP_BA_IS_NULL) << std::endl;
std::cout << "\tBA_MAX_VAR: " << mfipErrors.at(MSTRFIP_BA_MAX_VAR) << std::endl;
std::cout << "\tBA_INVALID_VAR_COUNT: " << mfipErrors.at(MSTRFIP_BA_INVALID_VAR_COUNT) << std::endl;
std::cout << "\tBA_PER_WIND_CFG_BAD: " << mfipErrors.at(MSTRFIP_BA_PER_WIND_CFG_BAD) << std::endl;
std::cout << "\tBA_INVALID_INSTR_PARAM: " << mfipErrors.at(MSTRFIP_BA_INVALID_INSTR_PARAM) << std::endl;
std::cout << "\tBA_NOT_STOP_STATE: " << mfipErrors.at(MSTRFIP_BA_NOT_STOP_STATE) << std::endl;
std::cout << "\tBA_INCONSISTENCY: " << mfipErrors.at(MSTRFIP_BA_INCONSISTENCY) << std::endl;
std::cout << "\tBA_WRONG_CYCLE_LENGTH: " << mfipErrors.at(MSTRFIP_BA_WRONG_CYCLE_LENGTH) << std::endl;
std::cout << "\tBA_INCONSISTENT_INSTR_SET: " << mfipErrors.at(MSTRFIP_BA_INCONSISTENT_INSTR_SET) << std::endl;
std::cout << "\tBA_WAIT_WIND_INSTR_MISSING: " << mfipErrors.at(MSTRFIP_BA_WAIT_WIND_INSTR_MISSING) << std::endl;
std::cout << "\tBA_INVALID_MACROCYCLE: " << mfipErrors.at(MSTRFIP_BA_INVALID_MACROCYCLE) << std::endl;
std::cout << "\tINVALID_HW_VERS: " << mfipErrors.at(MSTRFIP_INVALID_HW_VERS) << std::endl;
std::cout << "\tTRTL_MSG_COUNT_INCONSISTENCY: " << mfipErrors.at(MSTRFIP_TRTL_MSG_COUNT_INCONSISTENCY) << std::endl;
std::cout << "\tTRTL_MSG_COUNT_OVERFLOW: "<< mfipErrors.at(MSTRFIP_TRTL_MSG_COUNT_OVERFLOW) << std::endl;
std::cout << "\tTRTL_MSG_OVERFLOW: " << mfipErrors.at(MSTRFIP_TRTL_MSG_OVERFLOW) << std::endl;
std::cout << "\tTRTL_MSG_READ_ERR: " << mfipErrors.at(MSTRFIP_TRTL_MSG_READ_ERR) << std::endl;
std::cout << "\tTRTL_MSG_READ_NULL: " << mfipErrors.at(MSTRFIP_TRTL_MSG_READ_NULL) << std::endl;
std::cout << "\tPOLL_TIMEOUT: " << mfipErrors.at(MSTRFIP_POLL_TIMEOUT) << std::endl;
std::cout << "\tPOLL_ERROR: " << mfipErrors.at(MSTRFIP_POLL_ERROR) << std::endl;
std::cout << "\tBA_APER_VAR_NO_CB: " << mfipErrors.at(MSTRFIP_BA_APER_VAR_NO_CB) << std::endl;
std::cout << "\tBA_APER_MSG_NO_CB: " << mfipErrors.at(MSTRFIP_BA_APER_MSG_NO_CB) << std::endl;
std::cout << "\tBA_PER_VAR_NO_CB: " << mfipErrors.at(MSTRFIP_BA_PER_VAR_NO_CB) << std::endl;
std::cout << "\tRESET_MOCKTRTL_ERR: " << mfipErrors.at(MSTRFIP_RESET_MOCKTRTL_ERR) << std::endl;
const auto& agentErrors = agent1.GetErrors();
std::cout << "Agent errors:" << std::endl;
std::cout << "\tWrite failed: " << agentErrors.at(WRITE_FAILED) << std::endl;
std::cout << "\tMissed data: " << agentErrors.at(MISSED) << std::endl;
std::cout << "\tNot refreshed: " << agentErrors.at(NOT_FRESHED) << std::endl;
std::cout << "\tNot significant: "<< agentErrors.at(NOT_SIGNIFICANT) << std::endl;
std::cout << "\tTimeout: " << agentErrors.at(TIMEOUT) << std::endl;
std::cout << "\tHW bit errors: " << agentErrors.at(HW_ERR) << std::endl;
std::cout << "\tHW wrong number of bytes: " << agentErrors.at(HW_BSZ) << std::endl;
std::cout << "\tHW bad control byte: " << agentErrors.at(HW_CTRL) << std::endl;
std::cout << "\tHW bad PDU byte: "<< agentErrors.at(HW_PDU) << std::endl;
std::cout << "\tUnknown error: " << agentErrors.at(UNKNOWN) << std::endl;
std::cout << "Agent frame statistics: " << std::endl;
for(const auto& stat : agent1.GetDataStats()) {
std::cout << "\t" << nanoFIP::GetDataStatDesc(stat.first) << ": " << stat.second << std::endl;
}
//mfip->StopCycle();
return 0;
......
......@@ -27,6 +27,7 @@ nanoFIP::nanoFIP(unsigned int addr, unsigned int variable_size)
{
cons_data.resize(variable_size);
prod_data.resize(variable_size);
ClearDataStats();
}
......@@ -51,6 +52,32 @@ int nanoFIP::AddVariables(WindowPeriodicVar& window)
}
void nanoFIP::ClearDataStats()
{
const mstrfip_data_status types[] = {
MSTRFIP_DATA_OK, MSTRFIP_DATA_FRAME_ERROR,
MSTRFIP_DATA_PAYLOAD_ERROR, MSTRFIP_DATA_NOT_RECEIVED
};
for(auto type : types) {
data_stats[type] = 0;
}
}
const std::string& nanoFIP::GetDataStatDesc(mstrfip_data_status stat)
{
static const std::unordered_map<mstrfip_data_status, std::string> statusMap = {
{ MSTRFIP_DATA_OK, "Data OK" },
{ MSTRFIP_DATA_FRAME_ERROR, "Frame error" },
{ MSTRFIP_DATA_PAYLOAD_ERROR, "Payload error" },
{ MSTRFIP_DATA_NOT_RECEIVED, "Data not received" }
};
return statusMap.at(stat);
}
void nanoFIP::consVarHandler(mstrfip_dev *dev, mstrfip_data *cvar,
mstrfip_irq* irq)
{
......@@ -64,24 +91,43 @@ void nanoFIP::consVarHandler(mstrfip_dev *dev, mstrfip_data *cvar,
break;
case MSTRFIP_DATA_PAYLOAD_ERROR:
// TODO check cvar->payload_error
DBG("Data payload error");
if (cvar->payload_error & MSTRFIP_FRAME_PAYLOAD_NOT_REFRESH)
reportError(NOT_FRESHED);
if (cvar->payload_error & MSTRFIP_FRAME_PAYLOAD_NOT_SIGNIFICANT)
reportError(NOT_SIGNIFICANT);
DBG("Data payload error\n");
break;
case MSTRFIP_DATA_NOT_RECEIVED:
// TODO
DBG("Data not received");
reportError(MISSED);
DBG("Data not received\n");
break;
case MSTRFIP_DATA_FRAME_ERROR:
// TODO check cvar->frame_error
DBG("Data frame error");
if (cvar->frame_error & MSTRFIP_FRAME_TMO)
reportError(TIMEOUT);
if (cvar->frame_error & MSTRFIP_FRAME_ERR)
reportError(HW_ERR);
if (cvar->frame_error & MSTRFIP_FRAME_BAD_CTRL)
reportError(HW_CTRL);
if (cvar->frame_error & MSTRFIP_FRAME_BAD_PDU)
reportError(HW_PDU);
if (cvar->frame_error & MSTRFIP_FRAME_BAD_BSZ)
reportError(HW_BSZ);
DBG("Data frame error\n");
break;
default:
reportError(UNKNOWN);
DBG("Unknown error\n");
break;
}
++data_stats[cvar->status];
}
if (cons_cb) // User callback
cons_cb(*this);
cons_cb(*this, cvar);
}
......@@ -96,14 +142,16 @@ void nanoFIP::prodVarHandler(mstrfip_dev *dev, mstrfip_data *pvar,
int res = mstrfip_var_write(dev, pvar);
if (res) {
DBG("Variable write failed");
return;
reportError(WRITE_FAILED);
DBG("Variable write failed\n");
}
else
{
prod_dirty = false;
}
prod_dirty = false;
}
}
if (prod_cb) // User callback
prod_cb(*this);
prod_cb(*this, pvar);
}
......@@ -24,6 +24,18 @@
#include <functional>
#include <mutex>
namespace std {
template<>
struct hash<mstrfip_data_status>
{
size_t operator()(const mstrfip_data_status& a) const noexcept
{
// no need for any fancy algorithm, enum values are already unique
return a;
}
};
} // namespace std
/**
* NanoFIP is a base class for all devices taking advantage of nanoFIP agent.
* It might be also used as a generic interface to nanoFIP.
......@@ -35,7 +47,10 @@ protected:
public:
///> Produced/consumed variable event handler signature
typedef std::function<void(nanoFIP&)> VarCallback;
typedef std::function<void(nanoFIP&, mstrfip_data*)> VarCallback;
///> Map to store data frame stats
typedef std::unordered_map<mstrfip_data_status, unsigned int> DataStatusMap;
/**
* nanoFIP constructor.
......@@ -104,6 +119,18 @@ public:
prod_cb = cb;
}
///> Returns frame statistics
const DataStatusMap& GetDataStats() const
{
return data_stats;
}
///> Resets frame statistics
void ClearDataStats();
///> Returns human-readable description for data status enum
static const std::string& GetDataStatDesc(mstrfip_data_status stat);
protected:
///> Consumed variable event handler
virtual void consVarHandler(mstrfip_dev *dev, mstrfip_data *cvar,
......@@ -157,6 +184,9 @@ protected:
}
private:
///> Data frame stats
DataStatusMap data_stats;
///> Raw consumed variable data (updated by consVarHandler), guarded with cons_mtx
std::vector<uint8_t> cons_data;
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>510</width>
<height>597</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>70</x>
<y>90</y>
<width>101</width>
<height>351</height>
</rect>
</property>
<property name="title">
<string>Slot 1</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>0</x>
<y>90</y>
<width>31</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>1</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>0</x>
<y>120</y>
<width>31</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>2</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_2">
<property name="geometry">
<rect>
<x>220</x>
<y>90</y>
<width>101</width>
<height>351</height>
</rect>
</property>
<property name="title">
<string>Slot 2</string>
</property>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>0</x>
<y>90</y>
<width>31</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>3</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
<widget class="QPushButton" name="pushButton_4">
<property name="geometry">
<rect>
<x>0</x>
<y>120</y>
<width>31</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>4</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="but1">
<property name="geometry">
<rect>
<x>410</x>
<y>330</y>
<width>99</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
<widget class="QRadioButton" name="radioButton">
<property name="geometry">
<rect>
<x>80</x>
<y>150</y>
<width>117</width>
<height>22</height>
</rect>
</property>
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
#!/usr/bin/python3
###############################################################################
# This work is part of the Distributed I/O Tier project
# Copyright (c) 2018 CERN (www.cern.ch)
# Author: Greg Daniluk <grzegorz.daniluk@cern.ch>
# Released according to the GNU GPL, version 2 or any later version.
###############################################################################
import sys
import copy
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from ui_dialog import Ui_Dialog
import threading
import time
class TestDialog(QDialog, Ui_Dialog):
def __init__(self):
super(TestDialog, self).__init__()
# setup GUI from Qt Designer
self.setupUi(self)
self.show()
##########################################################
## DiotSlot class definition ##
##########################################################
class DiotSlot():
def __init__(self, Dialog, num, idx):
self.btn_state = []
self.io_state = []
self.btn_test = []
#######################
self.groupBox = QGroupBox(Dialog)
self.groupBox.setGeometry(QtCore.QRect(20+idx*170, 20, 150, 40+num*30))
self.groupBox.setTitle("Slot "+str(idx+1))
for i in range(0, num):
self.io_state.append(True)
self.btn_state.append(QPushButton(self.groupBox))
self.btn_state[i].setGeometry(QtCore.QRect(20, 30+i*30, 30, 30))
self.btn_state[i].setText(str((i+1)+idx*num))
self.btn_state[i].setStyleSheet("background-color: green")
self.btn_test.append(QPushButton(self.groupBox))
self.btn_test[i].setGeometry(QtCore.QRect(50, 30+i*30, 80, 30))
self.btn_test[i].setText("Test")
self.btn_test[i].clicked.connect(lambda state, slot=idx, io=i: self.action_click(slot, io))
def action_click(self, slot, io):
print("Button test clicked - slot(" + str(slot) +") io(" + str(io) + ")")
## TODO: add here sending new output state over fieldbus
self.update_state(io, not self.io_state[io])
def update_state(self, io, new_state):
self.io_state[io] = new_state
# and refresh color
if self.io_state[io] == True:
self.btn_state[io].setStyleSheet("background-color: green")
else:
self.btn_state[io].setStyleSheet("background-color: red")
##########################################################
## Thread class definition ##
##########################################################
class ReadThread (threading.Thread):
def __init__(self, threadID, name, slots):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.slots = slots
self.end_thread = 0
def run(self):
## TODO: put here cyclic reading of all IO state
while self.end_thread == 0:
time.sleep(1)
self.slots[3].update_state(5, not self.slots[3].io_state[5])
print("thread updated io")
def stop(self):
self.end_thread = 1
if __name__ == '__main__':
app = QApplication(sys.argv)
#w = TestDialog()
w = QDialog()
slots = []
for i in range (0, 8):
slots.append(DiotSlot(w, 16, i))
#ui = Ui_Dialog()
#ui.setupUi(w)
w.show()
thread1 = ReadThread(1, "ReadThread-1", slots)
thread1.start()
sys.exit(app.exec_())
print("Exiting")
thread1.stop()
print("thread stopped?")
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'dialog.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(510, 597)
self.groupBox = QtWidgets.QGroupBox(Dialog)
self.groupBox.setGeometry(QtCore.QRect(70, 90, 101, 351))
self.groupBox.setObjectName("groupBox")
self.pushButton = QtWidgets.QPushButton(self.groupBox)
self.pushButton.setGeometry(QtCore.QRect(0, 90, 31, 27))
self.pushButton.setCheckable(False)
self.pushButton.setChecked(False)
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(self.groupBox)
self.pushButton_2.setGeometry(QtCore.QRect(0, 120, 31, 27))
self.pushButton_2.setCheckable(False)
self.pushButton_2.setChecked(False)
self.pushButton_2.setObjectName("pushButton_2")
self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
self.groupBox_2.setGeometry(QtCore.QRect(220, 90, 101, 351))
self.groupBox_2.setObjectName("groupBox_2")
self.pushButton_3 = QtWidgets.QPushButton(self.groupBox_2)
self.pushButton_3.setGeometry(QtCore.QRect(0, 90, 31, 27))
self.pushButton_3.setCheckable(False)
self.pushButton_3.setChecked(False)
self.pushButton_3.setObjectName("pushButton_3")
self.pushButton_4 = QtWidgets.QPushButton(self.groupBox_2)
self.pushButton_4.setGeometry(QtCore.QRect(0, 120, 31, 27))
self.pushButton_4.setCheckable(False)
self.pushButton_4.setChecked(False)
self.pushButton_4.setObjectName("pushButton_4")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.groupBox.setTitle(_translate("Dialog", "Slot 1"))
self.pushButton.setText(_translate("Dialog", "1"))
self.pushButton_2.setText(_translate("Dialog", "2"))
self.groupBox_2.setTitle(_translate("Dialog", "Slot 2"))
self.pushButton_3.setText(_translate("Dialog", "3"))
self.pushButton_4.setText(_translate("Dialog", "4"))
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main_win.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.but1 = QtWidgets.QPushButton(self.centralwidget)
self.but1.setGeometry(QtCore.QRect(410, 330, 99, 27))
self.but1.setObjectName("but1")
self.radioButton = QtWidgets.QRadioButton(self.centralwidget)
self.radioButton.setGeometry(QtCore.QRect(140, 180, 117, 22))
self.radioButton.setObjectName("radioButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 25))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.but1.setText(_translate("MainWindow", "PushButton"))
self.radioButton.setText(_translate("MainWindow", "RadioButton"))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment