Initial sensor monitor server client

master
Timothy Pearson 12 years ago
parent 25abfd3c58
commit 3ecb5d9be7

@ -90,6 +90,7 @@ AC_CONFIG_FILES([ src/part/commanalyzer/Makefile ])
AC_CONFIG_FILES([ src/part/fpgaprogram/Makefile ])
AC_CONFIG_FILES([ src/part/fpgaview/Makefile ])
AC_CONFIG_FILES([ src/part/scope/Makefile ])
AC_CONFIG_FILES([ src/part/sensormonitor/Makefile ])
AC_CONFIG_FILES([ src/widgets/Makefile ])
AC_OUTPUT
# Check if KDE_SET_PREFIX was called, and --prefix was passed to configure

@ -396,6 +396,7 @@ void ScopePart::setTickerMessage(TQString message) {
} \
else { \
m_commHandlerState = ScopeState_ExternalCommandRequest; \
EXEC_NEXT_STATE_IMMEDIATELY \
}
#define EXEC_NEXT_STATE_IMMEDIATELY m_forcedUpdateTimer->start(0, TRUE);

@ -40,6 +40,7 @@
#include <tqvbox.h>
#include <tqsocket.h>
#include <tqmutex.h>
#include <tqlayout.h>
#include <tqeventloop.h>
#include <tqapplication.h>
#include <tqgroupbox.h>
@ -58,13 +59,21 @@
#define NETWORK_COMM_TIMEOUT_MS 2500
enum connectionModes {
ModeIdle = 0
ModeIdle = 0,
ModeInterruptRequested = 1,
ModeGetSample = 2
};
enum connectionStates {
ModeIdle_StateStatusRequest = 0,
ModeIdle_StateProcessStatus = 1,
ModeIdle_StateDelay = 2
ModeIdle_StateSensorListRequest = 0,
ModeIdle_StateProcessSensorList = 1,
ModeIdle_StateStatusRequest = 2,
ModeIdle_StateProcessStatus = 3,
ModeIdle_StateDelay = 4,
ModeIdle_StatePaused = 5,
ModeIdle_StateExternalRequest = 6,
ModeGetSample_StateSampleRequest = 7,
ModeGetSample_StateProcessSample = 8
};
namespace RemoteLab {
@ -73,8 +82,103 @@ typedef KParts::GenericFactory<RemoteLab::SensorMonitorPart> Factory;
#define CLIENT_LIBRARY "libremotelab_sensormonitor"
K_EXPORT_COMPONENT_FACTORY(libremotelab_sensormonitor, RemoteLab::Factory)
TQValueTimer::TQValueTimer(TQObject *parent, const char *name)
: TQTimer(parent, name)
{
connect(this, SIGNAL(timeout()), this, SLOT(timeoutHandler()));
}
TQValueTimer::~TQValueTimer() {
//
}
void TQValueTimer::timeoutHandler() {
emit(valueTimeout(m_value));
}
int TQValueTimer::value() {
return m_value;
}
void TQValueTimer::setValue(int value) {
m_value = value;
}
TraceControlWidget::TraceControlWidget(TQWidget *parent, const char *name)
: TQWidget(parent, name), m_minimumTimeStep(0.0), m_nominalTimeStep(1.0)
{
TQGridLayout *topGrid = new TQGridLayout(this);
m_groupBox = new TQGroupBox(this);
m_groupBox->setColumnLayout(0, TQt::Vertical);
topGrid->addMultiCellWidget(m_groupBox, 0, 0, 0, 0);
m_groupBox->setTitle(i18n("Unknown Channel"));
m_primaryLayout = new TQGridLayout(m_groupBox->layout(), KDialog::marginHint(), KDialog::spacingHint());
m_channelEnabledCheckBox = new TQCheckBox(m_groupBox);
connect(m_channelEnabledCheckBox, SIGNAL(clicked()), this, SLOT(enableClicked()));
m_channelEnabledCheckBox->setText(i18n("Enable"));
m_primaryLayout->addMultiCellWidget(m_channelEnabledCheckBox, 0, 0, 0, 0);
m_timestepSpinBox = new FloatSpinBox(m_groupBox);
m_timestepSpinBox->setFloatMax(60*60*24); // 1 day
connect(m_timestepSpinBox, SIGNAL(floatValueChanged(double)), this, SLOT(timestepChanged(double)));
m_primaryLayout->addMultiCellWidget(m_timestepSpinBox, 0, 0, 1, 1);
m_sampleTimer = new TQTimer();
connect(m_sampleTimer, SIGNAL(timeout()), this, SIGNAL(newSampleDesired()));
}
TraceControlWidget::~TraceControlWidget() {
m_sampleTimer->stop();
delete m_sampleTimer;
}
void TraceControlWidget::startSampleTimer(int msecs) {
if (m_channelEnabledCheckBox->isOn()) {
m_nominalTimeStep = msecs/1.0e3;
m_sampleTimer->start(msecs, FALSE);
}
else {
m_sampleTimer->stop();
}
}
void TraceControlWidget::stopSampleTimer() {
m_sampleTimer->stop();
}
void TraceControlWidget::setTraceEnabled(bool enabled) {
m_channelEnabledCheckBox->setChecked(enabled);
}
void TraceControlWidget::setTraceName(TQString name) {
m_groupBox->setTitle(name);
}
void TraceControlWidget::setTimestep(double seconds) {
m_nominalTimeStep = seconds;
m_timestepSpinBox->setFloatValue(m_nominalTimeStep);
startSampleTimer(m_nominalTimeStep*1.0e3);
}
void TraceControlWidget::setMinTimestep(double seconds) {
m_minimumTimeStep = seconds;
m_timestepSpinBox->setFloatMin(seconds);
}
void TraceControlWidget::enableClicked() {
bool enabled = m_channelEnabledCheckBox->isOn();
emit(enableChanged(enabled));
startSampleTimer(m_nominalTimeStep*1.0e3);
}
void TraceControlWidget::timestepChanged(double value) {
m_sampleTimer->stop();
startSampleTimer(value*1.0e3);
}
SensorMonitorPart::SensorMonitorPart(TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name, const TQStringList&)
: RemoteInstrumentPart( parent, name ), m_base(NULL), m_commHandlerState(0), m_connectionActiveAndValid(false), m_tickerState(0)
: RemoteInstrumentPart( parent, name ), m_base(NULL), m_commHandlerState(0), m_connectionActiveAndValid(false), m_tickerState(0), stopTraceUpdate(false)
{
// Initialize important base class variables
m_clientLibraryName = CLIENT_LIBRARY;
@ -94,12 +198,57 @@ SensorMonitorPart::SensorMonitorPart(TQWidget *parentWidget, const char *widgetN
m_pingDelayTimer = new TQTimer(this);
connect(m_pingDelayTimer, SIGNAL(timeout()), this, SLOT(mainEventLoop()));
// Initialize data
m_hdivs = 10;
m_vdivs = 8;
m_maxNumberOfTraces = 0;
for (int traceno=0; traceno<=MAXTRACES; traceno++) {
m_samplesInTrace[traceno] = 0;
m_channelActive[traceno] = false;
m_traceUnits[traceno] = "";
m_traceControlWidgetList[traceno] = NULL;
m_sampleRequestInProgress[traceno] = false;
}
// Create widgets
m_base = new SensorMonitorBase(widget());
m_traceControlWidgetGrid = new TQGridLayout(m_base->traceControlLayoutWidget);
m_traceWidget = m_base->traceWidget;
m_traceWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding));
m_traceWidget->setNumberOfCursors(4);
m_traceWidget->setZoomCursorStartIndex(0);
m_traceWidget->setCursorOrientation(0, TQt::Horizontal);
m_traceWidget->setCursorOrientation(1, TQt::Horizontal);
m_traceWidget->setCursorOrientation(2, TQt::Vertical);
m_traceWidget->setCursorOrientation(3, TQt::Vertical);
m_traceWidget->setCursorEnabled(0, true);
m_traceWidget->setCursorEnabled(1, true);
m_traceWidget->setCursorEnabled(2, true);
m_traceWidget->setCursorEnabled(3, true);
m_traceWidget->setCursorName(0, "Cursor H1");
m_traceWidget->setCursorName(1, "Cursor H2");
m_traceWidget->setCursorName(2, "Cursor V1");
m_traceWidget->setCursorName(3, "Cursor V2");
m_traceWidget->setCursorPosition(0, 25);
m_traceWidget->setCursorPosition(1, 75);
m_traceWidget->setCursorPosition(2, 25);
m_traceWidget->setCursorPosition(3, 75);
TraceNumberList activeTraces;
for (uint trace=0; trace<MAXTRACES; trace++) {
activeTraces.append(trace);
}
m_traceWidget->setCursorActiveTraceList(0, activeTraces);
m_traceWidget->setCursorActiveTraceList(1, activeTraces);
m_traceWidget->setCursorActiveTraceList(2, activeTraces);
m_traceWidget->setCursorActiveTraceList(3, activeTraces);
m_traceWidget->setZoomBoxEnabled(true);
m_base->traceZoomWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding));
connect(m_traceWidget, SIGNAL(zoomBoxChanged(const TQRectF&)), this, SLOT(updateZoomWidgetLimits(const TQRectF&)));
// Initialize widgets
connect(m_base->runControlStartButton, SIGNAL(clicked()), this, SLOT(programStartButtonClicked()));
connect(m_base->runControlStopButton, SIGNAL(clicked()), this, SLOT(programStopButtonClicked()));
connect(m_base->runControlStartButton, SIGNAL(clicked()), this, SLOT(acquisitionStartButtonClicked()));
connect(m_base->runControlStopButton, SIGNAL(clicked()), this, SLOT(acquisitionStopButtonClicked()));
TQTimer::singleShot(0, this, TQT_SLOT(postInit()));
}
@ -123,6 +272,14 @@ void SensorMonitorPart::processLockouts() {
mainWidget->setEnabled(false);
}
}
if (stopTraceUpdate) {
m_base->runControlStartButton->setEnabled(true);
m_base->runControlStopButton->setEnabled(false);
}
else {
m_base->runControlStartButton->setEnabled(false);
m_base->runControlStopButton->setEnabled(true);
}
}
void SensorMonitorPart::resizeToHint() {
@ -160,7 +317,7 @@ void SensorMonitorPart::connectionFinishedCallback() {
m_socket->processPendingData();
connect(m_socket, SIGNAL(newDataReceived()), this, SLOT(mainEventLoop()));
m_tickerState = 0;
m_commHandlerState = ModeIdle_StateStatusRequest;
m_commHandlerState = ModeIdle_StateSensorListRequest;
m_commHandlerMode = ModeIdle;
m_socket->setDataTimeout(NETWORK_COMM_TIMEOUT_MS);
m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
@ -177,6 +334,9 @@ void SensorMonitorPart::connectionStatusChangedCallback() {
m_tickerState = 0; \
m_commHandlerState = ModeIdle_StateStatusRequest; \
m_commHandlerMode = ModeIdle; \
for (int traceno=0; traceno<=MAXTRACES; traceno++) { \
m_sampleRequestInProgress[traceno] = false; \
} \
m_socket->clearIncomingData(); \
setStatusMessage(i18n("Server ping timeout. Please verify the status of your network connection.")); \
m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE); \
@ -186,7 +346,14 @@ void SensorMonitorPart::connectionStatusChangedCallback() {
#define SET_WATCHDOG_TIMER if (!m_updateTimeoutTimer->isActive()) m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
#define PAT_WATCHDOG_TIMER m_updateTimeoutTimer->stop(); m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
#define SET_NEXT_STATE(x) m_commHandlerState = x;
#define SET_NEXT_STATE(x) if ((m_commHandlerMode == ModeIdle) || (m_commHandlerMode == ModeGetSample)) { \
m_commHandlerState = x; \
} \
else { \
m_commHandlerState = ModeIdle_StateExternalRequest; \
EXEC_NEXT_STATE_IMMEDIATELY \
}
#define SET_NEXT_STATE_DATA_WAITING(x) m_commHandlerState = x;
#define EXEC_NEXT_STATE_IMMEDIATELY m_forcedUpdateTimer->start(0, TRUE);
@ -224,17 +391,42 @@ void SensorMonitorPart::mainEventLoop() {
}
if (m_socket) {
if (m_commHandlerMode == ModeIdle) {
if ((m_commHandlerMode == ModeIdle) || (m_commHandlerMode == ModeInterruptRequested)) {
// Normal operation
switch (m_commHandlerState) {
case ModeIdle_StateSensorListRequest:
PAT_WATCHDOG_TIMER
ds << TQString("SENSORS");
m_socket->writeEndOfFrame();
SET_NEXT_STATE_DATA_WAITING(ModeIdle_StateProcessSensorList)
break;
case ModeIdle_StateProcessSensorList:
if (m_socket->canReadFrame()) {
PAT_WATCHDOG_TIMER
ds >> m_sensorList;
m_socket->clearFrameTail();
m_maxNumberOfTraces = m_sensorList.count();
updateTraceControlWidgets();
SET_NEXT_STATE(ModeIdle_StateStatusRequest)
EXEC_NEXT_STATE_IMMEDIATELY
}
else {
if (!m_updateTimeoutTimer->isActive()) {
UPDATEDISPLAY_TIMEOUT
}
}
break;
case ModeIdle_StateStatusRequest:
// Get status of remote system
// Clear buffers to synchronize frames in case of data corruption
m_socket->clearIncomingData();
ds << TQString("STATUS");
PAT_WATCHDOG_TIMER
// Ping remote system
ds << TQString("PING");
m_socket->writeEndOfFrame();
SET_NEXT_STATE(ModeIdle_StateProcessStatus)
SET_NEXT_STATE_DATA_WAITING(ModeIdle_StateProcessStatus)
break;
case ModeIdle_StateProcessStatus:
// Get all data
@ -249,16 +441,14 @@ void SensorMonitorPart::mainEventLoop() {
// Transfer probably failed
UPDATEDISPLAY_TIMEOUT
}
else if (status == "IDLE") {
else if (status == "PONG") {
// Do nothing
}
setTickerMessage(i18n("Connected"));
if (m_commHandlerState == ModeIdle_StateProcessStatus) {
m_pingDelayTimer->start(250, TRUE);
SET_NEXT_STATE(ModeIdle_StateDelay);
}
m_pingDelayTimer->start(250, TRUE);
SET_NEXT_STATE(ModeIdle_StateDelay);
}
else {
if (!m_updateTimeoutTimer->isActive()) {
@ -275,6 +465,67 @@ void SensorMonitorPart::mainEventLoop() {
}
PAT_WATCHDOG_TIMER
break;
case ModeIdle_StatePaused:
PAT_WATCHDOG_TIMER
break;
case ModeIdle_StateExternalRequest:
m_commHandlerMode = ModeGetSample;
m_commHandlerState = m_commHandlerNextState;
break;
}
}
else if (m_commHandlerMode == ModeGetSample) {
if (m_commHandlerState == ModeGetSample_StateSampleRequest) {
PAT_WATCHDOG_TIMER
ds << TQString("SAMPLE");
ds << m_sampleRequestIndex;
m_socket->writeEndOfFrame();
SET_NEXT_STATE_DATA_WAITING(ModeGetSample_StateProcessSample)
setTickerMessage(i18n("Obtaining new data point for sensor %1").arg(m_sensorList[m_sampleRequestIndex].name));
}
else if (m_commHandlerState == ModeGetSample_StateProcessSample) {
if (m_socket->canReadFrame()) {
PAT_WATCHDOG_TIMER
TQString result;
double newValue;
TQDateTime timestamp;
ds >> result;
if (result == "ACK") {
ds >> newValue;
ds >> timestamp;
TQDoubleArray sampleArray = m_traceWidget->samples(m_sampleRequestIndex);
TQDoubleArray positionArray = m_traceWidget->positions(m_sampleRequestIndex);
m_samplesInTrace[m_sampleRequestIndex]++;
sampleArray.resize(m_samplesInTrace[m_sampleRequestIndex]);
positionArray.resize(m_samplesInTrace[m_sampleRequestIndex]);
sampleArray[m_samplesInTrace[m_sampleRequestIndex]-1] = newValue;
positionArray[m_samplesInTrace[m_sampleRequestIndex]-1] = (timestamp.toTime_t()+(timestamp.time().msec()*1.0e-3));
m_traceWidget->setSamples(m_sampleRequestIndex, sampleArray);
m_traceWidget->setPositions(m_sampleRequestIndex, positionArray);
m_base->traceZoomWidget->setSamples(m_sampleRequestIndex, sampleArray);
m_base->traceZoomWidget->setPositions(m_sampleRequestIndex, positionArray);
updateGraticule();
m_traceWidget->repaint(false);
m_base->traceZoomWidget->repaint(false);
}
m_socket->clearFrameTail();
m_sampleRequestInProgress[m_sampleRequestIndex] = false;
m_commHandlerMode = ModeIdle;
m_pingDelayTimer->start(250, TRUE);
SET_NEXT_STATE(ModeIdle_StateDelay);
EXEC_NEXT_STATE_IMMEDIATELY
}
else {
if (!m_updateTimeoutTimer->isActive()) {
UPDATEDISPLAY_TIMEOUT
}
}
}
}
@ -288,6 +539,183 @@ void SensorMonitorPart::mainEventLoop() {
m_connectionMutex->unlock();
}
void SensorMonitorPart::updateZoomWidgetLimits(const TQRectF& zoomRect) {
for (int traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
TQRectF fullZoomRect = m_traceWidget->displayLimits(traceno);
double widthSpan = fullZoomRect.width()-fullZoomRect.x();
double heightSpan = fullZoomRect.height()-fullZoomRect.y();
TQRectF zoomLimitsRect((fullZoomRect.x()+(widthSpan*(zoomRect.x()/100.0))), (fullZoomRect.y()+(heightSpan*(zoomRect.y()/100.0))), (fullZoomRect.x()+(widthSpan*((zoomRect.x()/100.0)+(zoomRect.width()/100.0)))), (fullZoomRect.y()+(heightSpan*((zoomRect.y()/100.0)+(zoomRect.height()/100.0)))));
m_base->traceZoomWidget->setDisplayLimits(traceno, zoomLimitsRect);
}
}
void SensorMonitorPart::updateGraticule() {
m_traceWidget->setNumberOfHorizontalDivisions(m_hdivs);
m_traceWidget->setNumberOfVerticalDivisions(m_vdivs);
m_base->traceZoomWidget->setNumberOfHorizontalDivisions(m_hdivs);
m_base->traceZoomWidget->setNumberOfVerticalDivisions(m_vdivs);
if (m_maxNumberOfTraces > 0) m_traceWidget->setTraceColor(0, TQColor(255, 255, 255));
if (m_maxNumberOfTraces > 1) m_traceWidget->setTraceColor(1, TQColor(128, 255, 128));
if (m_maxNumberOfTraces > 2) m_traceWidget->setTraceColor(2, TQColor(255, 255, 128));
if (m_maxNumberOfTraces > 3) m_traceWidget->setTraceColor(3, TQColor(128, 128, 255));
if (m_maxNumberOfTraces > 0) m_base->traceZoomWidget->setTraceColor(0, TQColor(255, 255, 255));
if (m_maxNumberOfTraces > 1) m_base->traceZoomWidget->setTraceColor(1, TQColor(128, 255, 128));
if (m_maxNumberOfTraces > 2) m_base->traceZoomWidget->setTraceColor(2, TQColor(255, 255, 128));
if (m_maxNumberOfTraces > 3) m_base->traceZoomWidget->setTraceColor(3, TQColor(128, 128, 255));
for (int traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
m_traceWidget->setTraceEnabled(traceno, m_channelActive[traceno]);
m_traceWidget->setTraceName(traceno, m_sensorList[traceno].name);
m_traceWidget->setTraceHorizontalUnits(traceno, "s");
m_traceWidget->setTraceVerticalUnits(traceno, m_sensorList[traceno].units);
m_base->traceZoomWidget->setTraceEnabled(traceno, m_channelActive[traceno], false);
m_base->traceZoomWidget->setTraceName(traceno, m_sensorList[traceno].name);
m_base->traceZoomWidget->setTraceHorizontalUnits(traceno, "s");
m_base->traceZoomWidget->setTraceVerticalUnits(traceno, m_sensorList[traceno].units);
m_traceWidget->setNumberOfSamples(traceno, m_samplesInTrace[traceno]);
m_base->traceZoomWidget->setNumberOfSamples(traceno, m_samplesInTrace[traceno]);
double starttime = 0.0;
double endtime = 0.0;
if (m_samplesInTrace[traceno] > 0) {
starttime = m_traceWidget->positions(traceno)[0];
endtime = m_traceWidget->positions(traceno)[m_samplesInTrace[traceno]-1];
}
m_traceWidget->setDisplayLimits(traceno, TQRectF(starttime, m_sensorList[traceno].max, endtime, m_sensorList[traceno].min));
if (m_traceControlWidgetList[traceno]) {
m_traceControlWidgetList[traceno]->setTraceEnabled(m_channelActive[traceno]);
}
}
updateZoomWidgetLimits(m_traceWidget->zoomBox());
}
void SensorMonitorPart::updateTraceControlWidgets() {
// Add or remove trace control widgets as needed...
int i;
for (i=0; i<m_maxNumberOfTraces;i++) {
if (!m_traceControlWidgetList[i]) {
m_traceControlWidgetList[i] = new TraceControlWidget(m_base->traceControlLayoutWidget);
connect(m_traceControlWidgetList[i], SIGNAL(enableChanged(bool)), this, SLOT(traceControlEnableChanged(bool)));
connect(m_traceControlWidgetList[i], SIGNAL(newSampleDesired()), this, SLOT(processNewSampleRequest()));
m_traceControlWidgetGrid->addMultiCellWidget(m_traceControlWidgetList[i], i, i, 0, 0);
m_traceControlWidgetList[i]->setTraceName(m_sensorList[i].name);
m_traceControlWidgetList[i]->show();
// Set sample rate
m_traceControlWidgetList[i]->setMinTimestep(m_sensorList[i].mininterval);
m_traceControlWidgetList[i]->setTimestep(m_sensorList[i].nominalinterval);
}
}
for (i=m_maxNumberOfTraces; i<MAXTRACES;i++) {
if (m_traceControlWidgetList[i]) {
m_traceControlWidgetGrid->remove(m_traceControlWidgetList[i]);
delete m_traceControlWidgetList[i];
}
}
}
void SensorMonitorPart::traceControlEnableChanged(bool enabled) {
int i;
int channel = -1;
const TraceControlWidget* widget = dynamic_cast<const TraceControlWidget*>(sender());
if (widget) {
for (i=0; i<MAXTRACES;i++) {
if (m_traceControlWidgetList[i] == widget) {
channel = i;
break;
}
}
if ((channel >= 0) && (channel <=MAXTRACES)) {
m_channelActive[channel] = enabled;
}
}
updateGraticule();
m_traceWidget->repaint(false);
m_base->traceZoomWidget->repaint(false);
updateTraceControlWidgets();
}
void SensorMonitorPart::processNewSampleRequest() {
int i;
int channel = -1;
const TraceControlWidget* widget = dynamic_cast<const TraceControlWidget*>(sender());
if (widget) {
for (i=0; i<MAXTRACES;i++) {
if (m_traceControlWidgetList[i] == widget) {
channel = i;
break;
}
}
if ((channel >= 0) && (channel <=MAXTRACES)) {
if (!stopTraceUpdate) {
if (!m_sampleRequestInProgress[channel]) {
m_sampleRequestInProgress[channel] = true;
processNewSampleRequest(channel);
}
else {
printf("[WARNING] Sample request made while previous sample not collected. Some data was not captured (therefore lost)...\n\r");
}
}
}
}
}
void SensorMonitorPart::processNewSampleRequest(int channel) {
TQValueTimer* senderTimer = const_cast<TQValueTimer*>(dynamic_cast<const TQValueTimer*>(sender()));
if (senderTimer) {
senderTimer->stop();
delete senderTimer;
}
if (m_commHandlerMode == ModeIdle) {
// Request a sample
if (m_commHandlerState == ModeIdle_StateDelay) {
m_commHandlerMode = ModeGetSample;
m_commHandlerState = ModeGetSample_StateSampleRequest;
EXEC_NEXT_STATE_IMMEDIATELY
}
else {
m_commHandlerMode = ModeInterruptRequested;
m_commHandlerNextState = ModeGetSample_StateSampleRequest;
}
m_sampleRequestIndex = channel;
}
else {
// The main loop is already getting a sample
// Resubmit the request later on
TQValueTimer* timer = new TQValueTimer;
timer->setValue(channel);
connect(timer, SIGNAL(valueTimeout(int)), this, SLOT(processNewSampleRequest(int)));
timer->start(10, TRUE);
}
}
void SensorMonitorPart::acquisitionStartButtonClicked() {
stopTraceUpdate = false;
processLockouts();
if (m_socket) m_socket->clearIncomingData();
m_commHandlerMode = ModeIdle;
m_commHandlerState = ModeIdle_StateStatusRequest;
EXEC_NEXT_STATE_IMMEDIATELY
}
void SensorMonitorPart::acquisitionStopButtonClicked() {
stopTraceUpdate = true;
processLockouts();
for (int i=0; i<MAXTRACES;i++) {
m_sampleRequestInProgress[i] = false;
}
m_commHandlerMode = ModeIdle;
m_commHandlerState = ModeIdle_StatePaused;
setStatusMessage(i18n("Acquisition stopped"));
mainEventLoop();
}
KAboutData* SensorMonitorPart::createAboutData() {
return new KAboutData( APP_NAME, I18N_NOOP( APP_PRETTYNAME ), APP_VERSION );
}

@ -33,21 +33,83 @@
#include <kparts/statusbarextension.h>
#include <kparts/part.h>
#include <kurl.h>
#include <kled.h>
#include <tqtrla.h>
#include "floatspinbox.h"
#define MAXTRACES 255
class KAboutData;
using KParts::StatusBarExtension;
class TraceWidget;
class TQSocket;
class TQTimer;
class TQMutex;
class TQRectF;
class TQGridLayout;
class TQCheckBox;
class TQGroupBox;
class TQFile;
class SensorMonitorBase;
namespace RemoteLab
{
class Q_EXPORT TQValueTimer : public TQTimer
{
Q_OBJECT
public:
TQValueTimer(TQObject *parent=0, const char *name=0);
~TQValueTimer();
int value();
void setValue(int);
signals:
void valueTimeout(int);
private slots:
void timeoutHandler();
private:
int m_value;
};
class TraceControlWidget : public TQWidget
{
Q_OBJECT
public:
TraceControlWidget(TQWidget *parent=0, const char *name=0);
~TraceControlWidget();
public:
void setTraceEnabled(bool enabled);
void setTraceName(TQString name);
void setTimestep(double seconds);
void setMinTimestep(double seconds);
void startSampleTimer(int msecs);
void stopSampleTimer();
signals:
void enableChanged(bool enabled);
void newSampleDesired();
private slots:
void enableClicked();
void timestepChanged(double);
private:
TQGroupBox* m_groupBox;
TQGridLayout* m_primaryLayout;
TQCheckBox* m_channelEnabledCheckBox;
FloatSpinBox* m_timestepSpinBox;
TQTimer* m_sampleTimer;
double m_minimumTimeStep;
double m_nominalTimeStep;
};
class SensorMonitorPart : public KParts::RemoteInstrumentPart
{
Q_OBJECT
@ -62,6 +124,7 @@ namespace RemoteLab
public slots:
virtual bool openURL(const KURL &url);
void updateZoomWidgetLimits(const TQRectF& zoomRect);
private slots:
void postInit();
@ -73,9 +136,19 @@ namespace RemoteLab
void disconnectFromServerCallback();
void connectionStatusChangedCallback();
void setTickerMessage(TQString message);
void updateGraticule();
void updateTraceControlWidgets();
void traceControlEnableChanged(bool enabled);
void processNewSampleRequest();
void processNewSampleRequest(int channel);
void acquisitionStartButtonClicked();
void acquisitionStopButtonClicked();
private:
SensorMonitorBase* m_base;
TraceWidget* m_traceWidget;
TQGridLayout* m_traceControlWidgetGrid;
TQMutex* m_connectionMutex;
TQTimer* m_pingDelayTimer;
TQTimer* m_forcedUpdateTimer;
@ -87,9 +160,18 @@ namespace RemoteLab
int m_commHandlerNextMode;
bool m_connectionActiveAndValid;
unsigned char m_tickerState;
TQByteArray m_programmingFileData;
TQ_ULONG m_programmingFileTotalSize;
TQ_ULONG m_programmingFileTransferredBytes;
bool stopTraceUpdate;
SensorList m_sensorList;
TQ_INT16 m_maxNumberOfTraces;
TQ_INT16 m_hdivs;
TQ_INT16 m_vdivs;
TQ_INT32 m_samplesInTrace[MAXTRACES+1];
bool m_channelActive[MAXTRACES+1];
TQString m_traceUnits[MAXTRACES+1];
TraceControlWidget* m_traceControlWidgetList[MAXTRACES];
TQ_UINT32 m_sampleRequestIndex;
bool m_sampleRequestInProgress[MAXTRACES+1];
};
}

@ -454,5 +454,47 @@ TQDataStream &operator>>( TQDataStream &s, StationType &st )
s >> st.description;
return s;
}
/*!
\relates SensorType
Writes the SensorType \a str to the stream \a s.
See also \link datastreamformat.html Format of the TQDataStream operators \endlink
*/
TQDataStream &operator<<( TQDataStream &s, const SensorType &st )
{
s << st.index;
s << st.name;
s << st.description;
s << st.units;
s << st.min;
s << st.max;
s << st.mininterval;
s << st.nominalinterval;
return s;
}
/*!
\relates SensorType
Reads a SensorType from the stream \a s into SensorType \a str.
See also \link datastreamformat.html Format of the TQDataStream operators \endlink
*/
TQDataStream &operator>>( TQDataStream &s, SensorType &st )
{
s >> st.index;
s >> st.name;
s >> st.description;
s >> st.units;
s >> st.min;
s >> st.max;
s >> st.mininterval;
s >> st.nominalinterval;
return s;
}
#endif // QT_NO_DATASTREAM

@ -163,4 +163,26 @@ typedef TQValueList<StationType> StationList;
// =============================================================================
class SensorType
{
public:
TQ_UINT32 index;
TQString name;
TQString description;
TQString units;
double min;
double max;
double mininterval;
double nominalinterval;
};
#ifndef QT_NO_DATASTREAM
Q_EXPORT TQDataStream &operator<<(TQDataStream &, const SensorType &);
Q_EXPORT TQDataStream &operator>>(TQDataStream &, SensorType &);
#endif
typedef TQValueList<SensorType> SensorList;
// =============================================================================
#endif // TQTRLA_H

@ -1,11 +1,11 @@
INCLUDES= $(all_includes) $(KDE_INCLUDES)/tde -I/usr/include/sasl
KDE_CXXFLAGS = $(USE_EXCEPTIONS)
bin_PROGRAMS = remotefpga_fpgaprogserver
bin_PROGRAMS = remotefpga_sensormonserver
remotefpga_fpgaprogserver_SOURCES = main.cpp fpga_conn.cpp
remotefpga_sensormonserver_SOURCES = main.cpp sensor_conn.cpp
remotefpga_fpgaprogserver_METASOURCES = AUTO
remotefpga_fpgaprogserver_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -lktexteditor -ltdekrbsocket -ltqtrla
remotefpga_sensormonserver_METASOURCES = AUTO
remotefpga_sensormonserver_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -lktexteditor -ltdekrbsocket -ltqtrla
KDE_OPTIONS = nofinal

@ -58,7 +58,7 @@ int main(int argc, char *argv[])
KSimpleConfig config(TQDir::currentDirPath() + "/remotefpga_sensormonserver.conf", false);
config.setGroup("Server");
SensorServer fpgasvr(0, config.readNumEntry("port", 4014), &config);
SensorServer sensorsvr(0, config.readNumEntry("port", 4014), &config);
return app.exec();
}

@ -56,12 +56,7 @@ struct exit_exception {
};
enum connectionStates {
StateIdle = 0,
StateGetFileSize = 1,
StateGetFileContents = 2,
StateStartProgramming = 3,
StateCheckProgrammingStatus = 4,
StateProgammingFinished = 5
StateIdle = 0
};
/*
@ -70,24 +65,37 @@ enum connectionStates {
instance of this class.
*/
SensorSocket::SensorSocket(int sock, TQObject *parent, const char *name) :
TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_loopTimer(NULL), m_config(static_cast<SensorServer*>(parent)->m_config), m_commandLoopState(StateIdle),
m_progpipe(NULL), m_progpipefd(-1), m_progErrorFlag(false), m_progDoneFlag(false)
TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_loopTimer(NULL), m_config(static_cast<SensorServer*>(parent)->m_config), m_commandLoopState(StateIdle)
{
// Initialize timers
m_kerberosInitTimer = new TQTimer();
connect(m_kerberosInitTimer, SIGNAL(timeout()), this, SLOT(finishKerberosHandshake()));
m_servClientTimeout = new TQTimer();
// Initialize data structures
int i;
for (i=0;i<MAX_SENSORS;i++) {
m_sensorMinIntervalTimers[i] = NULL;
}
initializeSensors();
setServiceName("remotefpga");
line = 0;
connect(this, SIGNAL(connectionClosed()), SLOT(connectionClosedHandler()));
connect(this, SIGNAL(connectionClosed()), parent, SLOT(remoteConnectionClosed()));
setSocket(sock);
}
SensorSocket::~SensorSocket() {
for (int j=0;j<MAX_SENSORS;j++) {
if (m_sensorMinIntervalTimers[j]) {
m_sensorMinIntervalTimers[j]->stop();
delete m_sensorMinIntervalTimers[j];
m_sensorMinIntervalTimers[j] = NULL;
}
}
if (m_servClientTimeout) {
m_servClientTimeout->stop();
delete m_servClientTimeout;
@ -161,6 +169,49 @@ void SensorSocket::finishKerberosHandshake() {
}
}
void SensorSocket::initializeSensors() {
int i=0;
m_sensorList.clear();
m_sensorExecInfo.clear();
m_config->setGroup("Sensors");
TQStringList sensorNameList = m_config->readListEntry("active");
for (TQStringList::Iterator it = sensorNameList.begin(); it != sensorNameList.end(); ++it) {
TQString sensorName = *it;
if (m_config->hasGroup(TQString("Sensor %1").arg(sensorName))) {
SensorType st;
m_config->setGroup(TQString("Sensor %1").arg(sensorName));
st.index = i;
st.name = sensorName;
st.description = m_config->readEntry("name", i18n("<unknown>"));
st.units = m_config->readEntry("units", i18n("<unknown>"));
st.min = m_config->readDoubleNumEntry("minvalue", 0.0);
st.max = m_config->readDoubleNumEntry("maxvalue", 1.0);
st.mininterval = m_config->readDoubleNumEntry("mininterval", 1.0);
st.nominalinterval = m_config->readDoubleNumEntry("nominalinterval", 10.0);
m_sensorList.append(st);
m_sensorExecInfo[i] = m_config->readEntry("exec", "echo 0 && exit");
if (!m_sensorMinIntervalTimers[i]) m_sensorMinIntervalTimers[i] = new TQTimer();
m_sensorMinIntervalTimers[i]->stop();
printf("[DEBUG] Added new sensor %s at index %d\n\r", st.name.ascii(), st.index);
i++;
}
else {
printf("[WARNING] Unknown sensor %s specified in sensor list. Ignoring...\n\r", sensorName.ascii());
}
if (i>=MAX_SENSORS) {
printf("[WARNING] MAX_SENSORS (%d) exceeded. Ignoring any additional sensor definitions...\n\r", MAX_SENSORS);
break;
}
}
for (int j=i;j<MAX_SENSORS;j++) {
if (m_sensorMinIntervalTimers[j]) {
m_sensorMinIntervalTimers[j]->stop();
delete m_sensorMinIntervalTimers[j];
m_sensorMinIntervalTimers[j] = NULL;
}
}
}
void SensorSocket::commandLoop() {
bool transferred_data;
@ -168,8 +219,7 @@ void SensorSocket::commandLoop() {
try {
transferred_data = false;
if (state() == TQSocket::Connected) {
if ((m_commandLoopState == StateIdle) || (m_commandLoopState == StateStartProgramming) || (m_commandLoopState == StateCheckProgrammingStatus) || (m_commandLoopState == StateProgammingFinished)) {
// Certain commands can come in at any time during some operations
if (m_commandLoopState == StateIdle) {
if (canReadLine()) {
processPendingData();
}
@ -178,145 +228,71 @@ void SensorSocket::commandLoop() {
ds.setPrintableData(true);
TQString command;
ds >> command;
clearFrameTail();
if (command == "STATUS") {
if (m_logMessages != "") {
ds << TQString("LOGMESSAGES");
writeEndOfFrame();
ds << m_logMessages;
writeEndOfFrame();
m_logMessages = "";
}
else if (m_progErrorFlag) {
ds << TQString("ERROR");
m_progErrorFlag = false;
writeEndOfFrame();
}
else if (m_progDoneFlag) {
ds << TQString("DONE");
ds << m_progRetCode;
m_progDoneFlag = false;
writeEndOfFrame();
}
else if (m_commandLoopState == StateIdle) {
ds << TQString("IDLE");
writeEndOfFrame();
}
else if ((m_commandLoopState == StateStartProgramming) || (m_commandLoopState == StateCheckProgrammingStatus) || (m_commandLoopState == StateProgammingFinished)) {
ds << TQString("PROGRAMMING");
writeEndOfFrame();
}
else {
ds << TQString("UNKNOWN");
writeEndOfFrame();
}
if (command == "SENSORS") {
clearFrameTail();
ds << m_sensorList;
writeEndOfFrame();
}
else if (m_commandLoopState == StateIdle) {
if (command == "FILE") {
m_commandLoopState = StateGetFileSize;
else if (command == "SAMPLE") {
TQ_UINT32 sensorIndex;
ds >> sensorIndex;
clearFrameTail();
printf("[DEBUG] Requested sample from sensor at index %d\n\r", sensorIndex);
if (sensorIndex >= m_sensorList.count()) {
ds << TQString("NCK");
}
else if (command == "PROGRAM") {
m_commandLoopState = StateStartProgramming;
else if (m_sensorMinIntervalTimers[sensorIndex]->isActive()) {
ds << TQString("DLY");
}
else {
printf("[WARNING] Received unknown command '%s'\n\r", command.ascii());
double sampleValue;
bool commandSuccess = true;
long long intervalMsec = (m_sensorList[sensorIndex].mininterval*1.0e3);
m_sensorMinIntervalTimers[sensorIndex]->start(intervalMsec, TRUE);
TQDateTime timestamp = TQDateTime::currentDateTime(TQt::UTC);
TQString command = m_sensorExecInfo[sensorIndex];
FILE* pipe = popen(command.ascii(), "r");
if (!pipe) {
commandSuccess = false;
}
else {
char buffer[1024];
TQString result = "";
while(!feof(pipe)) {
if (fgets(buffer, 1024, pipe) != NULL) {
result += buffer;
}
}
TQ_INT32 retcode = pclose(pipe);
sampleValue = result.toDouble();
if (retcode != 0) {
commandSuccess = false;
}
}
if (commandSuccess) {
ds << TQString("ACK");
ds << sampleValue;
ds << timestamp;
}
else {
ds << TQString("NCK");
}
}
writeEndOfFrame();
}
transferred_data = true;
}
}
if (m_commandLoopState == StateGetFileSize) {
if (canReadLine()) {
processPendingData();
}
if (canReadFrame()) {
TQDataStream ds(this);
ds.setPrintableData(true);
ds >> m_programmingFileSize;
clearFrameTail();
m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
m_commandLoopState = StateGetFileContents;
}
}
else if (m_commandLoopState == StateGetFileContents) {
if (canReadLine()) {
m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
processPendingData();
}
if (bytesAvailable() >= m_programmingFileSize) {
TQByteArray fileContents(m_programmingFileSize);
readBlock(fileContents.data(), fileContents.size());
m_programmingFileName = TQString("/tmp/%1#%2.dat").arg(m_remoteHost).arg(port());
TQFile outputFile(m_programmingFileName);
if (outputFile.open(IO_ReadWrite)) {
outputFile.writeBlock(fileContents);
outputFile.flush();
outputFile.close();
else if (command == "PING") {
clearFrameTail();
ds << TQString("PONG");
writeEndOfFrame();
}
transferred_data = true;
m_commandLoopState = StateIdle;
}
else {
if (!m_servClientTimeout->isActive()) {
m_progErrorFlag = true;
transferred_data = true;
m_commandLoopState = StateIdle;
else {
clearFrameTail();
printf("[WARNING] Received unknown command %s from host %s\n\r", command.ascii(), m_remoteHost.ascii()); fflush(stdout);
ds << TQString("NCK");
writeEndOfFrame();
}
}
}
else if (m_commandLoopState == StateStartProgramming) {
// Start programming!
// Open programming process
m_config->setGroup("Programming");
TQString programmingScript = m_config->readEntry("script");
programmingScript.replace("%f", m_programmingFileName);
if (!programmingScript.contains("2>&1")) {
programmingScript.append(" 2>&1");
}
if ((m_progpipe = popen(programmingScript.ascii(), "r")) == NULL) {
m_logMessages.append(TQString("The system was unable to execute '%1'\nPlease contact your system administrator with this information").arg(programmingScript));
m_progErrorFlag = true;
transferred_data = true;
m_commandLoopState = StateIdle;
}
else {
m_progpipefd = fileno(m_progpipe);
fcntl(m_progpipefd, F_SETFL, O_NONBLOCK);
}
m_commandLoopState = StateCheckProgrammingStatus;
}
else if (m_commandLoopState == StateCheckProgrammingStatus) {
// Check programming status
TQCString buf;
buf.resize(8192);
ssize_t r = read(m_progpipefd, buf.data(), buf.size());
if ((r == -1) && (errno == EAGAIN)) {
// No data available yet
}
else if (r > 0) {
// Data was received
buf.data()[r] = 0;
m_logMessages.append(buf);
}
else {
// Process terminated
m_commandLoopState = StateProgammingFinished;
}
}
else if (m_commandLoopState == StateProgammingFinished) {
// Programming process terminated; get exit code and clean up
if (m_progpipe) {
m_progRetCode = pclose(m_progpipe);
}
else {
m_progRetCode = -1;
}
m_progpipe = NULL;
m_progpipefd = -1;
m_progDoneFlag = true;
m_commandLoopState = StateIdle;
}
}
m_criticalSection--;

@ -38,13 +38,17 @@
#define MAGIC_NUMBER 1
#define PROTOCOL_VERSION 1
class SensorServer : public TDEKerberosServerSocket
#define MAX_SENSORS 255
typedef TQMap<TQ_UINT32, TQString> SensorStringMap;
class SensorSocket : public TDEKerberosServerSocket
{
Q_OBJECT
public:
SensorServer(int sock, TQObject *parent=0, const char *name=0);
~SensorServer();
SensorSocket(int sock, TQObject *parent=0, const char *name=0);
~SensorSocket();
public:
void close();
@ -55,9 +59,9 @@ class SensorServer : public TDEKerberosServerSocket
void finishKerberosHandshake();
void connectionClosedHandler();
void commandLoop();
void initializeSensors();
private:
int line;
int m_criticalSection;
TQString m_remoteHost;
@ -68,26 +72,20 @@ class SensorServer : public TDEKerberosServerSocket
KSimpleConfig* m_config;
int m_commandLoopState;
TQ_ULONG m_programmingFileSize;
TQString m_programmingFileName;
FILE *m_progpipe;
int m_progpipefd;
bool m_progErrorFlag;
bool m_progDoneFlag;
TQ_INT32 m_progRetCode;
TQString m_logMessages;
SensorList m_sensorList;
SensorStringMap m_sensorExecInfo;
TQTimer* m_sensorMinIntervalTimers[MAX_SENSORS];
friend class FPGAServer;
friend class SensorServer;
};
class FPGAServer : public TQServerSocket
class SensorServer : public TQServerSocket
{
Q_OBJECT
public:
FPGAServer(TQObject* parent=0, int port=0, KSimpleConfig* config=0);
~FPGAServer();
SensorServer(TQObject* parent=0, int port=0, KSimpleConfig* config=0);
~SensorServer();
void newConnection(int socket);
@ -95,12 +93,12 @@ class FPGAServer : public TQServerSocket
void remoteConnectionClosed();
signals:
void newConnect(SensorServer*);
void newConnect(SensorSocket*);
private:
KSimpleConfig* m_config;
int m_numberOfConnections;
friend class SensorServer;
friend class SensorSocket;
};
Loading…
Cancel
Save