diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 000000000..40e9f40a0 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,5 @@ + + +Default +python 2.7 + diff --git a/Makefile.in b/Makefile.in index 5c520065f..786559cbd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -42,7 +42,7 @@ ifeq ($(NOPLASMA),0) qtsubdirs += plasma endif ifeq ($(NOPUMPSTATION),0) -qtsubdirs += pumpstation/daemon pumpstation/controller pumpstation/app +qtsubdirs += pumpstation/daemon pumpstation/controller pumpstation/app pumpstation/analysis endif installsubdirs = devices external common pumpstation diff --git a/common/ApplicationConfigReader.cc b/common/ApplicationConfigReader.cc index 8448ab589..f90cc68af 100644 --- a/common/ApplicationConfigReader.cc +++ b/common/ApplicationConfigReader.cc @@ -38,9 +38,9 @@ void ApplicationConfigReader::fill(std::multimap &keyva std::istringstream iss(buffer.c_str(), std::istringstream::in); iss >> Key; - iss >> Value; - - keyvalueMap.insert(std::make_pair(Key, Value)); + while (iss >> Value) { + keyvalueMap.insert(std::make_pair(Key, Value)); + } } file.close(); diff --git a/common/ConradModel.cc b/common/ConradModel.cc index ac48011f1..f60c06b73 100644 --- a/common/ConradModel.cc +++ b/common/ConradModel.cc @@ -11,6 +11,16 @@ ConradModel::ConradModel(QObject * /* parent */) setControlsEnabled(true); } +ConradModel::ConradModel(const char* port, QObject * /* parent */) +: QObject(), + AbstractDeviceModel(), + port_(port), + switchStates_(8, OFF) +{ + setDeviceEnabled(true); + setControlsEnabled(true); +} + /// Shuts down all the devices before closing down. ConradModel::~ConradModel() { @@ -66,85 +76,101 @@ void ConradModel::initialize( void ) #else - // create a list with all available ttyUSB device (system) files - QStringList filters("ttyUSB*"); - - QDir devDir("/dev"); - devDir.setNameFilters(filters); - devDir.setFilter(QDir::System); - QStringList list = devDir.entryList(); - - // Only loop over list when not empty - if (!list.empty()) { - - // browse and try initialize() until conradController_ gets an answer - QStringList::const_iterator it = list.begin(); - QString port = QString( "/dev/" ) + *it; - - renewController( port ); - - while (it < list.end() && !controller_->initialize()) { - - // Compose full absolute location of USB device - port = QString( "/dev/" ) + *it; + if (port_.isEmpty()) { + // create a list with all available ttyUSB device (system) files + QStringList filters("ttyUSB*"); + + QDir devDir("/dev"); + devDir.setNameFilters(filters); + devDir.setFilter(QDir::System); + QStringList list = devDir.entryList(); + + // Only loop over list when not empty + if (!list.empty()) { + + // browse and try initialize() until conradController_ gets an answer + QStringList::const_iterator it = list.begin(); + QString port = QString( "/dev/" ) + *it; + renewController( port ); + + while (it < list.end() && !controller_->initialize()) { - ++it; - } - - // check communication; if it is not at the end, switch was found - if (it != list.end()) { + // Compose full absolute location of USB device + port = QString( "/dev/" ) + *it; + renewController( port ); - // read and init status - std::vector status = controller_->queryStatus(); - - // Announce new states - if (status.size() == 8) { - - setAllSwitchesReady( status ); - setDeviceState( READY ); - - // FIXME Redirect to central logger - // if( debugLevel_ >= 1 ) - NQLog("ConradModel::initialize()", NQLog::Message) + ++it; + } + + // check communication; if it is not at the end, switch was found + if (it != list.end()) { + + // read and init status + std::vector status = controller_->queryStatus(); + + // Announce new states + if (status.size() == 8) { + + setAllSwitchesReady( status ); + setDeviceState( READY ); + + // FIXME Redirect to central logger + // if( debugLevel_ >= 1 ) + NQLog("ConradModel::initialize()", NQLog::Message) << "connection to conrad via: " << port.toStdString() << "."; - - } else { - - /* - would be 0 if query failed (according to ConradController::queryStatus) - This means device malfunction, so set state accordingly - */ - - setDeviceFullOff(); - - NQLog("ConradModel::initialize()", NQLog::Fatal) + + } else { + + /* + would be 0 if query failed (according to ConradController::queryStatus) + This means device malfunction, so set state accordingly + */ + + setDeviceFullOff(); + + NQLog("ConradModel::initialize()", NQLog::Fatal) << "** ERROR: received malformed state vector."; - + + } + } else { + // if not successful; i.e. DEVICE NOT FOUND + setDeviceFullOff(); + // TODO Log why it failed + NQLog("ConradModel::initialize()", NQLog::Fatal) + << "Cannot connect to Conrad. Make sure that"; + NQLog("ConradModel::initialize()", NQLog::Fatal) + << "/dev/ttyUSB* is present and readable and no other process"; + NQLog("ConradModel::initialize()", NQLog::Fatal) + << "is connecting to the device."; } } else { - // if not successful; i.e. DEVICE NOT FOUND + setDeviceFullOff(); - // TODO Log why it failed + NQLog("ConradModel::initialize()", NQLog::Fatal) - << "Cannot connect to Conrad. Make sure that"; + << "Cannot connect to Conrad. Make sure that"; NQLog("ConradModel::initialize()", NQLog::Fatal) - << "/dev/ttyUSB* is present and readable and no other process"; + << "/dev/ttyUSB* is present and readable and no other process"; NQLog("ConradModel::initialize()", NQLog::Fatal) - << "is connecting to the device."; + << "is connecting to the device."; + } } else { - setDeviceFullOff(); - - NQLog("ConradModel::initialize()", NQLog::Fatal) - << "Cannot connect to Conrad. Make sure that"; - NQLog("ConradModel::initialize()", NQLog::Fatal) - << "/dev/ttyUSB* is present and readable and no other process"; - NQLog("ConradModel::initialize()", NQLog::Fatal) - << "is connecting to the device."; - + renewController(port_); + + controller_->initialize(); + + std::vector status = controller_->queryStatus(); + + // Announce new states + if (status.size() == 8) { + + setAllSwitchesReady(status); + setDeviceState( READY ); + } } #endif } diff --git a/common/ConradModel.h b/common/ConradModel.h index 1317dc2b7..0c09d8946 100644 --- a/common/ConradModel.h +++ b/common/ConradModel.h @@ -42,6 +42,8 @@ class ConradModel : // TODO Add initialisation parameters explicit ConradModel(QObject *parent = 0); + explicit ConradModel(const char* port, + QObject *parent = 0); virtual ~ConradModel(); // Methods for power control and status querying of the devices connected to @@ -58,6 +60,9 @@ public slots: void setSwitchEnabled(int device, bool enabled); protected: + + QString port_; + void initialize(); void close(); diff --git a/common/Fifo.h b/common/Fifo.h new file mode 100644 index 000000000..812366cb5 --- /dev/null +++ b/common/Fifo.h @@ -0,0 +1,83 @@ +#ifndef FIFO_H +#define FIFO_H + +#include + +#include + +template class Fifo +{ +public: + + typedef T value_type; + + Fifo(int N) { + buffer_.resize(N); + size_ = 0; + capacity_ = N; + currentFirstIndex_ = 0; + } + + int size() const { + return size_; + } + + virtual void push(const T& value) { + if (size_=capacity_) currentFirstIndex_ = 0; + buffer_[currentFirstIndex_] = value; + } + } + + const T & at(int i) const { + if (i>=size_) return last(); + int idx = currentFirstIndex_ - i; + if (idx<0) idx += size_; + return buffer_[idx]; + } + + T & first() { + return buffer_[currentFirstIndex_]; + } + + const T & first() const { + return buffer_[currentFirstIndex_]; + } + + T & last() { + int idx = currentFirstIndex_; + if (size_=capacity_) idx = 0; + } + return buffer_[idx]; + } + + const T & last() const { + int idx = currentFirstIndex_; + if (size_=capacity_) idx = 0; + } + return buffer_[idx]; + } + +protected: + + int size_; + int capacity_; + int currentFirstIndex_; + + QVector buffer_; +}; + +#endif // RINGBUFFER_H diff --git a/common/HistoryFifo.h b/common/HistoryFifo.h new file mode 100644 index 000000000..fd1f5484c --- /dev/null +++ b/common/HistoryFifo.h @@ -0,0 +1,178 @@ +#ifndef HISTORYFIFO_H +#define HISTORYFIFO_H + +#include + +#include +#include + +template class HistoryFifo +{ +public: + + typedef T value_type; + + HistoryFifo(int N) { + timestamp_.resize(N); + buffer_.resize(N); + size_ = 0; + capacity_ = N; + currentFirstIndex_ = 0; + } + + int size() const { + return size_; + } + + virtual void push(const T& value) { + push(QDateTime::currentDateTime(), value); + } + + virtual void push(const QDateTime& dt, const T& value) { + if (size_=capacity_) currentFirstIndex_ = 0; + timestamp_[currentFirstIndex_] = dt; + buffer_[currentFirstIndex_] = value; + } + } + + const QDateTime & timeAt(int i) const { + if (i>=size_) return lastTime(); + int idx = currentFirstIndex_ - i; + if (idx<0) idx += size_; + return timestamp_[idx]; + } + + QDateTime & firstTime() { + return timestamp_[currentFirstIndex_]; + } + + const QDateTime & firstTime() const { + return timestamp_[currentFirstIndex_]; + } + + QDateTime & lastTime() { + int idx = currentFirstIndex_; + if (size_=capacity_) idx = 0; + } + return timestamp_[idx]; + } + + const QDateTime & lastTime() const { + int idx = currentFirstIndex_; + if (size_=capacity_) idx = 0; + } + return timestamp_[idx]; + } + + qint64 sizeInSecs() const { + const QDateTime & f = firstTime(); + const QDateTime & l = lastTime(); + + return l.secsTo(f); + } + + qint64 deltaTime() const { + const QDateTime & f = firstTime(); + const QDateTime & l = lastTime(); + + return f.secsTo(l); + } + + qint64 deltaTime(int i, int j) const { + const QDateTime & f = timeAt(i); + const QDateTime & l = timeAt(j); + + return f.secsTo(l); + } + + const T & at(int i) const { + if (i>=size_) return last(); + int idx = currentFirstIndex_ - i; + if (idx<0) idx += size_; + return buffer_[idx]; + } + + T & first() { + return buffer_[currentFirstIndex_]; + } + + const T & first() const { + return buffer_[currentFirstIndex_]; + } + + T & last() { + int idx = currentFirstIndex_; + if (size_=capacity_) idx = 0; + } + return buffer_[idx]; + } + + const T & last() const { + int idx = currentFirstIndex_; + if (size_=capacity_) idx = 0; + } + return buffer_[idx]; + } + + qint64 delta() const { + const T & f = first(); + const T & l = last(); + + return l - f; + } + + qint64 delta(int i, int j) const { + const T & f = at(i); + const T & l = at(j); + + return l - f; + } + + const T gradient() const { + T d = delta(); + double dt = deltaTime(); + + return d/dt; + } + + const T gradient(int i, int j) const { + T d = delta(i, j); + double dt = deltaTime(i, j); + + return d/dt; + } + +protected: + + int size_; + int capacity_; + int currentFirstIndex_; + + QVector timestamp_; + QVector buffer_; +}; + +#endif // RINGBUFFER_H diff --git a/common/LeyboldGraphixThreeModel.cc b/common/LeyboldGraphixThreeModel.cc index 7c6df12b8..c9481c4e5 100644 --- a/common/LeyboldGraphixThreeModel.cc +++ b/common/LeyboldGraphixThreeModel.cc @@ -18,11 +18,11 @@ LeyboldGraphixThreeModel::LeyboldGraphixThreeModel(const char* port, timer_ = new QTimer(this); timer_->setInterval(updateInterval_ * 1000); - connect( timer_, SIGNAL(timeout()), this, SLOT(updateInformation()) ); + connect( timer_, SIGNAL(timeout()), this, SLOT(updateInformation())); setDeviceEnabled(true); - NQLog("LeyboldGraphixThree") << "constructed"; + NQLog("LeyboldGraphixThreeModel") << "constructed"; } LeyboldGraphixThree_t::SensorDetectionMode LeyboldGraphixThreeModel::getSensorDetectionMode(int sensor) const diff --git a/common/common.pro.in b/common/common.pro.in index 7d326dfde..f6e23c963 100644 --- a/common/common.pro.in +++ b/common/common.pro.in @@ -72,6 +72,8 @@ HEADERS += nqlogger.h \ DeviceState.h \ DeviceParameter.h \ Ringbuffer.h \ + Fifo.h \ + HistoryFifo.h \ SingletonApplication.h \ ApplicationConfig.h \ ApplicationConfigReader.h \ diff --git a/common_test/main.cpp b/common_test/main.cpp index e1639635e..0a55d09fa 100644 --- a/common_test/main.cpp +++ b/common_test/main.cpp @@ -17,6 +17,9 @@ #include +#include +#include + double imageScale(double focalLength) { double p0 = -0.0240888; @@ -28,93 +31,140 @@ double imageScale(double focalLength) int main(int argc, char *argv[]) { - double f = 50.0; - double gamma = imageScale(f); - double imageDistance = f * (gamma + 1.0); - double objectDistance = imageDistance / gamma; - - NVector3D height1(0., 0., 1720.); // HEIGHT1 - NVector3D height2(0., 0., 150.); // HEIGHT2 - NVector3D distance(0., -1.0*437., 0.); // DISTANCE - double angle1 = 20.9 * M_PI / 180.; - double angle2 = 16.2 * M_PI / 180.; - double angle3 = 0.4 * M_PI / 180.; - - distance.print(); - distance.rotateX(angle2); - distance.print(); + { + HistoryFifo fifo(5); + + fifo.push(QDateTime::fromString("2017-06-13T09:09:11", Qt::ISODate), 10); + fifo.push(QDateTime::fromString("2017-06-13T09:09:12", Qt::ISODate), 20); + fifo.push(QDateTime::fromString("2017-06-13T09:09:13", Qt::ISODate), 30); + fifo.push(QDateTime::fromString("2017-06-13T09:09:14", Qt::ISODate), 40); + fifo.push(QDateTime::fromString("2017-06-13T09:09:15", Qt::ISODate), 50); + fifo.push(QDateTime::fromString("2017-06-13T09:09:16", Qt::ISODate), 60); + fifo.push(QDateTime::fromString("2017-06-13T09:09:17", Qt::ISODate), 70); + fifo.push(QDateTime::fromString("2017-06-13T09:09:18", Qt::ISODate), 80); + fifo.push(QDateTime::fromString("2017-06-13T09:09:19", Qt::ISODate), 90); + + for (int i=0;i fifo(5); + + fifo.push(1); + fifo.push(2); // 1 + fifo.push(3); // 1 + fifo.push(4); // 1 + fifo.push(5); // 1 + fifo.push(6); // 2 + fifo.push(7); // 3 + fifo.push(8); // 4 + + for (int i=0;i #include +#include #include "LeyboldGraphixThreeFake.h" @@ -14,9 +15,9 @@ LeyboldGraphixThreeFake::LeyboldGraphixThreeFake( const ioport_t ioPort ) sensorType_[1] = "TTR?"; sensorType_[2] = "TTR?"; - pressure_[0] = 100.0; - pressure_[1] = 100.1; - pressure_[2] = 100.2; + pressure_[0] = 110.0; + pressure_[1] = 120.0; + pressure_[2] = 130.0; displayUnit_ = DisplayUnit_mbar; @@ -104,7 +105,7 @@ LeyboldGraphixThreeFake::SensorStatus LeyboldGraphixThreeFake::GetSensorStatus(i double LeyboldGraphixThreeFake::GetPressure(int sensor) const { if (sensor<1 || sensor>3) return -1; - return pressure_[sensor-1]; + return pressure_[sensor-1] + rand() % 10; } LeyboldGraphixThreeFake::DisplayUnit LeyboldGraphixThreeFake::GetDisplayUnit() const diff --git a/documentation/docs/pumpstation/index.md b/documentation/docs/pumpstation/index.md index ed5f64537..b8a87690c 100644 --- a/documentation/docs/pumpstation/index.md +++ b/documentation/docs/pumpstation/index.md @@ -1,3 +1,42 @@ # Usage -![Screenshot](screenshot.png) \ No newline at end of file +![Screenshot](screenshot.png) + +# PumpStationControl + +the command line program `PumpStationControl` communicates with the `PumpStationDaemon` +by sending commands and receiving and printing the daemon response on the command line. +The daemon understands the following commands: + +* setPumpState [int pump] [int state]
+switches on or off a pump. [int pump] can be either 1 or 2, [int state] is either 1 for +ON or 0 for OFF. + +* getPumpState [int pump]
+returns the state of a pump. [int pump] can be either 1 or 2. The returned value is +either 1 if the pump is ON or 0 if it is OFF. + +* setPumpOperatingHours [int pump] [double hours]
+Sets the operating hours of a pump. [int pump] can be either 1 or 2, [double hours] is +the number of hours the pump has been running. This command can be used to synchronize +the operating hours of a pump stored in the daemon config file with the actual value +measured by the pump itself. + +* getPumpOperatingHours
+returns the operating hours of both pumps in hours separated by a semicolon. + +* setValveState [int valve] [int state]
+opens or closes a valve. [int valve] can be either 1, 2 or 3, [int state] is either 1 for +OPEN or 0 for CLOSED. + +* getValveState [int valve]
+returns the state of a valve. [int valve] can be either 1, 2 or 3. The returned value is +either 1 if the valve is OPEN or 0 if it is CLOSED. + +* getPressure [int gauge]
+returns the pressure reading of a gauge in mbar. [int gauge] can be either 1, 2 or 3. + +* getVacuumStatus
+returns the status and pressure reading of all three gauges. The individual values are separated +by semicolons. + diff --git a/documentation/docs/pumpstation/setup.md b/documentation/docs/pumpstation/setup.md index 24158b291..e72adaa7d 100644 --- a/documentation/docs/pumpstation/setup.md +++ b/documentation/docs/pumpstation/setup.md @@ -11,7 +11,8 @@ In addition, please install the following packages via `sudo apt-get install apache2`
`sudo apt-get install libapache2-mod-webauth`
`sudo apt-get install libapache2-mod-php5`
- + `sudo apt-get install udev`
+ ## Installation Once building the software has successfully finished, install all required libraries and applications via @@ -19,4 +20,10 @@ Once building the software has successfully finished, install all required libra `sudo make install` This will also install scripts to automatically start the pump station daemon on system startup. -After a reboot of the system, the daemon will be running as the default raspberry pi user. \ No newline at end of file +After a reboot of the system, the daemon will be running as the default raspberry pi user. + +The deamon communicating with the devices in the background requires the devices (`/dev/ttyUSB*`) to +be correctly found. The Leybold GraphixThree controller is supposed to accessable via `/dev/ttyLeybold`, +and the Conrad relay card via `/dev/ttyConrad`. A udev rules file `99-usb-serial.rules` is +available in the `pumpstation` directory of the repository. Please copy it to the directory +`/etc/udev/rules.d/` and restart the system. \ No newline at end of file diff --git a/pumpstation/Makefile.in b/pumpstation/Makefile.in index ca24b59a0..e92a64fff 100644 --- a/pumpstation/Makefile.in +++ b/pumpstation/Makefile.in @@ -5,8 +5,8 @@ NOPUMPSTATION = @nopumpstation@ USEFAKEDEVICES= @usefakedevices@ -subdirs = daemon controller app -installsubdirs = daemon website +subdirs = daemon controller app analysis +installsubdirs = daemon website analysis all: @for dir in $(subdirs); do (cd $$dir; make); done diff --git a/pumpstation/analysis/.gitignore b/pumpstation/analysis/.gitignore new file mode 100644 index 000000000..9359498fd --- /dev/null +++ b/pumpstation/analysis/.gitignore @@ -0,0 +1,11 @@ +PumpStationAnalysis.pro +PumpStationAnalysis.pro.user +.qmake.cache +.qmake.stash +Makefile +*.d +*.o +*~ +moc_* +PumpStationAnalysis +*.root diff --git a/pumpstation/analysis/Analyser.cc b/pumpstation/analysis/Analyser.cc new file mode 100644 index 000000000..af60670c4 --- /dev/null +++ b/pumpstation/analysis/Analyser.cc @@ -0,0 +1,170 @@ +#include + +#include +#include +#include + +#include + +#include "Analyser.h" + +Analyser::Analyser(QStringList& arguments) + : arguments_(arguments), + measurementValid_(false) +{ + dataValid_ = false; + for (int i=0;i<5;++i) switchStateValid_[i] = false; + for (int i=0;i<3;++i) gaugeValid_[i] = false; +} + +void Analyser::analyse() +{ + if (arguments_.size()<2) { + std::cout << "usage: PumpStationAnalysis ..." << std::endl; + return; + } + + QStringList::const_iterator constIterator = arguments_.constBegin(); + + QString filename = *constIterator; + if (!filename.endsWith(".root")) filename += ".root"; + std::string rootname = filename.toStdString(); + + ofile_ = new TFile(rootname.c_str(), "RECREATE"); + + otree_ = new TTree("pumpstation", "pumpstation"); + + otree_->Branch("uTime", &measurement_.uTime, "uTime/i"); + otree_->Branch("datime", &measurement_.datime, 1024, 2); + + for (int i=0;i<5;++i) { + char dummy1[20]; + char dummy2[20]; + + sprintf(dummy1, "switchState%d", i); + sprintf(dummy2, "switchState%d/I", i); + otree_->Branch(dummy1, &measurement_.switchState[i], dummy2); + } + + for (int i=0;i<3;++i) { + char dummy1[20]; + char dummy2[20]; + + sprintf(dummy1, "gaugeState%d", i); + sprintf(dummy2, "gaugeState%d/I", i); + otree_->Branch(dummy1, &measurement_.gaugeState[i], dummy2); + + sprintf(dummy1, "pressure%d", i); + sprintf(dummy2, "pressure%d/D", i); + otree_->Branch(dummy1, &measurement_.pressure[i], dummy2); + } + + ++constIterator; + for (; + constIterator != arguments_.constEnd(); + ++constIterator) { + processFile(*constIterator); + } + + ofile_->Write(); + delete ofile_; + + QCoreApplication::quit(); +} + +void Analyser::processFile(const QString& filename) +{ + std::cerr << "processing file: " << filename.toLocal8Bit().constData() << std::endl; + + QFile file(filename); + if (file.open(QFile::ReadOnly)) { + QXmlStreamReader reader(&file); + + while (!reader.atEnd()) { + + QXmlStreamReader::TokenType tokentype = reader.readNext(); + + if (tokentype==QXmlStreamReader::EndElement) { + + if (reader.name()=="Status") { + if (dataValid_) dumpData(); + } + + } + + if (tokentype==QXmlStreamReader::StartElement) { + + QXmlStreamAttributes attributes = reader.attributes(); + + if (attributes.hasAttribute("time")) { + utime_ = QDateTime::fromString(attributes.value("time").toString(), Qt::ISODate); + } + + if (reader.name()=="ConradSwitch") { + + if (attributes.hasAttribute("id") && + attributes.hasAttribute("state")) { + int id = attributes.value("id").toString().toInt(); + bool state = attributes.value("state").toString().toInt(); + + switchState_[id] = state; + switchStateValid_[id] = true; + + if (attributes.hasAttribute("time")) dumpData(); + } + } + + if (reader.name()=="LeyboldGraphixThree") { + if (attributes.hasAttribute("id") && + attributes.hasAttribute("status") && + attributes.hasAttribute("p")) { + int id = attributes.value("id").toString().toInt() - 1; + bool state = attributes.value("status").toString().toInt(); + float p = attributes.value("p").toString().toFloat(); + + gaugeState_[id] = state; + gaugeValid_[id] = true; + gaugePressure_[id] = p; + + if (attributes.hasAttribute("time")) dumpData(); + } + } + + if (dataValid_==false) { + bool valid = true; + for (int i=0;i<5;++i) { + valid &= switchStateValid_[i]; + //std::cout << switchStateValid_[i] << " "; + } + for (int i=0;i<3;++i) { + valid &= gaugeValid_[i]; + //std::cout << gaugeValid_[i] << " "; + } + //std::cout << std::endl; + + dataValid_ = valid; + } + } + } + } +} + +void Analyser::dumpData() +{ + std::cout << utime_.toTime_t(); + measurement_.uTime = utime_.toTime_t(); + measurement_.datime = TDatime(measurement_.uTime); + + for (int i=0;i<5;++i) { + std::cout << " " << switchState_[i]; + measurement_.switchState[i] = switchState_[i]; + } + for (int i=0;i<3;++i) { + std::cout << " " << gaugeState_[i] << " " << std::scientific << gaugePressure_[i]; + measurement_.gaugeState[i] = gaugeState_[i]; + measurement_.pressure[i] = gaugePressure_[i]; + } + std::cout << std::endl; + + otree_->Fill(); +} diff --git a/pumpstation/analysis/Analyser.h b/pumpstation/analysis/Analyser.h new file mode 100644 index 000000000..30ac33a54 --- /dev/null +++ b/pumpstation/analysis/Analyser.h @@ -0,0 +1,55 @@ +#ifndef ANALYSER_H +#define ANALYSER_H + +#include + +#include +#include +#include + +#include +#include +#include + +typedef struct { + unsigned int uTime; + TDatime datime; + int switchState[5]; + int gaugeState[3]; + double pressure[3]; +} Measurement_t; + +class Analyser : public QObject +{ + Q_OBJECT + +public: + + Analyser(QStringList& arguments); + +public slots: + + void analyse(); + +private: + + void processFile(const QString& filename); + void dumpData(); + + QStringList arguments_; + + QDateTime utime_; + bool dataValid_; + std::array switchState_; + std::array switchStateValid_; + std::array gaugeState_; + std::array gaugePressure_; + std::array gaugeValid_; + + bool measurementValid_; + Measurement_t measurement_; + TFile *ofile_; + TTree *otree_; +}; + +#endif // ANALYSER_H diff --git a/pumpstation/analysis/PumpStationAnalysis.cc b/pumpstation/analysis/PumpStationAnalysis.cc new file mode 100644 index 000000000..7174cd389 --- /dev/null +++ b/pumpstation/analysis/PumpStationAnalysis.cc @@ -0,0 +1,25 @@ +#include + +#include +#include +#include +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +#include +#else +#include +#endif + +#include "Analyser.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QStringList arguments = QCoreApplication::arguments(); + arguments.removeAt(0); + + Analyser analyser(arguments); + QTimer::singleShot(0, &analyser, SLOT(analyse())); + + return app.exec(); +} diff --git a/pumpstation/analysis/PumpStationAnalysis.pro.in b/pumpstation/analysis/PumpStationAnalysis.pro.in new file mode 100644 index 000000000..d50034503 --- /dev/null +++ b/pumpstation/analysis/PumpStationAnalysis.pro.in @@ -0,0 +1,85 @@ +ARCHITECTURE=@architecture@ +USEFAKEDEVICES="X@usefakedevices@" + +QMAKE_CXXFLAGS += @rootcflags@ +LIBS += @rootlibs@ + +QMAKE = @qmake@ + +macx { + CONFIG+=x86_64 + QMAKE_CXXFLAGS += -stdlib=libc++ + #QMAKE_MAC_SDK = macosx10.11 + QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11 + #LIBS += -framework AppKit + #LIBS += -framework QuartzCore + #LIBS += -framework QTKit + #LIBS += -framework Cocoa +} + +CONFIG += link_pkgconfig +PKGCONFIG += + +QMAKE_CXXFLAGS += -std=c++11 +macx { + QMAKE_CXXFLAGS += -DAPPLICATIONVERSIONSTR=\\\"unknown\\\" +} +else { + QMAKE_CXXFLAGS += -DAPPLICATIONVERSIONSTR=\\\"`git describe --dirty --always --tags`\\\" +} + +DEFINES += @configdefines@ + +equals(USEFAKEDEVICES,"X1") { +DEFINES += USE_FAKEIO +} + +QT += core xml +greaterThan(QT_MAJOR_VERSION, 4) { + QT += +} + +CONFIG += console +CONFIG -= app_bundle + +TARGET = PumpStationAnalysis +TEMPLATE = app + +macx { + #QMAKE_POST_LINK = install_name_tool -change libCommon.1.dylib @basepath@/common/libCommon.1.dylib $(TARGET) +} + +unix { + target.path = /usr/bin + target.from = PumpStationAnalysis + + INSTALLS += target +} + +DEPENDPATH += @basepath@/common +INCLUDEPATH += . +INCLUDEPATH += .. +INCLUDEPATH += @basepath@ +INCLUDEPATH += @basepath@/common + +greaterThan(QT_MAJOR_VERSION, 4) { + cache() +} + +# Input +HEADERS += Analyser.h + +equals(USEFAKEDEVICES,"X0") { +HEADERS += +} else { +HEADERS += +} + +SOURCES += PumpStationAnalysis.cc \ + Analyser.cc + +equals(USEFAKEDEVICES,"X0") { +SOURCES += +} else { +SOURCES += +} diff --git a/pumpstation/controller/Controller.cc b/pumpstation/controller/Controller.cc index 3d4721b97..2801cd81f 100644 --- a/pumpstation/controller/Controller.cc +++ b/pumpstation/controller/Controller.cc @@ -33,7 +33,7 @@ Controller::Controller(QStringList& arguments) void Controller::connectToServer() { - NQLogDebug("controller") << "void Controller::connectToServer()"; + NQLogDebug("Controller") << "void Controller::connectToServer()"; quint16 port = ApplicationConfig::instance()->getValue("ServerPort", 63432); @@ -41,7 +41,7 @@ void Controller::connectToServer() socket_->connectToHost(ipAddress, port); if (!socket_->waitForConnected(500)) { - NQLog("controller") << "The following error occurred: " << socket_->errorString().toStdString(); + NQLog("Controller") << "The following error occurred: " << socket_->errorString().toStdString(); std::cout << "ERR" << std::endl; @@ -53,7 +53,7 @@ void Controller::connectToServer() void Controller::sendCommand() { - NQLogDebug("controller") << "void Controller::sendCommand()"; + NQLogDebug("Controller") << "void Controller::sendCommand()"; QString command; for (int i=0; i> blockSize; - NQLogDebug("controller") << "blockSize = " << blockSize; + NQLogDebug("Controller") << "blockSize = " << blockSize; QString response; in >> response; - NQLogDebug("controller") << "response: (" << blockSize << ") |" << response.toStdString() << "|"; + NQLogDebug("Controller") << "response: (" << blockSize << ") |" << response.toStdString() << "|"; std::cout << response.toStdString() << std::endl; diff --git a/pumpstation/daemon/CommunicationServer.cc b/pumpstation/daemon/CommunicationServer.cc index 209d19b49..f0024d983 100644 --- a/pumpstation/daemon/CommunicationServer.cc +++ b/pumpstation/daemon/CommunicationServer.cc @@ -12,18 +12,29 @@ CommunicationServer::CommunicationServer(PumpStationModel* model, : QTcpServer(parent), model_(model) { + ApplicationConfig * config = ApplicationConfig::instance(); + + pumpChannels_ = config->getValueVector("PumpSwitches"); + valveChannels_ = config->getValueVector("ValveSwitches"); + + connect(this, SIGNAL(setSwitchBlocked(int, bool)), + model_, SLOT(setSwitchBlocked(int, bool))); + connect(this, SIGNAL(setSwitchEnabled(int, bool)), model_, SLOT(setSwitchEnabled(int, bool))); + + connect(this, SIGNAL(setPumpOperatingHours(int, double)), + model_, SLOT(setPumpOperatingHours(int, double))); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) void CommunicationServer::incomingConnection(int socketDescriptor) { - NQLogDebug("server") << "void CommunicationServer::incomingConnection(int socketDescriptor)"; + NQLogDebug("CommunicationServer") << "void CommunicationServer::incomingConnection(int socketDescriptor)"; #else void CommunicationServer::incomingConnection(qintptr socketDescriptor) { - NQLogDebug("server") << "void CommunicationServer::incomingConnection(qintptr socketDescriptor)"; + NQLogDebug("CommunicationServer") << "void CommunicationServer::incomingConnection(qintptr socketDescriptor)"; #endif socket_ = new QTcpSocket(); @@ -41,7 +52,7 @@ void CommunicationServer::incomingConnection(int socketDescriptor) void CommunicationServer::handleCommand() { - NQLogDebug("server") << "void CommunicationServer::handleCommand()"; + NQLogDebug("CommunicationServer") << "void CommunicationServer::handleCommand()"; QDataStream in(socket_); in.setVersion(QDataStream::Qt_4_0); @@ -52,14 +63,107 @@ void CommunicationServer::handleCommand() QString command; in >> command; - NQLogDebug("server") << "command: (" << blockSize << ") |" << command.toStdString() << "|"; + NQLogDebug("CommunicationServer") << "command: (" << blockSize << ") |" << command.toStdString() << "|"; QStringList args = command.split(" "); QString cmd = args.at(0); args.removeAt(0); QString response; - if (cmd=="setSwitchState") { + if (cmd=="setPumpState") { + if (args.count()!=2) { + response = "ERR"; + } else { + int pump = args.at(0).toInt(); + int state = args.at(1).toInt(); + + if (pump<1 || pump>2) { + response = "ERR"; + } else { + emit setSwitchEnabled(pumpChannels_[pump-1], state); + response = "OK"; + } + } + } else if (cmd=="getPumpState") { + if (args.count()!=1) { + response = "ERR"; + } else { + int pump = args.at(0).toInt(); + + if (pump<1 || pump>2) { + response = "ERR"; + } else { + QMutexLocker locker(&mutex_); + State state = model_->getSwitchState(pumpChannels_[pump-1]); + response = QString::number((int)state); + } + } + } else if (cmd=="setPumpOperatingHours") { + if (args.count()!=2) { + response = "ERR"; + } else { + int pump = args.at(0).toInt(); + double value = args.at(1).toDouble(); + + if (pump<1 || pump>2) { + response = "ERR"; + } else { + emit setPumpOperatingHours(pump, value); + response = "OK"; + } + } + } else if (cmd=="getPumpOperatingHours") { + if (args.count()!=0) { + response = "ERR"; + } else { + QMutexLocker locker(&mutex_); + double value1 = model_->getPumpOperatingHours(1); + double value2 = model_->getPumpOperatingHours(2); + response = QString("%1;%2").arg(value1, 0, 'f', 6).arg(value2, 0, 'f', 6); + } + } else if (cmd=="setValveState") { + if (args.count()!=2) { + response = "ERR"; + } else { + int valve = args.at(0).toInt(); + int state = args.at(1).toInt(); + + if (valve<1 || valve>3) { + response = "ERR"; + } else { + emit setSwitchEnabled(valveChannels_[valve-1], state); + response = "OK"; + } + } + } else if (cmd=="getValveState") { + if (args.count()!=1) { + response = "ERR"; + } else { + int valve = args.at(0).toInt(); + + if (valve<1 || valve>3) { + response = "ERR"; + } else { + QMutexLocker locker(&mutex_); + State state = model_->getSwitchState(valveChannels_[valve-1]); + response = QString::number((int)state); + } + } + } else if (cmd=="setSwitchState") { + if (args.count()!=2) { + response = "ERR"; + } else { + int channel = args.at(0).toInt(); + int state = args.at(1).toInt(); + + if (channel<0 || channel>4) { + response = "ERR"; + } else { + emit setSwitchEnabled(channel, state); + response = "OK"; + } + } + } else if (cmd=="setSwitchBlocked") { if (args.count()!=2) { response = "ERR"; } else { @@ -69,7 +173,7 @@ void CommunicationServer::handleCommand() if (channel<0 || channel>4) { response = "ERR"; } else { - emit setSwitchEnabled(channel, state); + emit setSwitchBlocked(channel, state); response = "OK"; } } @@ -87,6 +191,20 @@ void CommunicationServer::handleCommand() response = QString::number((int)state); } } + } else if (cmd=="getSwitchBlocked") { + if (args.count()!=1) { + response = "ERR"; + } else { + int channel = args.at(0).toInt(); + + if (channel<0 || channel>4) { + response = "ERR"; + } else { + QMutexLocker locker(&mutex_); + bool state = model_->getSwitchBlocked(channel); + response = QString::number((int)state); + } + } } else if (cmd=="getSwitchStatus") { if (args.count()!=0) { response = "ERR"; @@ -100,6 +218,26 @@ void CommunicationServer::handleCommand() int s3 = model_->getSwitchState(3); int s4 = model_->getSwitchState(4); + response = QString("%1;%2;%3;%4;%5") + .arg(s0) + .arg(s1) + .arg(s2) + .arg(s3) + .arg(s4); + } + } else if (cmd=="getSwitchBlockedStatus") { + if (args.count()!=0) { + response = "ERR"; + } else { + + QMutexLocker locker(&mutex_); + + int s0 = model_->getSwitchBlocked(0); + int s1 = model_->getSwitchBlocked(1); + int s2 = model_->getSwitchBlocked(2); + int s3 = model_->getSwitchBlocked(3); + int s4 = model_->getSwitchBlocked(4); + response = QString("%1;%2;%3;%4;%5") .arg(s0) .arg(s1) @@ -132,7 +270,7 @@ void CommunicationServer::handleCommand() } else { QMutexLocker locker(&mutex_); double pressure = model_->getPressure(sensor); - response = QString("%1").arg(pressure, 0, 'f', 1); + response = QString("%1").arg(pressure, 0, 'E', 3); } } } else if (cmd=="getVacuumStatus") { @@ -151,9 +289,9 @@ void CommunicationServer::handleCommand() double p3 = model_->getPressure(3); response = QString("%1;%2;%3;%4;%5;%6") - .arg(s1).arg(p1, 0, 'f', 1) - .arg(s2).arg(p2, 0, 'f', 1) - .arg(s3).arg(p3, 0, 'f', 1); + .arg(s1).arg(p1, 0, 'E', 3) + .arg(s2).arg(p2, 0, 'E', 3) + .arg(s3).arg(p3, 0, 'E', 3); } } else { response = "ERR"; diff --git a/pumpstation/daemon/CommunicationServer.h b/pumpstation/daemon/CommunicationServer.h index deca4186f..d69d5de79 100644 --- a/pumpstation/daemon/CommunicationServer.h +++ b/pumpstation/daemon/CommunicationServer.h @@ -1,6 +1,8 @@ #ifndef COMMUNICATIONSERVER_H #define COMMUNICATIONSERVER_H +#include + #include #include #include @@ -23,6 +25,8 @@ protected slots: signals: void setSwitchEnabled(int channel, bool enabled); + void setSwitchBlocked(int channel, bool blocked); + void setPumpOperatingHours(int, double); protected: @@ -34,6 +38,9 @@ protected slots: PumpStationModel* model_; + std::vector pumpChannels_; + std::vector valveChannels_; + QTcpSocket* socket_; QMutex mutex_; }; diff --git a/pumpstation/daemon/DataLogger.cc b/pumpstation/daemon/DataLogger.cc index f19b64537..6fa6301cc 100644 --- a/pumpstation/daemon/DataLogger.cc +++ b/pumpstation/daemon/DataLogger.cc @@ -1,5 +1,11 @@ +#include +#include +#include +#include + #include +#include #include #include #include @@ -9,14 +15,44 @@ #include "DataLogger.h" +int DataLogger::sighupFd[2]; +int DataLogger::sigintFd[2]; +int DataLogger::sigtermFd[2]; + DataLogger::DataLogger(PumpStationModel* model, + CommunicationThread* thread, QObject *parent) : QObject(parent), model_(model), + thread_(thread), isStreaming_(false), ofile_(0), stream_(0) { + connect(model_, SIGNAL(dataValid()), + this, SLOT(initialize())); +} + +void DataLogger::initialize() +{ + NQLog("DataLogger") << "initialize"; + + if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd)) + qFatal("Couldn't create HUP socketpair"); + + if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd)) + qFatal("Couldn't create HUP socketpair"); + + if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd)) + qFatal("Couldn't create TERM socketpair"); + + snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this); + connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup())); + snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this); + connect(snInt, SIGNAL(activated(int)), this, SLOT(handleSigInt())); + snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this); + connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm())); + connect(model_, SIGNAL(switchStateChanged(int, State)), this, SLOT(switchStateChanged(int, State))); @@ -30,12 +66,16 @@ DataLogger::DataLogger(PumpStationModel* model, statusTimer_ = new QTimer(); connect(statusTimer_, SIGNAL(timeout()), this, SLOT(writeStatus())); + + start(); } void DataLogger::start() { if (isStreaming_) return; + NQLog("DataLogger") << "start"; + QDateTime dt = QDateTime::currentDateTime(); ApplicationConfig* config = ApplicationConfig::instance(); @@ -72,12 +112,21 @@ void DataLogger::start() */ } - stream_ = new QTextStream(ofile_); + //stream_ = new QTextStream(ofile_); + + xml_ = new QXmlStreamWriter(ofile_); + xml_->setAutoFormatting(true); isStreaming_ = true; fileDateTime_ = dt; + QString buffer; + xml_->writeStartDocument(); + + xml_->writeStartElement("PumpStationLog"); + xml_->writeAttribute("time", dt.toString(Qt::ISODate)); + writeStatus(); restartTimer_->start(60000); @@ -88,14 +137,20 @@ void DataLogger::stop() { if (!isStreaming_) return; + NQLog("DataLogger") << "stop"; + statusTimer_->stop(); restartTimer_->stop(); writeStatus(); - stream_->device()->close(); + xml_->writeEndElement(); + xml_->writeEndDocument(); + + //stream_->device()->close(); delete ofile_; - delete stream_; + delete xml_; + //delete stream_; isStreaming_ = false; } @@ -118,28 +173,27 @@ void DataLogger::writeStatus() QDateTime utime = QDateTime::currentDateTime(); - QString buffer; - QXmlStreamWriter xml(&buffer); - xml.setAutoFormatting(true); + xml_->writeStartElement("Status"); + xml_->writeAttribute("time", utime.toString(Qt::ISODate)); for (int i=0;i<5;++i) { - xml.writeStartElement("ConradSwitch"); - xml.writeAttribute("time", utime.toString(Qt::ISODate)); - xml.writeAttribute("id", QString::number(i)); - xml.writeAttribute("state", QString::number((int)model_->getSwitchState(i))); - xml.writeEndElement(); + xml_->writeStartElement("ConradSwitch"); + xml_->writeAttribute("id", QString::number(i)); + xml_->writeAttribute("state", QString::number((int)model_->getSwitchState(i))); + xml_->writeEndElement(); } for (int i=1;i<4;++i) { - xml.writeStartElement("LeyboldGraphixThree"); - xml.writeAttribute("time", utime.toString(Qt::ISODate)); - xml.writeAttribute("id", QString::number(i)); - xml.writeAttribute("status", QString::number(model_->getSensorStatus(i))); - xml.writeAttribute("p", QString::number(model_->getPressure(i), 'e', 6)); - xml.writeEndElement(); + xml_->writeStartElement("LeyboldGraphixThree"); + xml_->writeAttribute("id", QString::number(i)); + xml_->writeAttribute("status", QString::number(model_->getSensorStatus(i))); + xml_->writeAttribute("p", QString::number(model_->getPressure(i), 'e', 6)); + xml_->writeEndElement(); } - writeToStream(buffer); + xml_->writeEndElement(); + + ofile_->flush(); } void DataLogger::switchStateChanged(int device, State newState) @@ -148,43 +202,35 @@ void DataLogger::switchStateChanged(int device, State newState) QMutexLocker locker(&mutex_); - NQLogMessage("logger") << "void DataLogger::switchStateChanged(" << device << ", " << (int)newState << ")"; + NQLogDebug("logger") << "void DataLogger::switchStateChanged(" << device << ", " << (int)newState << ")"; QDateTime utime = QDateTime::currentDateTime(); - QString buffer; - QXmlStreamWriter xml(&buffer); - xml.setAutoFormatting(true); - - xml.writeStartElement("ConradSwitch"); - xml.writeAttribute("time", utime.toString(Qt::ISODate)); - xml.writeAttribute("id", QString::number(device)); - xml.writeAttribute("state", QString::number((int)newState)); - xml.writeEndElement(); + xml_->writeStartElement("ConradSwitch"); + xml_->writeAttribute("time", utime.toString(Qt::ISODate)); + xml_->writeAttribute("id", QString::number(device)); + xml_->writeAttribute("state", QString::number((int)newState)); + xml_->writeEndElement(); - writeToStream(buffer); + ofile_->flush(); } void DataLogger::pressureChanged(int sensor, double p) { QMutexLocker locker(&mutex_); - NQLogMessage("logger") << "void DataLogger::pressureChanged(" << sensor << ", " << p << ")"; + NQLogDebug("logger") << "void DataLogger::pressureChanged(" << sensor << ", " << p << ")"; QDateTime utime = QDateTime::currentDateTime(); - QString buffer; - QXmlStreamWriter xml(&buffer); - xml.setAutoFormatting(true); - - xml.writeStartElement("LeyboldGraphixThree"); - xml.writeAttribute("time", utime.toString(Qt::ISODate)); - xml.writeAttribute("id", QString::number(sensor)); - xml.writeAttribute("status", QString::number(model_->getSensorStatus(sensor))); - xml.writeAttribute("p", QString::number(p, 'e', 6)); - xml.writeEndElement(); + xml_->writeStartElement("LeyboldGraphixThree"); + xml_->writeAttribute("time", utime.toString(Qt::ISODate)); + xml_->writeAttribute("id", QString::number(sensor)); + xml_->writeAttribute("status", QString::number(model_->getSensorStatus(sensor))); + xml_->writeAttribute("p", QString::number(p, 'e', 6)); + xml_->writeEndElement(); - writeToStream(buffer); + ofile_->flush(); } void DataLogger::writeToStream(QString& buffer) @@ -198,3 +244,64 @@ void DataLogger::writeToStream(QString& buffer) stream_->flush(); } } + +void DataLogger::hupSignalHandler(int) +{ + char a = 1; + ::write(sighupFd[0], &a, sizeof(a)); +} + +void DataLogger::intSignalHandler(int) +{ + char a = 1; + ::write(sigintFd[0], &a, sizeof(a)); +} + +void DataLogger::termSignalHandler(int) +{ + char a = 1; + ::write(sigtermFd[0], &a, sizeof(a)); +} + +void DataLogger::handleSigHup() +{ + snHup->setEnabled(false); + char tmp; + ::read(sighupFd[1], &tmp, sizeof(tmp)); + + // std::cout << "handleSigHup()" << std::endl; + + snHup->setEnabled(true); +} + +void DataLogger::handleSigInt() +{ + snInt->setEnabled(false); + char tmp; + ::read(sigintFd[1], &tmp, sizeof(tmp)); + + // std::cout << "handleSigInt()" << std::endl; + + stop(); + + thread_->quit(); + thread_->wait(); + + ApplicationConfig * config = ApplicationConfig::instance(); + config->safe(std::string(Config::CMSTkModLabBasePath) + "/pumpstation/pumpstation.cfg"); + + QCoreApplication::exit(0); + + snInt->setEnabled(true); +} + +void DataLogger::handleSigTerm() +{ + snTerm->setEnabled(false); + char tmp; + ::read(sigtermFd[1], &tmp, sizeof(tmp)); + + // std::cout << "handleSigTerm()" << std::endl; + + snTerm->setEnabled(true); +} diff --git a/pumpstation/daemon/DataLogger.h b/pumpstation/daemon/DataLogger.h index 959e534ca..c7129f188 100644 --- a/pumpstation/daemon/DataLogger.h +++ b/pumpstation/daemon/DataLogger.h @@ -7,8 +7,11 @@ #include #include #include +#include +#include #include +#include class DataLogger : public QObject { @@ -16,12 +19,25 @@ class DataLogger : public QObject public: - DataLogger(PumpStationModel* model, + DataLogger(PumpStationModel* model, CommunicationThread* thread, QObject *parent = 0); + // Unix signal handlers. + static void hupSignalHandler(int unused); + static void intSignalHandler(int unused); + static void termSignalHandler(int unused); + +public slots: + + void initialize(); void start(); void stop(); + // Qt signal handlers. + void handleSigHup(); + void handleSigInt(); + void handleSigTerm(); + protected slots: void switchStateChanged(int device, State newState); @@ -33,18 +49,30 @@ protected slots: protected: PumpStationModel* model_; + CommunicationThread* thread_; QMutex mutex_; bool isStreaming_; QString ofilename_; QFile* ofile_; QTextStream* stream_; + QXmlStreamWriter* xml_; QDir currentDir_; QDateTime fileDateTime_; QTimer* restartTimer_; QTimer* statusTimer_; void writeToStream(QString& buffer); + +private: + + static int sighupFd[2]; + static int sigintFd[2]; + static int sigtermFd[2]; + + QSocketNotifier *snHup; + QSocketNotifier *snInt; + QSocketNotifier *snTerm; }; #endif // DATALOGGER_H diff --git a/pumpstation/daemon/PumpStationDaemon.cc b/pumpstation/daemon/PumpStationDaemon.cc index 86a3a11e1..687c7d3de 100644 --- a/pumpstation/daemon/PumpStationDaemon.cc +++ b/pumpstation/daemon/PumpStationDaemon.cc @@ -1,3 +1,5 @@ +#include + #include #include @@ -17,18 +19,56 @@ #include #include #include +#include #include "PumpStationModel.h" #include "CommunicationThread.h" +static int setup_unix_signal_handlers() +{ + /* + struct sigaction sighup; + sighup.sa_handler = DataLogger::hupSignalHandler; + sigemptyset(&sighup.sa_mask); + sighup.sa_flags = 0; + sighup.sa_flags |= SA_RESTART; + + if (sigaction(SIGHUP, &sighup, 0)) + return 1; + */ + + struct sigaction sigint; + sigint.sa_handler = DataLogger::intSignalHandler; + sigemptyset(&sigint.sa_mask); + sigint.sa_flags = 0; + sigint.sa_flags |= SA_RESTART; + + if (sigaction(SIGINT, &sigint, 0)) + return 2; + + /* + struct sigaction sigterm; + sigterm.sa_handler = DataLogger::termSignalHandler; + sigemptyset(&sigterm.sa_mask); + sigterm.sa_flags |= SA_RESTART; + + if (sigaction(SIGTERM, &sigterm, 0)) + return 3; + */ + + return 0; +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + setup_unix_signal_handlers(); + if (app.arguments().contains("--nodaemon")) { NQLogger::instance()->addActiveModule("*"); - NQLogger::instance()->addDestiniation(stdout, NQLog::Debug); + NQLogger::instance()->addDestiniation(stdout, NQLog::Spam); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QString logdir = QDesktopServices::storageLocation(QDesktopServices::CacheLocation); @@ -57,11 +97,12 @@ int main(int argc, char *argv[]) qRegisterMetaType("State"); ApplicationConfig * config = ApplicationConfig::instance(std::string(Config::CMSTkModLabBasePath) + "/pumpstation/pumpstation.cfg"); - - ConradModel conrad(&app); + + std::string conradPort = config->getValue("ConradPort"); + ConradModel conrad(conradPort.c_str(), &app); std::string leyboldPort = config->getValue("LeyboldPort"); - LeyboldGraphixThreeModel leybold(leyboldPort.c_str(), 5, &app); + LeyboldGraphixThreeModel leybold(leyboldPort.c_str(), config->getValue("LeyboldUpdateInterval"), &app); /* if (leybold.getSensorDetectionMode(1)!=VLeyboldGraphixThree::SensorDetectionAuto) { @@ -96,11 +137,14 @@ int main(int argc, char *argv[]) PumpStationModel model(&conrad, &leybold, 5, &app); - DataLogger logger(&model, &app); - logger.start(); - CommunicationThread commthread(&model, &app); commthread.start(); + DataLogger logger(&model, &commthread, &app); + logger.initialize(); + + WatchDog watchdog(&model, 300/5, &app); + watchdog.initialize(); + return app.exec(); } diff --git a/pumpstation/daemon/PumpStationDaemon.pro.in b/pumpstation/daemon/PumpStationDaemon.pro.in index 51955280e..a85a9f2bb 100644 --- a/pumpstation/daemon/PumpStationDaemon.pro.in +++ b/pumpstation/daemon/PumpStationDaemon.pro.in @@ -74,7 +74,8 @@ greaterThan(QT_MAJOR_VERSION, 4) { HEADERS += PumpStationModel.h \ CommunicationThread.h \ CommunicationServer.h \ - DataLogger.h + DataLogger.h \ + WatchDog.h equals(USEFAKEDEVICES,"X0") { HEADERS += @@ -86,7 +87,8 @@ SOURCES += PumpStationDaemon.cc \ PumpStationModel.cc \ CommunicationThread.cc \ CommunicationServer.cc \ - DataLogger.cc + DataLogger.cc \ + WatchDog.cc equals(USEFAKEDEVICES,"X0") { SOURCES += diff --git a/pumpstation/daemon/PumpStationModel.cc b/pumpstation/daemon/PumpStationModel.cc index 330f86f67..7b980a08b 100644 --- a/pumpstation/daemon/PumpStationModel.cc +++ b/pumpstation/daemon/PumpStationModel.cc @@ -1,5 +1,7 @@ #include +#include + #include #include "PumpStationModel.h" @@ -11,26 +13,56 @@ PumpStationModel::PumpStationModel(ConradModel* conradModel, : QObject(), conradModel_(conradModel), leyboldModel_(leyboldModel), + conradDataValid_(false), + leyboldDataValid_(false), + dataValid_(false), updateInterval_(updateInterval) { - for (int i=0;i<3;i++) sensorStatus_[i] = LeyboldGraphixThree_t::SensorStatus_unknown; - for (int i=0;i<3;i++) pressure_[i] = -999; + ApplicationConfig * config = ApplicationConfig::instance(); + + pumpChannels_ = config->getValueVector("PumpSwitches"); + valveChannels_ = config->getValueVector("ValveSwitches"); + pumpOperatingHours_[1] = config->getValue("Pump1OperatingHours"); + pumpOperatingHours_[2] = config->getValue("Pump2OperatingHours"); + + for (int i=0;i<5;++i) { + switchBlocked_[i] = true; + switchState_[i] = OFF; + } + + for (int i=0;i<3;i++) { + sensorStatus_[i] = LeyboldGraphixThree_t::SensorStatus_unknown; + pressure_[i] = 0; + } connect(leyboldModel_, SIGNAL(informationChanged()), this, SLOT(updateInformation())); timer_ = new QTimer(this); timer_->setInterval(updateInterval_ * 1000); - connect( timer_, SIGNAL(timeout()), this, SLOT(updateConrad()) ); + connect(timer_, SIGNAL(timeout()), this, SLOT(updateConrad())); timer_->start(); + pump1timer_ = new QTimer(this); + pump1timer_->setInterval(30 * 1000); + connect(pump1timer_, SIGNAL(timeout()), this, SLOT(pump1HeartBeat())); + + pump2timer_ = new QTimer(this); + pump2timer_->setInterval(30 * 1000); + connect(pump2timer_, SIGNAL(timeout()), this, SLOT(pump2HeartBeat())); + updateInformation(); updateConrad(); NQLog("PumpStationModel") << "constructed"; } +bool PumpStationModel::getSwitchBlocked(int channel) const +{ + return switchBlocked_[channel]; +} + const State& PumpStationModel::getSwitchState( int channel ) const { return switchState_[channel]; @@ -53,8 +85,15 @@ int PumpStationModel::getSensorStatus(int sensor) const return (int)sensorStatus_[sensor-1]; } +void PumpStationModel::setSwitchBlocked(int channel, bool blocked) +{ + switchBlocked_[channel] = blocked; +} + void PumpStationModel::setSwitchEnabled(int channel, bool enabled) { + // if (switchBlocked_[channel]) return; + conradModel_->setSwitchEnabled(channel, enabled); if (enabled) { @@ -91,11 +130,20 @@ void PumpStationModel::updateInformation() } pressure[i] = leyboldModel_->getPressure(i+1); + if (pressure_[i] != pressure[i]) { pressure_[i] = pressure[i]; emit pressureChanged(i+1, pressure_[i]); } } + + leyboldDataValid_ = true; + if (!dataValid_) { + if (conradDataValid_) { + dataValid_ = true; + emit dataValid(); + } + } } void PumpStationModel::updateConrad() @@ -112,9 +160,62 @@ void PumpStationModel::updateConrad() for (int i=0;i<5;++i) { switchState[i] = conradModel_->getSwitchState(i); if (switchState_[i] != switchState[i]) { + + if (i==pumpChannels_[0]) { // pump 1 + if (switchState[i]==OFF) { + pump1timer_->stop(); + } else if (switchState[i]==READY) { + pump1timer_->start(); + } + } + + if (i==pumpChannels_[1]) { // pump 1 + if (switchState[i]==OFF) { + pump2timer_->stop(); + } else if (switchState[i]==READY) { + pump2timer_->start(); + } + } + emit switchStateChanged(i, switchState[i]); } } switchState_ = switchState; + + conradDataValid_ = true; + if (!dataValid_) { + if (leyboldDataValid_) { + dataValid_ = true; + emit dataValid(); + } + } +} + +double PumpStationModel::getPumpOperatingHours(int pump) const +{ + if (pump<1 || pump>2) return 0; + return pumpOperatingHours_[pump]; +} + +void PumpStationModel::setPumpOperatingHours(int pump, double value) +{ + if (pump<1 || pump>2) return; + pumpOperatingHours_[pump] = value; +} + +void PumpStationModel::pump1HeartBeat() +{ + pumpOperatingHours_[1] += 30. / 3600.; + + ApplicationConfig * config = ApplicationConfig::instance(); + config->setValue("Pump1OperatingHours", pumpOperatingHours_[1]); +} + +void PumpStationModel::pump2HeartBeat() +{ + pumpOperatingHours_[2] += 30. / 3600.; + + ApplicationConfig * config = ApplicationConfig::instance(); + config->setValue("Pump2OperatingHours", pumpOperatingHours_[2]); } diff --git a/pumpstation/daemon/PumpStationModel.h b/pumpstation/daemon/PumpStationModel.h index 5b008db08..2819d6f5a 100644 --- a/pumpstation/daemon/PumpStationModel.h +++ b/pumpstation/daemon/PumpStationModel.h @@ -2,6 +2,7 @@ #define PUMPSTATIONMODEL_H #include +#include #include @@ -19,37 +20,57 @@ class PumpStationModel : public QObject double updateInterval = 5, QObject *parent = 0); + bool getSwitchBlocked(int channel) const; const State& getSwitchState(int channel) const; std::string getSensorName(int sensor) const; int getSensorStatus(int sensor) const; double getPressure(int sensor) const; + double getPumpOperatingHours(int pump) const; + public slots: + void setSwitchBlocked(int, bool); void setSwitchEnabled(int, bool); + void setPumpOperatingHours(int, double); protected slots: void updateInformation(); void updateConrad(); + void pump1HeartBeat(); + void pump2HeartBeat(); + protected: ConradModel* conradModel_; LeyboldGraphixThreeModel* leyboldModel_; - + bool conradDataValid_; + bool leyboldDataValid_; + bool dataValid_; + /// Time interval between cache refreshes; in seconds. const double updateInterval_; QTimer* timer_; + QTimer* pump1timer_; + QTimer* pump2timer_; + + std::array switchBlocked_; std::array switchState_; std::array sensorStatus_; std::array pressure_; + std::vector pumpChannels_; + std::vector valveChannels_; + std::array pumpOperatingHours_; + signals: + void dataValid(); void switchStateChanged(int,State); void pressureChanged(int,double); void sensorStatusChanged(int,int); diff --git a/pumpstation/daemon/WatchDog.cc b/pumpstation/daemon/WatchDog.cc new file mode 100644 index 000000000..7bbea069d --- /dev/null +++ b/pumpstation/daemon/WatchDog.cc @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "WatchDog.h" + +WatchDog::WatchDog(PumpStationModel* model, + int history, + QObject *parent) + : QObject(parent), + model_(model), + pressure1_(HistoryFifo(history)), + pressure2_(HistoryFifo(history)), + pressure3_(HistoryFifo(history)) +{ + connect(model_, SIGNAL(dataValid()), + this, SLOT(initialize())); +} + +void WatchDog::initialize() +{ + connect(model_, SIGNAL(switchStateChanged(int, State)), + this, SLOT(switchStateChanged(int, State))); + + connect(model_, SIGNAL(pressureChanged(int,double)), + this, SLOT(pressureChanged(int,double))); + + connect(this, SIGNAL(setSwitchBlocked(int, bool)), + model_, SLOT(setSwitchBlocked(int, bool))); + + connect(this, SIGNAL(setSwitchEnabled(int, bool)), + model_, SLOT(setSwitchEnabled(int, bool))); + +} + +void WatchDog::switchStateChanged(int device, State newState) +{ + if (newState!=OFF && newState!=READY) return; + + QMutexLocker locker(&mutex_); + + NQLogDebug("watchdog") << "void WatchDog::switchStateChanged(" << device << ", " << (int)newState << ")"; + + switchState_[device] = newState; + + checkValues(); +} + +void WatchDog::pressureChanged(int sensor, double p) +{ + QMutexLocker locker(&mutex_); + + NQLogDebug("watchdog") << "void DataLogger::pressureChanged(" << sensor << ", " << p << ")"; + + switch (sensor) { + case 1: + pressure1_.push(p); + break; + case 2: + pressure2_.push(p); + break; + case 3: + pressure3_.push(p); + break; + } + + checkValues(); +} + +void WatchDog::checkValues() +{ + NQLogDebug("WatchDog") << "checkValues"; + + for (int i=0;i<5;++i) { + if (model_->getSwitchBlocked(i)) { + emit setSwitchBlocked(i, false); + } + } +} diff --git a/pumpstation/daemon/WatchDog.h b/pumpstation/daemon/WatchDog.h new file mode 100644 index 000000000..d63e2110e --- /dev/null +++ b/pumpstation/daemon/WatchDog.h @@ -0,0 +1,56 @@ +#ifndef WATCHDOG_H +#define WATCHDOG_H + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +class WatchDog : public QObject +{ + Q_OBJECT + +public: + + WatchDog(PumpStationModel* model, + int history, + QObject *parent = 0); + +public slots: + + void initialize(); + +protected slots: + + void switchStateChanged(int device, State newState); + void pressureChanged(int sensor, double p); + +protected: + + void checkValues(); + + PumpStationModel* model_; + + QMutex mutex_; + + std::array switchState_; + HistoryFifo pressure1_; + HistoryFifo pressure2_; + HistoryFifo pressure3_; + +signals: + + void setSwitchEnabled(int channel, bool enabled); + void setSwitchBlocked(int channel, bool blocked); +}; + +#endif // WATCHDOG_H + diff --git a/pumpstation/data/.gitignore b/pumpstation/data/.gitignore new file mode 100644 index 000000000..6722cd96e --- /dev/null +++ b/pumpstation/data/.gitignore @@ -0,0 +1 @@ +*.xml diff --git a/pumpstation/pumpstation.cfg.in b/pumpstation/pumpstation.cfg.in index 4ea4e2370..bd1ce64c4 100644 --- a/pumpstation/pumpstation.cfg.in +++ b/pumpstation/pumpstation.cfg.in @@ -1,4 +1,16 @@ -ServerPort 63432 -DataPath @basepath@/pumpstation -LeyboldPort /dev/ttyUSB0 -URL http://cmsvakusaug.desy.de +ServerPort 63432 +DataPath @basepath@/pumpstation/data +LeyboldPort /dev/ttyLeybold +ConradPort /dev/ttyConrad +URL http://cmsvakusaug.desy.de +LeyboldUpdateInterval 1 + +PumpSwitches 0 1 +ValveSwitches 2 4 3 + +Pump1OperatingHours 1.3456 +Pump2OperatingHours 2.6789 + +slackwebhook https://hooks.slack.com/services/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 +slackusername pumpstation +slackchannel #daf_25c diff --git a/pumpstation/udev_99-usb-serial.rules b/pumpstation/udev_99-usb-serial.rules new file mode 100644 index 000000000..9e101148e --- /dev/null +++ b/pumpstation/udev_99-usb-serial.rules @@ -0,0 +1,2 @@ +SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SYMLINK+="ttyLeybold" +SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="ttyConrad" diff --git a/pumpstation/website/ConradSwitch.php b/pumpstation/website/ConradSwitch.php index 97510424b..a663d9e0a 100644 --- a/pumpstation/website/ConradSwitch.php +++ b/pumpstation/website/ConradSwitch.php @@ -1,29 +1,31 @@ -= 0) ) { - - $ini_array = parse_ini_file("pumpstation.ini"); - - $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState ".$channel; - exec ($command, $status, $return); - - if ($status[0] == "0" ) { - $status[0] = "1"; - } else if ($status[0] == "1" ) { - $status[0] = "0"; - } - - $command = $ini_array['DocumentRoot']."/PumpStationControl --web setSwitchState ".$channel." ".$status[0]; - exec ($command, $status, $return); - - echo($status[0]); - - } else { - echo("fail"); - } -} else { - echo("fail"); -} += 0)) { + + $ini_array = parse_ini_file ( "pumpstation.ini" ); + + $command = $ini_array ['DocumentRoot'] . "/PumpStationControl --web getSwitchState " . $channel; + exec ( $command, $status, $return ); + + if ($status [0] == "0") { + $status [0] = "1"; + } else if ($status [0] == "1") { + $status [0] = "0"; + } + + $command = $ini_array ['DocumentRoot'] . "/PumpStationControl --web setSwitchState " . $channel . " " . $status [0]; + exec ( $command, $status, $return ); + + $command = $ini_array ['DocumentRoot'] . "/PumpStationControl --web getSwitchState " . $channel; + exec ( $command, $status, $return ); + + echo ($status [0]); + } else { + echo ("fail"); + } +} else { + echo ("fail"); +} ?> diff --git a/pumpstation/website/data/pumpstation_schematic.png b/pumpstation/website/data/pumpstation_schematic.png index 7dc5c723c..d37062a71 100644 Binary files a/pumpstation/website/data/pumpstation_schematic.png and b/pumpstation/website/data/pumpstation_schematic.png differ diff --git a/pumpstation/website/index.php b/pumpstation/website/index.php index dd167bcd5..12131a21e 100644 --- a/pumpstation/website/index.php +++ b/pumpstation/website/index.php @@ -27,12 +27,8 @@ } - - - - .: CMS Pump Station Status & Control :. - - + +
@@ -40,219 +36,233 @@
- = 200.0 || $P1 < 0.0) { - echo ('
'); - } else if ($P1 < 150.0 ) { - echo ('
'); - } else { - echo ('
'); - } - echo ('
'); - echo (number_format($P1, 1, ".", ",")); - echo (" mbar"); - echo ('
'); - - # $command = $ini_array['DocumentRoot']."/PumpStationControl --web getPressure 2"; - # exec ($command, $valP2, $return); - # if (is_array($valP2)) { - # $P2 = floatval($valP2[0]); - # } else { - # $P2 = floatval($valP2); - # } - if ($P2 >= 200.0 || $P2 < 0.0) { - echo ('
'); - } else if ($P2 < 150.0 ) { - echo ('
'); - } else { - echo ('
'); - } - echo ('
'); - echo (number_format($P2, 1, ".", ",")); - echo (" mbar"); - echo ('
'); - - # $command = $ini_array['DocumentRoot']."/PumpStationControl --web getPressure 3"; - # exec ($command, $valP3, $return); - # if (is_array($valP3)) { - # $P3 = floatval($valP3[0]); - # } else { - # $P3 = floatval($valP3); - # } - if ($P3 >= 200.0 || $P3 < 0.0) { - echo ('
'); - } else if ($P3 < 150.0 ) { - echo ('
'); - } else { - echo ('
'); - } - echo ('
'); - echo (number_format($P3, 1, ".", ",")); - echo (" mbar"); - echo ('
'); - - $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchStatus"; - exec ($command, $valSS, $return); - if (is_array($valSS)) { - $SS = $valSS[0]; - } else { - $SS = $valSS; - } - list($valS0, $valS1, $valS2, $valS3, $valS4) = explode(";", $SS); - - $S0 = intval($valS0); - $S1 = intval($valS1); - $S2 = intval($valS2); - $S3 = intval($valS3); - $S4 = intval($valS4); - - # $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState 0"; - # exec ($command, $valS0, $return); - # if (is_array($valS0)) { - # $S0 = boolval($valS0[0]); - # } else { - # $S0 = boolval($valS0); - # } - if ($S0 == 0 ) { - echo ('
'); - } else if ($S0 == 1 ) { - echo ('
'); - } - echo ('
'); - if ($S0 == 0 ) { - echo ("closed"); - } else if ($S0 == 1 ) { - echo ("open"); - } else { - echo ("XXX"); - } - echo ("
"); - - # $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState 1"; - # exec ($command, $valS1, $return); - # if (is_array($valS1)) { - # $S1 = boolval($valS1[0]); - # } else { - # $S1 = boolval($valS1); - # } - if ($S1 == 0 ) { - echo ('
'); - } else if ($S1 == 1 ) { - echo ('
'); - } - echo ('
'); - if ($S1 == 0 ) { - echo ("closed"); - } else if ($S1 == 1 ) { - echo ("open"); - } else { - echo ("XXX"); - } - echo ("
"); += 200.0 || $P1 < 0.0) { + echo ('
'); +} else if ($P1 < 150.0) { + echo ('
'); +} else { + echo ('
'); +} +echo ('
'); +if ($P1 >= 10.0) { + printf ( "%.0f", $P1); +} else if ($P1 >= 0.1) { + printf ( "%.1f", $P1); +} else { + printf ( "%.2E", $P1); +} +echo (" mbar"); +echo ('
'); + +// $command = $ini_array['DocumentRoot']."/PumpStationControl --web getPressure 2"; +// exec ($command, $valP2, $return); +// if (is_array($valP2)) { +// $P2 = floatval($valP2[0]); +// } else { +// $P2 = floatval($valP2); +// } +if ($P2 >= 200.0 || $P2 < 0.0) { + echo ('
'); +} else if ($P2 < 150.0) { + echo ('
'); +} else { + echo ('
'); +} +echo ('
'); +if ($P2 >= 10.0) { + printf ( "%.0f", $P2); +} else if ($P2 >= 0.1) { + printf ( "%.1f", $P2); +} else { + printf ( "%.2E", $P2); +} +echo (" mbar"); +echo ('
'); + +// $command = $ini_array['DocumentRoot']."/PumpStationControl --web getPressure 3"; +// exec ($command, $valP3, $return); +// if (is_array($valP3)) { +// $P3 = floatval($valP3[0]); +// } else { +// $P3 = floatval($valP3); +// } +if ($P3 >= 200.0 || $P3 < 0.0) { + echo ('
'); +} else if ($P3 < 150.0) { + echo ('
'); +} else { + echo ('
'); +} +echo ('
'); +if ($P3 >= 10.0) { + printf ( "%.0f", $P3); +} else if ($P3 >= 0.1) { + printf ( "%.1f", $P3); +} else { + printf ( "%.2E", $P3); +} +echo (" mbar"); +echo ('
'); + +$command = $ini_array ['DocumentRoot'] . "/PumpStationControl --web getSwitchStatus"; +exec ( $command, $valSS, $return ); +if (is_array ( $valSS )) { + $SS = $valSS [0]; +} else { + $SS = $valSS; +} +list ( $valS0, $valS1, $valS2, $valS3, $valS4 ) = explode ( ";", $SS ); + +$Pump1State = intval ( $valS0 ); +$Pump2State = intval ( $valS1 ); +$Valve1State = intval ( $valS2 ); +$Valve2State= intval ( $valS3 ); +$Valve3State= intval ( $valS4 ); - # $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState 2"; - # exec ($command, $valS2, $return); - # if (is_array($valS2)) { - # $S2 = boolval($valS2[0]); - # } else { - # $S2 = boolval($valS2); - # } - if ($S2 == 0 ) { - echo ('
'); - } else if ($S2 == 1 ) { - echo ('
'); - } - echo ('
'); - if ($S2 == 0 ) { - echo ("closed"); - } else if ($S2 == 1 ) { - echo ("open"); - } else { - echo ("XXX"); - } - echo ("
"); - - # $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState 3"; - # exec ($command, $valS3, $return); - # if (is_array($valS3)) { - # $S3 = boolval($valS3[0]); - # } else { - # $S3 = boolval($valS3); - # } - if ($S3 == 0 ) { - echo ('
'); - } else if ($S3 == 1 ) { - echo ('
'); - } - echo ('
'); - if ($S3 == 0 ) { - echo ("OFF"); - } else if ($S3 == 1 ) { - echo ("ON"); - } else { - echo ("XXX"); - } - echo ("
"); - - # $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState 4"; - # exec ($command, $valS4, $return); - # if (is_array($valS4)) { - # $S4 = boolval($valS4[0]); - # } else { - # $S4 = boolval($valS4); - # } - if ($S4 == 0 ) { - echo ('
'); - } else if ($S4 == 1 ) { - echo ('
'); - } - echo ('
'); - if ($S4 == 0 ) { - echo ("OFF"); - } else if ($S4 == 1 ) { - echo ("ON"); - } else { - echo ("XXX"); - } - echo ("
"); - ?> +$command = $ini_array ['DocumentRoot'] . "/PumpStationControl --web getPumpOperatingHours"; +exec ( $command, $valOH, $return ); +if (is_array ( $valOH )) { + $OH = $valOH [0]; +} else { + $OH = $valOH; +} +list ( $valOH1, $valOH2 ) = explode ( ";", $OH ); + +// $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState " . $ini_array['Valve1Switch']; +// exec ($command, $valV1, $return); +// if (is_array($valV1)) { +// $Valve1State= boolval($valV1[0]); +// } else { +// $Valve1State= boolval($valV1); +// } +if ($Valve1State== 0) { + echo ('
'); +} else if ($Valve1State== 1) { + echo ('
'); +} +echo ('
'); +if ($Valve1State== 0) { + echo ("closed"); +} else if ($Valve1State== 1) { + echo ("open"); +} else { + echo ("XXX"); +} +echo ("
"); + +// $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState " . $ini_array['Valve2Switch']; +// exec ($command, $valV2, $return); +// if (is_array($valV2)) { +// $Valve2State= boolval($valV2[0]); +// } else { +// $Valve2State= boolval($valV2); +// } +if ($Valve2State== 0) { + echo ('
'); +} else if ($S1 == 1) { + echo ('
'); +} +echo ('
'); +if ($Valve2State== 0) { + echo ("closed"); +} else if ($Valve2State== 1) { + echo ("open"); +} else { + echo ("XXX"); +} +echo ("
"); + +// $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState " . $ini_array['Valve3Switch']; +// exec ($command, $valV3, $return); +// if (is_array($valV3)) { +// $Valve3State= boolval($valV3[0]); +// } else { +// $Valve3State= boolval($valV3); +// } +if ($Valve3State== 0) { + echo ('
'); +} else if ($Valve3State== 1) { + echo ('
'); +} +echo ('
'); +if ($Valve3State== 0) { + echo ("closed"); +} else if ($Valve3State== 1) { + echo ("open"); +} else { + echo ("XXX"); +} +echo ("
"); + +// $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState " . $ini_array['Pump2Switch']; +// exec ($command, $valP2, $return); +// if (is_array($valP2)) { +// $Pump2State= boolval($valP2[0]); +// } else { +// $Pump2State= boolval($valP2); +// } +if ($Pump2State== 0) { + echo ('
'); +} else if ($Pump2State== 1) { + echo ('
'); +} +echo ('
'); +printf ( "%.2f h", $valOH2 ); +echo ("
"); + +// $command = $ini_array['DocumentRoot']."/PumpStationControl --web getSwitchState " . $ini_array['Pump1Switch']; +// exec ($command, $valP1, $return); +// if (is_array($valP1)) { +// $Pump1State= boolval($valP1[0]); +// } else { +// $Pump1State= boolval($valP1); +// } +if ($Pump1State== 0) { + echo ('
'); +} else if ($Pump1State== 1) { + echo ('
'); +} +echo ('
'); +printf ( "%.2f h", $valOH1 ); +echo ("
"); +?>
Valve 1
"); + if ($Valve1State== 0 ) { + echo (""); } else { - echo (""); + echo (""); } ?>
@@ -260,10 +270,10 @@
Valve 2
"); + if ($Valve2State== 0 ) { + echo (""); } else { - echo (""); + echo (""); } ?>
@@ -271,10 +281,10 @@
Valve 3
"); + if ($Valve3State== 0 ) { + echo (""); } else { - echo (""); + echo (""); } ?>
@@ -282,10 +292,10 @@
Pump 1
"); + if ($Pump1State== 0 ) { + echo (""); } else { - echo (""); + echo (""); } ?>
@@ -293,10 +303,10 @@
Pump 2
"); + if ($Pump2State== 0 ) { + echo (""); } else { - echo (""); + echo (""); } ?>
@@ -308,18 +318,18 @@ - + -
+
- + \ No newline at end of file diff --git a/pumpstation/website/pumpstation.ini b/pumpstation/website/pumpstation.ini index b18196606..3a0a91113 100644 --- a/pumpstation/website/pumpstation.ini +++ b/pumpstation/website/pumpstation.ini @@ -1,2 +1,7 @@ DocumentRoot = /var/www/html TimeZone = Europe/Berlin +Pump1Switch = 0 +Pump2Switch = 1 +Valve1Switch = 2 +Valve2Switch = 4 +Valve3Switch = 3 diff --git a/pumpstation/website/script.js b/pumpstation/website/script.js index 4b039dd1a..fa0f7b2d7 100644 --- a/pumpstation/website/script.js +++ b/pumpstation/website/script.js @@ -1,14 +1,14 @@ -var switch_0 = document.getElementById("switch_0"); -var switch_1 = document.getElementById("switch_1"); -var switch_2 = document.getElementById("switch_2"); -var switch_3 = document.getElementById("switch_3"); -var switch_4 = document.getElementById("switch_4"); +var switch_V1 = document.getElementById("switch_V1"); +var switch_V2 = document.getElementById("switch_V2"); +var switch_V3 = document.getElementById("switch_V3"); +var switch_P1 = document.getElementById("switch_P1"); +var switch_P2 = document.getElementById("switch_P2"); //Create an array for easy access later -var Switches = [ switch_0, switch_1, switch_2, switch_3, switch_4]; +var Switches = [ switch_V1, switch_V2, switch_V3, switch_P1, switch_P2]; function changeSwitch(channel) { - var data = 0; + var data = 0; var request = new XMLHttpRequest(); request.open("GET", "ConradSwitch.php?channel=" + channel, true); request.send(null); @@ -29,7 +29,7 @@ function changeSwitch(channel) { alert ("Something went wrong!"); return ("fail"); } - + } else if (request.readyState == 4 && request.status == 500) { alert ("server error"); return ("fail"); @@ -38,5 +38,5 @@ function changeSwitch(channel) { return ("fail"); } } - return 0; + return 0; } \ No newline at end of file diff --git a/python/leybold.py b/python/leybold.py new file mode 100644 index 000000000..c90537a37 --- /dev/null +++ b/python/leybold.py @@ -0,0 +1,7 @@ +import time +import PyTkModLabLeybold + +leybold = PyTkModLabLeybold.LeyboldGraphixThree("/dev/ttyUSB0") + +print "version: " + leybold.GetVersion() + diff --git a/tools/TkModLabRoot/Makefile.in b/tools/TkModLabRoot/Makefile.in index 1a559949c..f245405af 100644 --- a/tools/TkModLabRoot/Makefile.in +++ b/tools/TkModLabRoot/Makefile.in @@ -59,7 +59,7 @@ endif lib$(TARGET).so: $(OBJECTS) @echo "Linking shared library $@" - $(LD) $(SOFLAGS) $^ -o $@ $(ELIBS) -lgfortran + $(LD) $(SOFLAGS) $^ -o $@ $(ELIBS) lib$(TARGET).rootmap: lib$(TARGET).so LinkDef.h @echo "Creating library rootmap $@"