Merge branch 'main' into MQTT_Robin
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
27
Applications/qModMaster/.hgtags
Normal file
@@ -0,0 +1,27 @@
|
||||
d6d0b41b126ccba8b09fc59e48912745cfff75be 0.3b
|
||||
2381684f3d5aba19a8341f5066e8926836e75bd4 0.3.1
|
||||
777230899f8d2d6293ce086e5d8121d5633587a7 0.3.2
|
||||
823d2854d09feaeffa8b33bd26820c92b1c9338c 0.3.3
|
||||
6b8ac66401954f5095d78a8b69737b1d29fb3058 0.3.4
|
||||
05290da92610d4e7b0ca3408b797f60970fa5196 0.3.5
|
||||
bc07afceca77bac00b39f4524c323cf0762b0adf 0.3.6
|
||||
91b2f29aabda0f8a447e68701e3ec5290c975763 0.3.7
|
||||
e29486700476b695e2c06efe547047b50b7d1310 0.3.8
|
||||
cff1be19d097303526a5d08e482748af329b038a 0.3.9
|
||||
cb03b5cbb8acb10f3eb448ab5ce77cdf7bea2846 0.4.0
|
||||
193b3543cff470f065e492921634466938c31087 0.4.1
|
||||
e2f735cb82c448dc01b6930326ef207cc634334f 0.4.2
|
||||
0d5dd919458705c1452c6729fb4a81213ebc59ef 0.4.2-TC1
|
||||
daa66ad96e999b69a7891d6b1e88f283449eb658 0.4.3
|
||||
89da4336a9421e32f7c067e0079df5a9bc174d93 0.4.5
|
||||
c3e35e2887e2406e5fa94663630bae92c57ce067 0.4.6
|
||||
38d3b294a86356a65fc62e2ea9e3d3e15078a51b 0.4.7
|
||||
86fbb4b96b1162d9f21c2a1fd521064ec9e10165 0.4.8
|
||||
38c7b5b820416bbb23c43623f75e743b15145ed3 0.4.9
|
||||
ef1fad56f0138adb3d72b1f4f607272cc2517150 0.5.0
|
||||
ed94674ee7bebfa6352922baf3cb4876a7c062b7 0.5.1-2
|
||||
44c7c2c84b61140d7965f1dd8dfb5276eb475c44 0.5.2
|
||||
e4488a09e77cee64179065cb4a3ee2ba315485ad 0.5.2-1
|
||||
febfe11c411e47f2311123b3382be598be529371 0.5.2-2
|
||||
6aba19d1ca6db89fe0f06039b05e2511bd57af4c 0.5.2-3
|
||||
c928384f1cd41a912f8238f076e691a382f95e5f 0.5.3-beta
|
||||
193
Applications/qModMaster/3rdparty/QsLog/QsLog.cpp
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QsLog.h"
|
||||
#include "QsLogDest.h"
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
#include <QThreadPool>
|
||||
#include <QRunnable>
|
||||
#else
|
||||
#include <QMutex>
|
||||
#endif
|
||||
#include <QVector>
|
||||
#include <QDateTime>
|
||||
#include <QtGlobal>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
typedef QVector<DestinationPtr> DestinationList;
|
||||
|
||||
static const char TraceString[] = "TRACE";
|
||||
static const char DebugString[] = "DEBUG";
|
||||
static const char InfoString[] = "INFO";
|
||||
static const char WarnString[] = "WARN";
|
||||
static const char ErrorString[] = "ERROR";
|
||||
static const char FatalString[] = "FATAL";
|
||||
|
||||
// not using Qt::ISODate because we need the milliseconds too
|
||||
static const QString fmtDateTime("yyyy-MM-ddThh:mm:ss.zzz");
|
||||
|
||||
static const char* LevelToText(Level theLevel)
|
||||
{
|
||||
switch (theLevel) {
|
||||
case TraceLevel:
|
||||
return TraceString;
|
||||
case DebugLevel:
|
||||
return DebugString;
|
||||
case InfoLevel:
|
||||
return InfoString;
|
||||
case WarnLevel:
|
||||
return WarnString;
|
||||
case ErrorLevel:
|
||||
return ErrorString;
|
||||
case FatalLevel:
|
||||
return FatalString;
|
||||
case OffLevel:
|
||||
return "";
|
||||
default: {
|
||||
assert(!"bad log level");
|
||||
return InfoString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
class LogWriterRunnable : public QRunnable
|
||||
{
|
||||
public:
|
||||
LogWriterRunnable(const QString &message, Level level)
|
||||
: mMessage(message)
|
||||
, mLevel(level) {}
|
||||
|
||||
virtual void run()
|
||||
{
|
||||
Logger::instance().write(mMessage, mLevel);
|
||||
}
|
||||
|
||||
private:
|
||||
QString mMessage;
|
||||
Level mLevel;
|
||||
};
|
||||
#endif
|
||||
|
||||
class LoggerImpl
|
||||
{
|
||||
public:
|
||||
LoggerImpl() :
|
||||
level(InfoLevel)
|
||||
{
|
||||
// assume at least file + console
|
||||
destList.reserve(2);
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
threadPool.setMaxThreadCount(1);
|
||||
threadPool.setExpiryTimeout(-1);
|
||||
#endif
|
||||
}
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
QThreadPool threadPool;
|
||||
#else
|
||||
QMutex logMutex;
|
||||
#endif
|
||||
Level level;
|
||||
DestinationList destList;
|
||||
};
|
||||
|
||||
Logger::Logger() :
|
||||
d(new LoggerImpl)
|
||||
{
|
||||
}
|
||||
|
||||
Logger::~Logger()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Logger::addDestination(DestinationPtr destination)
|
||||
{
|
||||
assert(destination.data());
|
||||
d->destList.push_back(destination);
|
||||
}
|
||||
|
||||
void Logger::setLoggingLevel(Level newLevel)
|
||||
{
|
||||
d->level = newLevel;
|
||||
}
|
||||
|
||||
Level Logger::loggingLevel() const
|
||||
{
|
||||
return d->level;
|
||||
}
|
||||
|
||||
//! creates the complete log message and passes it to the logger
|
||||
void Logger::Helper::writeToLog()
|
||||
{
|
||||
const char* const levelName = LevelToText(level);
|
||||
const QString completeMessage(QString("%1 %2 %3")
|
||||
.arg(levelName, 5)
|
||||
.arg(QDateTime::currentDateTime().toString(fmtDateTime))
|
||||
.arg(buffer)
|
||||
);
|
||||
|
||||
Logger::instance().enqueueWrite(completeMessage, level);
|
||||
}
|
||||
|
||||
Logger::Helper::~Helper()
|
||||
{
|
||||
try {
|
||||
writeToLog();
|
||||
}
|
||||
catch(std::exception&) {
|
||||
// you shouldn't throw exceptions from a sink
|
||||
assert(!"exception in logger helper destructor");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//! directs the message to the task queue or writes it directly
|
||||
void Logger::enqueueWrite(const QString& message, Level level)
|
||||
{
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
LogWriterRunnable *r = new LogWriterRunnable(message, level);
|
||||
d->threadPool.start(r);
|
||||
#else
|
||||
QMutexLocker lock(&d->logMutex);
|
||||
write(message, level);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Sends the message to all the destinations. The level for this message is passed in case
|
||||
//! it's useful for processing in the destination.
|
||||
void Logger::write(const QString& message, Level level)
|
||||
{
|
||||
for (DestinationList::iterator it = d->destList.begin(),
|
||||
endIt = d->destList.end();it != endIt;++it) {
|
||||
(*it)->write(message, level);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
138
Applications/qModMaster/3rdparty/QsLog/QsLog.h
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOG_H
|
||||
#define QSLOG_H
|
||||
|
||||
#include "QsLogLevel.h"
|
||||
#include "QsLogDest.h"
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
||||
#define QS_LOG_VERSION "2.0b1"
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
class Destination;
|
||||
class LoggerImpl; // d pointer
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static Logger& instance()
|
||||
{
|
||||
static Logger staticLog;
|
||||
return staticLog;
|
||||
}
|
||||
|
||||
//! Adds a log message destination. Don't add null destinations.
|
||||
void addDestination(DestinationPtr destination);
|
||||
//! Logging at a level < 'newLevel' will be ignored
|
||||
void setLoggingLevel(Level newLevel);
|
||||
//! The default level is INFO
|
||||
Level loggingLevel() const;
|
||||
|
||||
//! The helper forwards the streaming to QDebug and builds the final
|
||||
//! log message.
|
||||
class Helper
|
||||
{
|
||||
public:
|
||||
explicit Helper(Level logLevel) :
|
||||
level(logLevel),
|
||||
qtDebug(&buffer) {}
|
||||
~Helper();
|
||||
QDebug& stream(){ return qtDebug; }
|
||||
|
||||
private:
|
||||
void writeToLog();
|
||||
|
||||
Level level;
|
||||
QString buffer;
|
||||
QDebug qtDebug;
|
||||
};
|
||||
|
||||
private:
|
||||
Logger();
|
||||
Logger(const Logger&);
|
||||
Logger& operator=(const Logger&);
|
||||
~Logger();
|
||||
|
||||
void enqueueWrite(const QString& message, Level level);
|
||||
void write(const QString& message, Level level);
|
||||
|
||||
LoggerImpl* d;
|
||||
|
||||
friend class LogWriterRunnable;
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
//! Logging macros: define QS_LOG_LINE_NUMBERS to get the file and line number
|
||||
//! in the log output.
|
||||
#ifndef QS_LOG_LINE_NUMBERS
|
||||
#define QLOG_TRACE() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::TraceLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::TraceLevel).stream()
|
||||
#define QLOG_DEBUG() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::DebugLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::DebugLevel).stream()
|
||||
#define QLOG_INFO() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::InfoLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::InfoLevel).stream()
|
||||
#define QLOG_WARN() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::WarnLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::WarnLevel).stream()
|
||||
#define QLOG_ERROR() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::ErrorLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream()
|
||||
#define QLOG_FATAL() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::FatalLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::FatalLevel).stream()
|
||||
#else
|
||||
#define QLOG_TRACE() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::TraceLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::TraceLevel).stream() << __FILE__ << '@' << __LINE__
|
||||
#define QLOG_DEBUG() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::DebugLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::DebugLevel).stream() << __FILE__ << '@' << __LINE__
|
||||
#define QLOG_INFO() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::InfoLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::InfoLevel).stream() << __FILE__ << '@' << __LINE__
|
||||
#define QLOG_WARN() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::WarnLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::WarnLevel).stream() << __FILE__ << '@' << __LINE__
|
||||
#define QLOG_ERROR() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::ErrorLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream() << __FILE__ << '@' << __LINE__
|
||||
#define QLOG_FATAL() \
|
||||
if (QsLogging::Logger::instance().loggingLevel() > QsLogging::FatalLevel) {} \
|
||||
else QsLogging::Logger::Helper(QsLogging::FatalLevel).stream() << __FILE__ << '@' << __LINE__
|
||||
#endif
|
||||
|
||||
#ifdef QS_LOG_DISABLE
|
||||
#include "QsLogDisableForThisFile.h"
|
||||
#endif
|
||||
|
||||
#endif // QSLOG_H
|
||||
19
Applications/qModMaster/3rdparty/QsLog/QsLog.pri
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
#DEFINES += QS_LOG_LINE_NUMBERS # automatically writes the file and line for each log message
|
||||
#DEFINES += QS_LOG_DISABLE # logging code is replaced with a no-op
|
||||
#DEFINES += QS_LOG_SEPARATE_THREAD # messages are queued and written from a separate thread
|
||||
SOURCES += $$PWD/QsLogDest.cpp \
|
||||
$$PWD/QsLog.cpp \
|
||||
$$PWD/QsLogDestConsole.cpp \
|
||||
$$PWD/QsLogDestFile.cpp
|
||||
|
||||
HEADERS += $$PWD/QSLogDest.h \
|
||||
$$PWD/QsLog.h \
|
||||
$$PWD/QsLogDestConsole.h \
|
||||
$$PWD/QsLogLevel.h \
|
||||
$$PWD/QsLogDestFile.h \
|
||||
$$PWD/QsLogDisableForThisFile.h
|
||||
|
||||
OTHER_FILES += \
|
||||
$$PWD/QsLogChanges.txt \
|
||||
$$PWD/QsLogReadme.txt
|
||||
12
Applications/qModMaster/3rdparty/QsLog/QsLogChanges.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
QsLog version 2.0b1
|
||||
|
||||
Changes:
|
||||
* destination pointers use shared pointer semantics
|
||||
* the file destination supports log rotation. As a consequence, log files are encoded as UTF-8 and
|
||||
the log appends rather than truncating on every startup when rotation is enabled.
|
||||
* added the posibility of disabling logging either at run time or compile time.
|
||||
* added the possibility of using a separate thread for writing to the log destinations.
|
||||
|
||||
Fixes:
|
||||
* renamed the main.cpp example to avoid QtCreator confusion
|
||||
* offer a way to check if the destination creation has failed (for e.g files)
|
||||
54
Applications/qModMaster/3rdparty/QsLog/QsLogDest.cpp
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QsLogDest.h"
|
||||
#include "QsLogDestConsole.h"
|
||||
#include "QsLogDestFile.h"
|
||||
#include <QString>
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
//! destination factory
|
||||
DestinationPtr DestinationFactory::MakeFileDestination(const QString& filePath, bool enableRotation,
|
||||
qint64 sizeInBytesToRotateAfter, int oldLogsToKeep)
|
||||
{
|
||||
if (enableRotation) {
|
||||
QScopedPointer<SizeRotationStrategy> logRotation(new SizeRotationStrategy);
|
||||
logRotation->setMaximumSizeInBytes(sizeInBytesToRotateAfter);
|
||||
logRotation->setBackupCount(oldLogsToKeep);
|
||||
|
||||
return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(logRotation.take())));
|
||||
}
|
||||
|
||||
return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(new NullRotationStrategy)));
|
||||
}
|
||||
|
||||
DestinationPtr DestinationFactory::MakeDebugOutputDestination()
|
||||
{
|
||||
return DestinationPtr(new DebugOutputDestination);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
57
Applications/qModMaster/3rdparty/QsLog/QsLogDest.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOGDEST_H
|
||||
#define QSLOGDEST_H
|
||||
|
||||
#include "QsLogLevel.h"
|
||||
#include <QSharedPointer>
|
||||
#include <QtGlobal>
|
||||
class QString;
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
class Destination
|
||||
{
|
||||
public:
|
||||
virtual ~Destination(){}
|
||||
virtual void write(const QString& message, Level level) = 0;
|
||||
virtual bool isValid() = 0; // returns whether the destination was created correctly
|
||||
};
|
||||
typedef QSharedPointer<Destination> DestinationPtr;
|
||||
|
||||
//! Creates logging destinations/sinks. The caller will have ownership of
|
||||
//! the newly created destinations.
|
||||
class DestinationFactory
|
||||
{
|
||||
public:
|
||||
static DestinationPtr MakeFileDestination(const QString& filePath, bool enableRotation = false, qint64 sizeInBytesToRotateAfter = 0, int oldLogsToKeep = 0);
|
||||
static DestinationPtr MakeDebugOutputDestination();
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
#endif // QSLOGDEST_H
|
||||
75
Applications/qModMaster/3rdparty/QsLog/QsLogDestConsole.cpp
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QsLogDestConsole.h"
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
void QsDebugOutput::output( const QString& message )
|
||||
{
|
||||
OutputDebugStringW(reinterpret_cast<const WCHAR*>(message.utf16()));
|
||||
OutputDebugStringW(L"\n");
|
||||
}
|
||||
#elif defined(Q_OS_SYMBIAN)
|
||||
#include <e32debug.h>
|
||||
void QsDebugOutput::output( const QString& message )
|
||||
{
|
||||
const int maxPrintSize = 256;
|
||||
if (message.size() <= maxPrintSize) {
|
||||
TPtrC16 symbianMessage(reinterpret_cast<const TUint16*>(message.utf16()));
|
||||
RDebug::RawPrint(symbianMessage);
|
||||
} else {
|
||||
QString slicedMessage = message;
|
||||
while (!slicedMessage.isEmpty()) {
|
||||
const int sliceSize = qMin(maxPrintSize, slicedMessage.size());
|
||||
const QString slice = slicedMessage.left(sliceSize);
|
||||
slicedMessage.remove(0, sliceSize);
|
||||
|
||||
TPtrC16 symbianSlice(reinterpret_cast<const TUint16*>(slice.utf16()));
|
||||
RDebug::RawPrint(symbianSlice);
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(Q_OS_UNIX)
|
||||
#include <cstdio>
|
||||
void QsDebugOutput::output( const QString& message )
|
||||
{
|
||||
fprintf(stderr, "%s\n", qPrintable(message));
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
|
||||
void QsLogging::DebugOutputDestination::write(const QString& message, Level)
|
||||
{
|
||||
QsDebugOutput::output(message);
|
||||
}
|
||||
|
||||
bool QsLogging::DebugOutputDestination::isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
52
Applications/qModMaster/3rdparty/QsLog/QsLogDestConsole.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOGDESTCONSOLE_H
|
||||
#define QSLOGDESTCONSOLE_H
|
||||
|
||||
#include "QsLogDest.h"
|
||||
|
||||
class QString;
|
||||
|
||||
class QsDebugOutput
|
||||
{
|
||||
public:
|
||||
static void output(const QString& a_message);
|
||||
};
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
// debugger sink
|
||||
class DebugOutputDestination : public Destination
|
||||
{
|
||||
public:
|
||||
virtual void write(const QString& message, Level level);
|
||||
virtual bool isValid();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QSLOGDESTCONSOLE_H
|
||||
155
Applications/qModMaster/3rdparty/QsLog/QsLogDestFile.cpp
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QsLogDestFile.h"
|
||||
#include <QtCore5Compat/QTextCodec>
|
||||
#include <QDateTime>
|
||||
#include <QtGlobal>
|
||||
#include <iostream>
|
||||
|
||||
const int QsLogging::SizeRotationStrategy::MaxBackupCount = 10;
|
||||
|
||||
QsLogging::RotationStrategy::~RotationStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
QsLogging::SizeRotationStrategy::SizeRotationStrategy()
|
||||
: mCurrentSizeInBytes(0)
|
||||
, mMaxSizeInBytes(0)
|
||||
, mBackupsCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void QsLogging::SizeRotationStrategy::setInitialInfo(const QFile &file)
|
||||
{
|
||||
mFileName = file.fileName();
|
||||
mCurrentSizeInBytes = file.size();
|
||||
}
|
||||
|
||||
void QsLogging::SizeRotationStrategy::includeMessageInCalculation(const QString &message)
|
||||
{
|
||||
mCurrentSizeInBytes += message.toUtf8().size();
|
||||
}
|
||||
|
||||
bool QsLogging::SizeRotationStrategy::shouldRotate()
|
||||
{
|
||||
return mCurrentSizeInBytes > mMaxSizeInBytes;
|
||||
}
|
||||
|
||||
// Algorithm assumes backups will be named filename.X, where 1 <= X <= mBackupsCount.
|
||||
// All X's will be shifted up.
|
||||
void QsLogging::SizeRotationStrategy::rotate()
|
||||
{
|
||||
if (!mBackupsCount) {
|
||||
if (!QFile::remove(mFileName))
|
||||
std::cerr << "QsLog: backup delete failed " << qPrintable(mFileName);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. find the last existing backup than can be shifted up
|
||||
const QString logNamePattern = mFileName + QString::fromUtf8(".%1");
|
||||
int lastExistingBackupIndex = 0;
|
||||
for (int i = 1;i <= mBackupsCount;++i) {
|
||||
const QString backupFileName = logNamePattern.arg(i);
|
||||
if (QFile::exists(backupFileName))
|
||||
lastExistingBackupIndex = qMin(i, mBackupsCount - 1);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// 2. shift up
|
||||
for (int i = lastExistingBackupIndex;i >= 1;--i) {
|
||||
const QString oldName = logNamePattern.arg(i);
|
||||
const QString newName = logNamePattern.arg(i + 1);
|
||||
QFile::remove(newName);
|
||||
const bool renamed = QFile::rename(oldName, newName);
|
||||
if (!renamed) {
|
||||
std::cerr << "QsLog: could not rename backup " << qPrintable(oldName)
|
||||
<< " to " << qPrintable(newName);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. rename current log file
|
||||
const QString newName = logNamePattern.arg(1);
|
||||
if (QFile::exists(newName))
|
||||
QFile::remove(newName);
|
||||
if (!QFile::rename(mFileName, newName)) {
|
||||
std::cerr << "QsLog: could not rename log " << qPrintable(mFileName)
|
||||
<< " to " << qPrintable(newName);
|
||||
}
|
||||
}
|
||||
|
||||
QIODevice::OpenMode QsLogging::SizeRotationStrategy::recommendedOpenModeFlag()
|
||||
{
|
||||
return QIODevice::Append;
|
||||
}
|
||||
|
||||
void QsLogging::SizeRotationStrategy::setMaximumSizeInBytes(qint64 size)
|
||||
{
|
||||
Q_ASSERT(size >= 0);
|
||||
mMaxSizeInBytes = size;
|
||||
}
|
||||
|
||||
void QsLogging::SizeRotationStrategy::setBackupCount(int backups)
|
||||
{
|
||||
Q_ASSERT(backups >= 0);
|
||||
mBackupsCount = qMin(backups, SizeRotationStrategy::MaxBackupCount);
|
||||
}
|
||||
|
||||
|
||||
QsLogging::FileDestination::FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy)
|
||||
: mRotationStrategy(rotationStrategy)
|
||||
{
|
||||
mFile.setFileName(filePath);
|
||||
if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
|
||||
std::cerr << "QsLog: could not open log file " << qPrintable(filePath);
|
||||
mOutputStream.setDevice(&mFile);
|
||||
/*mOutputStream.setCodec(QTextCodec::codecForName("UTF-8"));*/
|
||||
|
||||
mRotationStrategy->setInitialInfo(mFile);
|
||||
}
|
||||
|
||||
void QsLogging::FileDestination::write(const QString& message, Level)
|
||||
{
|
||||
mRotationStrategy->includeMessageInCalculation(message);
|
||||
if (mRotationStrategy->shouldRotate()) {
|
||||
mOutputStream.setDevice(NULL);
|
||||
mFile.close();
|
||||
mRotationStrategy->rotate();
|
||||
if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
|
||||
std::cerr << "QsLog: could not reopen log file " << qPrintable(mFile.fileName());
|
||||
mRotationStrategy->setInitialInfo(mFile);
|
||||
mOutputStream.setDevice(&mFile);
|
||||
}
|
||||
|
||||
mOutputStream << message << Qt::endl;
|
||||
mOutputStream.flush();
|
||||
}
|
||||
|
||||
bool QsLogging::FileDestination::isValid()
|
||||
{
|
||||
return mFile.isOpen();
|
||||
}
|
||||
|
||||
101
Applications/qModMaster/3rdparty/QsLog/QsLogDestFile.h
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOGDESTFILE_H
|
||||
#define QSLOGDESTFILE_H
|
||||
|
||||
#include "QsLogDest.h"
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QtGlobal>
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
class RotationStrategy
|
||||
{
|
||||
public:
|
||||
virtual ~RotationStrategy();
|
||||
|
||||
virtual void setInitialInfo(const QFile &file) = 0;
|
||||
virtual void includeMessageInCalculation(const QString &message) = 0;
|
||||
virtual bool shouldRotate() = 0;
|
||||
virtual void rotate() = 0;
|
||||
virtual QIODevice::OpenMode recommendedOpenModeFlag() = 0;
|
||||
};
|
||||
|
||||
// Never rotates file, overwrites existing file.
|
||||
class NullRotationStrategy : public RotationStrategy
|
||||
{
|
||||
public:
|
||||
virtual void setInitialInfo(const QFile &) {}
|
||||
virtual void includeMessageInCalculation(const QString &) {}
|
||||
virtual bool shouldRotate() { return false; }
|
||||
virtual void rotate() {}
|
||||
virtual QIODevice::OpenMode recommendedOpenModeFlag() { return QIODevice::Truncate; }
|
||||
};
|
||||
|
||||
// Rotates after a size is reached, keeps a number of <= 10 backups, appends to existing file.
|
||||
class SizeRotationStrategy : public RotationStrategy
|
||||
{
|
||||
public:
|
||||
SizeRotationStrategy();
|
||||
static const int MaxBackupCount;
|
||||
|
||||
virtual void setInitialInfo(const QFile &file);
|
||||
virtual void includeMessageInCalculation(const QString &message);
|
||||
virtual bool shouldRotate();
|
||||
virtual void rotate();
|
||||
virtual QIODevice::OpenMode recommendedOpenModeFlag();
|
||||
|
||||
void setMaximumSizeInBytes(qint64 size);
|
||||
void setBackupCount(int backups);
|
||||
|
||||
private:
|
||||
QString mFileName;
|
||||
qint64 mCurrentSizeInBytes;
|
||||
qint64 mMaxSizeInBytes;
|
||||
int mBackupsCount;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<RotationStrategy> RotationStrategyPtr;
|
||||
|
||||
// file message sink
|
||||
class FileDestination : public Destination
|
||||
{
|
||||
public:
|
||||
FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy);
|
||||
virtual void write(const QString& message, Level level);
|
||||
virtual bool isValid();
|
||||
|
||||
private:
|
||||
QFile mFile;
|
||||
QTextStream mOutputStream;
|
||||
QSharedPointer<RotationStrategy> mRotationStrategy;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QSLOGDESTFILE_H
|
||||
22
Applications/qModMaster/3rdparty/QsLog/QsLogDisableForThisFile.h
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef QSLOGDISABLEFORTHISFILE_H
|
||||
#define QSLOGDISABLEFORTHISFILE_H
|
||||
|
||||
#include <QtDebug>
|
||||
// When included AFTER QsLog.h, this file will disable logging in that C++ file. When included
|
||||
// before, it will lead to compiler warnings or errors about macro redefinitions.
|
||||
|
||||
#undef QLOG_TRACE
|
||||
#undef QLOG_DEBUG
|
||||
#undef QLOG_INFO
|
||||
#undef QLOG_WARN
|
||||
#undef QLOG_ERROR
|
||||
#undef QLOG_FATAL
|
||||
|
||||
#define QLOG_TRACE() if (1) {} else qDebug()
|
||||
#define QLOG_DEBUG() if (1) {} else qDebug()
|
||||
#define QLOG_INFO() if (1) {} else qDebug()
|
||||
#define QLOG_WARN() if (1) {} else qDebug()
|
||||
#define QLOG_ERROR() if (1) {} else qDebug()
|
||||
#define QLOG_FATAL() if (1) {} else qDebug()
|
||||
|
||||
#endif // QSLOGDISABLEFORTHISFILE_H
|
||||
45
Applications/qModMaster/3rdparty/QsLog/QsLogLevel.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2013, Razvan Petru
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOGLEVEL_H
|
||||
#define QSLOGLEVEL_H
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
enum Level
|
||||
{
|
||||
TraceLevel = 0,
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
ErrorLevel,
|
||||
FatalLevel,
|
||||
OffLevel
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QSLOGLEVEL_H
|
||||
34
Applications/qModMaster/3rdparty/QsLog/QsLogReadme.txt
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
QsLog - the simple Qt logger
|
||||
|
||||
QsLog is an easy to use logger that is based on Qt's QDebug class.
|
||||
Features
|
||||
|
||||
Six logging levels (from trace to fatal)
|
||||
Logging level threshold configurable at runtime.
|
||||
Minimum overhead when logging is turned off.
|
||||
Supports multiple destinations, comes with file and debug destinations.
|
||||
Thread-safe
|
||||
Supports logging of common Qt types out of the box.
|
||||
Small dependency: just drop it in your project directly.
|
||||
|
||||
Usage
|
||||
|
||||
Include QsLog.h. Include QsLogDest.h only where you create/add destinations.
|
||||
Get the instance of the logger by calling QsLogging::Logger::instance();
|
||||
Optionally set the logging level. Info is default.
|
||||
Create as many destinations as you want by using the QsLogging::DestinationFactory.
|
||||
Add the destinations to the logger instance by calling addDestination.
|
||||
|
||||
Disabling logging
|
||||
|
||||
Sometimes it's necessary to turn off logging. This can be done in several ways:
|
||||
|
||||
globally, at compile time, by enabling the QS_LOG_DISABLE macro in the supplied .pri file.
|
||||
globally, at run time, by setting the log level to "OffLevel".
|
||||
per file, at compile time, by including QsLogDisableForThisFile.h in the target file.
|
||||
|
||||
Thread safety
|
||||
|
||||
The Qt docs say: A thread-safe function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized. A reentrant function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.
|
||||
|
||||
Since sending the log message to the destinations is protected by a mutex, the logging macros are thread-safe provided that the log has been initialized - i.e: instance() has been called. The instance function and the setup functions (e.g: setLoggingLevel, addDestination) are NOT thread-safe and are NOT reentrant.
|
||||
40
Applications/qModMaster/3rdparty/QsLog/examplemain.cpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "QsLog.h"
|
||||
#include "QsLogDest.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDir>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
// init the logging mechanism
|
||||
QsLogging::Logger& logger = QsLogging::Logger::instance();
|
||||
logger.setLoggingLevel(QsLogging::TraceLevel);
|
||||
const QString sLogPath(QDir(a.applicationDirPath()).filePath("log.txt"));
|
||||
|
||||
QsLogging::DestinationPtr fileDestination(
|
||||
QsLogging::DestinationFactory::MakeFileDestination(sLogPath, true, 512, 2) );
|
||||
QsLogging::DestinationPtr debugDestination(
|
||||
QsLogging::DestinationFactory::MakeDebugOutputDestination() );
|
||||
logger.addDestination(debugDestination);
|
||||
logger.addDestination(fileDestination);
|
||||
|
||||
QLOG_INFO() << "Program started";
|
||||
QLOG_INFO() << "Built with Qt" << QT_VERSION_STR << "running on" << qVersion();
|
||||
|
||||
QLOG_TRACE() << "Here's a" << QString::fromUtf8("trace") << "message";
|
||||
QLOG_DEBUG() << "Here's a" << static_cast<int>(QsLogging::DebugLevel) << "message";
|
||||
QLOG_WARN() << "Uh-oh!";
|
||||
qDebug() << "This message won't be picked up by the logger";
|
||||
QLOG_ERROR() << "An error has occurred";
|
||||
qWarning() << "Neither will this one";
|
||||
QLOG_FATAL() << "Fatal error!";
|
||||
|
||||
logger.setLoggingLevel(QsLogging::OffLevel);
|
||||
for (int i = 0;i < 10000000;++i) {
|
||||
QLOG_ERROR() << QString::fromUtf8("logging is turned off");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
Applications/qModMaster/3rdparty/QsLog/log_example.pro
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# -------------------------------------------------
|
||||
# Project created by QtCreator 2010-03-20T12:17:43
|
||||
# -------------------------------------------------
|
||||
QT -= gui
|
||||
TARGET = log_example
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
TEMPLATE = app
|
||||
SOURCES += \
|
||||
examplemain.cpp
|
||||
include(QsLog.pri)
|
||||
171
Applications/qModMaster/3rdparty/libmodbus/config.h
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `TIOCSRS485', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_TIOCSRS485 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `TIOCM_RTS', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_TIOCM_RTS 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `__CYGWIN__', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL___CYGWIN__ 0
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#define HAVE_ERRNO_H 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#define HAVE_FORK 1
|
||||
|
||||
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||
#define HAVE_GETADDRINFO 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the `inet_ntoa' function. */
|
||||
#define HAVE_INET_NTOA 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/serial.h> header file. */
|
||||
#define HAVE_LINUX_SERIAL_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#define HAVE_NETDB_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#define HAVE_NETINET_IN_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/tcp.h> header file. */
|
||||
#define HAVE_NETINET_TCP_H 1
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#define HAVE_SELECT 1
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#define HAVE_SOCKET 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
/* #undef HAVE_STRLCPY */
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#define HAVE_SYS_SOCKET_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#define HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#define HAVE_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#define HAVE_VFORK 1
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
/* #undef HAVE_VFORK_H */
|
||||
|
||||
/* Define to 1 if you have the <winsock2.h> header file. */
|
||||
/* #undef HAVE_WINSOCK2_H */
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#define HAVE_WORKING_FORK 1
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#define HAVE_WORKING_VFORK 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "libmodbus"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "https://github.com/stephane/libmodbus/issues"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "libmodbus"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "libmodbus 3.1.0-1"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "libmodbus"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "3.1.0-1"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "3.1.0-1"
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* #undef pid_t */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
/* #undef vfork */
|
||||
229
Applications/qModMaster/3rdparty/libmodbus/modbus-data.c
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# include <stdint.h>
|
||||
#else
|
||||
# include "stdint.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "modbus.h"
|
||||
|
||||
#if defined(HAVE_BYTESWAP_H)
|
||||
# include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <libkern/OSByteOrder.h>
|
||||
# define bswap_16 OSSwapInt16
|
||||
# define bswap_32 OSSwapInt32
|
||||
# define bswap_64 OSSwapInt64
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10)
|
||||
# if GCC_VERSION >= 430
|
||||
// Since GCC >= 4.30, GCC provides __builtin_bswapXX() alternatives so we switch to them
|
||||
# undef bswap_32
|
||||
# define bswap_32 __builtin_bswap32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
# define bswap_32 _byteswap_ulong
|
||||
# define bswap_16 _byteswap_ushort
|
||||
#endif
|
||||
|
||||
#if !defined(__CYGWIN__) && !defined(bswap_16)
|
||||
# warning "Fallback on C functions for bswap_16"
|
||||
static inline uint16_t bswap_16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(bswap_32)
|
||||
# warning "Fallback on C functions for bswap_32"
|
||||
static inline uint32_t bswap_32(uint32_t x)
|
||||
{
|
||||
return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sets many bits from a single byte value (all 8 bits of the byte value are
|
||||
set) */
|
||||
void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < 8; i++) {
|
||||
dest[idx+i] = (value & (1 << i)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sets many bits from a table of bytes (only the bits between idx and
|
||||
idx + nb_bits are set) */
|
||||
void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
|
||||
const uint8_t *tab_byte)
|
||||
{
|
||||
unsigned int i;
|
||||
int shift = 0;
|
||||
|
||||
for (i = idx; i < idx + nb_bits; i++) {
|
||||
dest[i] = tab_byte[(i - idx) / 8] & (1 << shift) ? 1 : 0;
|
||||
/* gcc doesn't like: shift = (++shift) % 8; */
|
||||
shift++;
|
||||
shift %= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets the byte value from many bits.
|
||||
To obtain a full byte, set nb_bits to 8. */
|
||||
uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx,
|
||||
unsigned int nb_bits)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t value = 0;
|
||||
|
||||
if (nb_bits > 8) {
|
||||
/* Assert is ignored if NDEBUG is set */
|
||||
assert(nb_bits < 8);
|
||||
nb_bits = 8;
|
||||
}
|
||||
|
||||
for (i=0; i < nb_bits; i++) {
|
||||
value |= (src[idx+i] << i);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */
|
||||
float modbus_get_float_abcd(const uint16_t *src)
|
||||
{
|
||||
float f;
|
||||
uint32_t i;
|
||||
|
||||
i = ntohl(((uint32_t)src[0] << 16) + src[1]);
|
||||
memcpy(&f, &i, sizeof(float));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Get a float from 4 bytes (Modbus) in inversed format (DCBA) */
|
||||
float modbus_get_float_dcba(const uint16_t *src)
|
||||
{
|
||||
float f;
|
||||
uint32_t i;
|
||||
|
||||
i = ntohl(bswap_32((((uint32_t)src[0]) << 16) + src[1]));
|
||||
memcpy(&f, &i, sizeof(float));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Get a float from 4 bytes (Modbus) with swapped bytes (BADC) */
|
||||
float modbus_get_float_badc(const uint16_t *src)
|
||||
{
|
||||
float f;
|
||||
uint32_t i;
|
||||
|
||||
i = ntohl((uint32_t)(bswap_16(src[0]) << 16) + bswap_16(src[1]));
|
||||
memcpy(&f, &i, sizeof(float));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Get a float from 4 bytes (Modbus) with swapped words (CDAB) */
|
||||
float modbus_get_float_cdab(const uint16_t *src)
|
||||
{
|
||||
float f;
|
||||
uint32_t i;
|
||||
|
||||
i = ntohl((((uint32_t)src[1]) << 16) + src[0]);
|
||||
memcpy(&f, &i, sizeof(float));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
|
||||
float modbus_get_float(const uint16_t *src)
|
||||
{
|
||||
float f;
|
||||
uint32_t i;
|
||||
|
||||
i = (((uint32_t)src[1]) << 16) + src[0];
|
||||
memcpy(&f, &i, sizeof(float));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
|
||||
void modbus_set_float_abcd(float f, uint16_t *dest)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
memcpy(&i, &f, sizeof(uint32_t));
|
||||
i = htonl(i);
|
||||
dest[0] = (uint16_t)(i >> 16);
|
||||
dest[1] = (uint16_t)i;
|
||||
}
|
||||
|
||||
/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
|
||||
void modbus_set_float_dcba(float f, uint16_t *dest)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
memcpy(&i, &f, sizeof(uint32_t));
|
||||
i = bswap_32(htonl(i));
|
||||
dest[0] = (uint16_t)(i >> 16);
|
||||
dest[1] = (uint16_t)i;
|
||||
}
|
||||
|
||||
/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
|
||||
void modbus_set_float_badc(float f, uint16_t *dest)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
memcpy(&i, &f, sizeof(uint32_t));
|
||||
i = htonl(i);
|
||||
dest[0] = (uint16_t)bswap_16(i >> 16);
|
||||
dest[1] = (uint16_t)bswap_16(i & 0xFFFF);
|
||||
}
|
||||
|
||||
/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
|
||||
void modbus_set_float_cdab(float f, uint16_t *dest)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
memcpy(&i, &f, sizeof(uint32_t));
|
||||
i = htonl(i);
|
||||
dest[0] = (uint16_t)i;
|
||||
dest[1] = (uint16_t)(i >> 16);
|
||||
}
|
||||
|
||||
/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
|
||||
void modbus_set_float(float f, uint16_t *dest)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
memcpy(&i, &f, sizeof(uint32_t));
|
||||
dest[0] = (uint16_t)i;
|
||||
dest[1] = (uint16_t)(i >> 16);
|
||||
}
|
||||
115
Applications/qModMaster/3rdparty/libmodbus/modbus-private.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright © 2010-2012 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef MODBUS_PRIVATE_H
|
||||
#define MODBUS_PRIVATE_H
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# include <stdint.h>
|
||||
# include <sys/time.h>
|
||||
#else
|
||||
# include "stdint.h"
|
||||
# include <time.h>
|
||||
typedef int ssize_t;
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <config.h>
|
||||
|
||||
#include "modbus.h"
|
||||
|
||||
MODBUS_BEGIN_DECLS
|
||||
|
||||
/* It's not really the minimal length (the real one is report slave ID
|
||||
* in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP
|
||||
* communications to read many values or write a single one.
|
||||
* Maximum between :
|
||||
* - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2)
|
||||
* - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2)
|
||||
*/
|
||||
#define _MIN_REQ_LENGTH 12
|
||||
|
||||
#define _REPORT_SLAVE_ID 180
|
||||
|
||||
#define _MODBUS_EXCEPTION_RSP_LENGTH 5
|
||||
|
||||
/* Timeouts in microsecond (0.5 s) */
|
||||
#define _RESPONSE_TIMEOUT 500000
|
||||
#define _BYTE_TIMEOUT 500000
|
||||
|
||||
typedef enum {
|
||||
_MODBUS_BACKEND_TYPE_RTU=0,
|
||||
_MODBUS_BACKEND_TYPE_TCP
|
||||
} modbus_backend_type_t;
|
||||
|
||||
/*
|
||||
* ---------- Request Indication ----------
|
||||
* | Client | ---------------------->| Server |
|
||||
* ---------- Confirmation Response ----------
|
||||
*/
|
||||
typedef enum {
|
||||
/* Request message on the server side */
|
||||
MSG_INDICATION,
|
||||
/* Request message on the client side */
|
||||
MSG_CONFIRMATION
|
||||
} msg_type_t;
|
||||
|
||||
/* This structure reduces the number of params in functions and so
|
||||
* optimizes the speed of execution (~ 37%). */
|
||||
typedef struct _sft {
|
||||
int slave;
|
||||
int function;
|
||||
int t_id;
|
||||
} sft_t;
|
||||
|
||||
typedef struct _modbus_backend {
|
||||
unsigned int backend_type;
|
||||
unsigned int header_length;
|
||||
unsigned int checksum_length;
|
||||
unsigned int max_adu_length;
|
||||
int (*set_slave) (modbus_t *ctx, int slave);
|
||||
int (*build_request_basis) (modbus_t *ctx, int function, int addr,
|
||||
int nb, uint8_t *req);
|
||||
int (*build_response_basis) (sft_t *sft, uint8_t *rsp);
|
||||
int (*prepare_response_tid) (const uint8_t *req, int *req_length);
|
||||
int (*send_msg_pre) (uint8_t *req, int req_length);
|
||||
ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);
|
||||
int (*receive) (modbus_t *ctx, uint8_t *req);
|
||||
ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);
|
||||
int (*check_integrity) (modbus_t *ctx, uint8_t *msg,
|
||||
const int msg_length);
|
||||
int (*pre_check_confirmation) (modbus_t *ctx, const uint8_t *req,
|
||||
const uint8_t *rsp, int rsp_length);
|
||||
int (*connect) (modbus_t *ctx);
|
||||
void (*close) (modbus_t *ctx);
|
||||
int (*flush) (modbus_t *ctx);
|
||||
int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
|
||||
void (*free) (modbus_t *ctx);
|
||||
} modbus_backend_t;
|
||||
|
||||
struct _modbus {
|
||||
/* Slave address */
|
||||
int slave;
|
||||
/* Socket or file descriptor */
|
||||
int s;
|
||||
int debug;
|
||||
int error_recovery;
|
||||
struct timeval response_timeout;
|
||||
struct timeval byte_timeout;
|
||||
const modbus_backend_t *backend;
|
||||
void *backend_data;
|
||||
};
|
||||
|
||||
void _modbus_init_common(modbus_t *ctx);
|
||||
void _error_print(modbus_t *ctx, const char *context);
|
||||
int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type);
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *dest, const char *src, size_t dest_size);
|
||||
#endif
|
||||
|
||||
MODBUS_END_DECLS
|
||||
|
||||
#endif /* MODBUS_PRIVATE_H */
|
||||
77
Applications/qModMaster/3rdparty/libmodbus/modbus-rtu-private.h
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef MODBUS_RTU_PRIVATE_H
|
||||
#define MODBUS_RTU_PRIVATE_H
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include "stdint.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#define _MODBUS_RTU_HEADER_LENGTH 1
|
||||
#define _MODBUS_RTU_PRESET_REQ_LENGTH 6
|
||||
#define _MODBUS_RTU_PRESET_RSP_LENGTH 2
|
||||
|
||||
#define _MODBUS_RTU_CHECKSUM_LENGTH 2
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if !defined(ENOTSUP)
|
||||
#define ENOTSUP WSAEOPNOTSUPP
|
||||
#endif
|
||||
|
||||
/* WIN32: struct containing serial handle and a receive buffer */
|
||||
#define PY_BUF_SIZE 512
|
||||
struct win32_ser {
|
||||
/* File handle */
|
||||
HANDLE fd;
|
||||
/* Receive buffer */
|
||||
uint8_t buf[PY_BUF_SIZE];
|
||||
/* Received chars */
|
||||
DWORD n_bytes;
|
||||
};
|
||||
#endif /* _WIN32 */
|
||||
|
||||
typedef struct _modbus_rtu {
|
||||
/* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" on Mac OS X. */
|
||||
char *device;
|
||||
/* Bauds: 9600, 19200, 57600, 115200, etc */
|
||||
int baud;
|
||||
/* Data bit */
|
||||
uint8_t data_bit;
|
||||
/* Stop bit */
|
||||
uint8_t stop_bit;
|
||||
/* Parity: 'N', 'O', 'E' */
|
||||
char parity;
|
||||
#if defined(_WIN32)
|
||||
struct win32_ser w_ser;
|
||||
DCB old_dcb;
|
||||
#else
|
||||
/* Save old termios settings */
|
||||
struct termios old_tios;
|
||||
#endif
|
||||
#if HAVE_DECL_TIOCSRS485
|
||||
int serial_mode;
|
||||
#endif
|
||||
//***Not part of libmodbus - added for QModMaster***//
|
||||
#if defined(_WIN32) || HAVE_DECL_TIOCM_RTS
|
||||
int rts;
|
||||
int rts_delay;
|
||||
int onebyte_time;
|
||||
void (*set_rts) (modbus_t *ctx, int on);
|
||||
#endif
|
||||
/* To handle many slaves on the same link */
|
||||
int confirmation_to_ignore;
|
||||
} modbus_rtu_t;
|
||||
|
||||
#endif /* MODBUS_RTU_PRIVATE_H */
|
||||
1285
Applications/qModMaster/3rdparty/libmodbus/modbus-rtu.c
vendored
Normal file
43
Applications/qModMaster/3rdparty/libmodbus/modbus-rtu.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef MODBUS_RTU_H
|
||||
#define MODBUS_RTU_H
|
||||
|
||||
#include "modbus.h"
|
||||
|
||||
MODBUS_BEGIN_DECLS
|
||||
|
||||
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
|
||||
* RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes
|
||||
*/
|
||||
#define MODBUS_RTU_MAX_ADU_LENGTH 256
|
||||
|
||||
//***Not part of libmodbus - rts param added for QModMaster***//
|
||||
MODBUS_API modbus_t* modbus_new_rtu(const char *device, int baud, char parity,
|
||||
int data_bit, int stop_bit, int rts);
|
||||
|
||||
#define MODBUS_RTU_RS232 0
|
||||
#define MODBUS_RTU_RS485 1
|
||||
|
||||
MODBUS_API int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
|
||||
MODBUS_API int modbus_rtu_get_serial_mode(modbus_t *ctx);
|
||||
|
||||
#define MODBUS_RTU_RTS_NONE 0
|
||||
#define MODBUS_RTU_RTS_UP 1
|
||||
#define MODBUS_RTU_RTS_DOWN 2
|
||||
|
||||
MODBUS_API int modbus_rtu_set_rts(modbus_t *ctx, int mode);
|
||||
MODBUS_API int modbus_rtu_get_rts(modbus_t *ctx);
|
||||
|
||||
MODBUS_API int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts) (modbus_t *ctx, int on));
|
||||
|
||||
MODBUS_API int modbus_rtu_set_rts_delay(modbus_t *ctx, int us);
|
||||
MODBUS_API int modbus_rtu_get_rts_delay(modbus_t *ctx);
|
||||
|
||||
MODBUS_END_DECLS
|
||||
|
||||
#endif /* MODBUS_RTU_H */
|
||||
44
Applications/qModMaster/3rdparty/libmodbus/modbus-tcp-private.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef MODBUS_TCP_PRIVATE_H
|
||||
#define MODBUS_TCP_PRIVATE_H
|
||||
|
||||
#define _MODBUS_TCP_HEADER_LENGTH 7
|
||||
#define _MODBUS_TCP_PRESET_REQ_LENGTH 12
|
||||
#define _MODBUS_TCP_PRESET_RSP_LENGTH 8
|
||||
|
||||
#define _MODBUS_TCP_CHECKSUM_LENGTH 0
|
||||
|
||||
/* In both structures, the transaction ID must be placed on first position
|
||||
to have a quick access not dependant of the TCP backend */
|
||||
typedef struct _modbus_tcp {
|
||||
/* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b
|
||||
(page 23/46):
|
||||
The transaction identifier is used to associate the future response
|
||||
with the request. This identifier is unique on each TCP connection. */
|
||||
uint16_t t_id;
|
||||
/* TCP port */
|
||||
int port;
|
||||
/* IP address */
|
||||
char ip[16];
|
||||
} modbus_tcp_t;
|
||||
|
||||
#define _MODBUS_TCP_PI_NODE_LENGTH 1025
|
||||
#define _MODBUS_TCP_PI_SERVICE_LENGTH 32
|
||||
|
||||
typedef struct _modbus_tcp_pi {
|
||||
/* Transaction ID */
|
||||
uint16_t t_id;
|
||||
/* TCP port */
|
||||
int port;
|
||||
/* Node */
|
||||
char node[_MODBUS_TCP_PI_NODE_LENGTH];
|
||||
/* Service */
|
||||
char service[_MODBUS_TCP_PI_SERVICE_LENGTH];
|
||||
} modbus_tcp_pi_t;
|
||||
|
||||
#endif /* MODBUS_TCP_PRIVATE_H */
|
||||
902
Applications/qModMaster/3rdparty/libmodbus/modbus-tcp.c
vendored
Normal file
@@ -0,0 +1,902 @@
|
||||
/*
|
||||
* Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define OS_WIN32
|
||||
/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
|
||||
* minwg32 headers check WINVER before allowing the use of these */
|
||||
# ifndef WINVER
|
||||
# define WINVER 0x0501
|
||||
# endif
|
||||
/* Already set in modbus-tcp.h but it seems order matters in VS2005 */
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# define SHUT_RDWR 2
|
||||
# define close closesocket
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <sys/ioctl.h>
|
||||
|
||||
#if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ < 5)
|
||||
# define OS_BSD
|
||||
# include <netinet/in_systm.h>
|
||||
#endif
|
||||
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/ip.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
#if !defined(MSG_NOSIGNAL)
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && !defined(MSG_DONTWAIT)
|
||||
#define MSG_DONTWAIT MSG_NONBLOCK
|
||||
#endif
|
||||
|
||||
#include "modbus-private.h"
|
||||
|
||||
#include "modbus-tcp.h"
|
||||
#include "modbus-tcp-private.h"
|
||||
|
||||
#ifdef OS_WIN32
|
||||
static int _modbus_tcp_init_win32(void)
|
||||
{
|
||||
/* Initialise Windows Socket API */
|
||||
WSADATA wsaData;
|
||||
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
fprintf(stderr, "WSAStartup() returned error code %d\n",
|
||||
(unsigned int)GetLastError());
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _modbus_set_slave(modbus_t *ctx, int slave)
|
||||
{
|
||||
/* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
|
||||
//***changed for QModMaster : <= 247***//
|
||||
if (slave >= 0 && slave <= 255) {
|
||||
ctx->slave = slave;
|
||||
} else if (slave == MODBUS_TCP_SLAVE) {
|
||||
/* The special value MODBUS_TCP_SLAVE (0xFF) can be used in TCP mode to
|
||||
* restore the default value. */
|
||||
ctx->slave = slave;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Builds a TCP request header */
|
||||
static int _modbus_tcp_build_request_basis(modbus_t *ctx, int function,
|
||||
int addr, int nb,
|
||||
uint8_t *req)
|
||||
{
|
||||
modbus_tcp_t *ctx_tcp = ctx->backend_data;
|
||||
|
||||
/* Increase transaction ID */
|
||||
if (ctx_tcp->t_id < UINT16_MAX)
|
||||
ctx_tcp->t_id++;
|
||||
else
|
||||
ctx_tcp->t_id = 0;
|
||||
req[0] = ctx_tcp->t_id >> 8;
|
||||
req[1] = ctx_tcp->t_id & 0x00ff;
|
||||
|
||||
/* Protocol Modbus */
|
||||
req[2] = 0;
|
||||
req[3] = 0;
|
||||
|
||||
/* Length will be defined later by set_req_length_tcp at offsets 4
|
||||
and 5 */
|
||||
|
||||
req[6] = ctx->slave;
|
||||
req[7] = function;
|
||||
req[8] = addr >> 8;
|
||||
req[9] = addr & 0x00ff;
|
||||
req[10] = nb >> 8;
|
||||
req[11] = nb & 0x00ff;
|
||||
|
||||
return _MODBUS_TCP_PRESET_REQ_LENGTH;
|
||||
}
|
||||
|
||||
/* Builds a TCP response header */
|
||||
static int _modbus_tcp_build_response_basis(sft_t *sft, uint8_t *rsp)
|
||||
{
|
||||
/* Extract from MODBUS Messaging on TCP/IP Implementation
|
||||
Guide V1.0b (page 23/46):
|
||||
The transaction identifier is used to associate the future
|
||||
response with the request. */
|
||||
rsp[0] = sft->t_id >> 8;
|
||||
rsp[1] = sft->t_id & 0x00ff;
|
||||
|
||||
/* Protocol Modbus */
|
||||
rsp[2] = 0;
|
||||
rsp[3] = 0;
|
||||
|
||||
/* Length will be set later by send_msg (4 and 5) */
|
||||
|
||||
/* The slave ID is copied from the indication */
|
||||
rsp[6] = sft->slave;
|
||||
rsp[7] = sft->function;
|
||||
|
||||
return _MODBUS_TCP_PRESET_RSP_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
static int _modbus_tcp_prepare_response_tid(const uint8_t *req, int *req_length)
|
||||
{
|
||||
return (req[0] << 8) + req[1];
|
||||
}
|
||||
|
||||
static int _modbus_tcp_send_msg_pre(uint8_t *req, int req_length)
|
||||
{
|
||||
/* Substract the header length to the message length */
|
||||
int mbap_length = req_length - 6;
|
||||
|
||||
req[4] = mbap_length >> 8;
|
||||
req[5] = mbap_length & 0x00FF;
|
||||
|
||||
return req_length;
|
||||
}
|
||||
|
||||
static ssize_t _modbus_tcp_send(modbus_t *ctx, const uint8_t *req, int req_length)
|
||||
{
|
||||
/* MSG_NOSIGNAL
|
||||
Requests not to send SIGPIPE on errors on stream oriented
|
||||
sockets when the other end breaks the connection. The EPIPE
|
||||
error is still returned. */
|
||||
return send(ctx->s, (const char *)req, req_length, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
static int _modbus_tcp_receive(modbus_t *ctx, uint8_t *req) {
|
||||
return _modbus_receive_msg(ctx, req, MSG_INDICATION);
|
||||
}
|
||||
|
||||
static ssize_t _modbus_tcp_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length) {
|
||||
return recv(ctx->s, (char *)rsp, rsp_length, 0);
|
||||
}
|
||||
|
||||
static int _modbus_tcp_check_integrity(modbus_t *ctx, uint8_t *msg, const int msg_length)
|
||||
{
|
||||
return msg_length;
|
||||
}
|
||||
|
||||
static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, const uint8_t *req,
|
||||
const uint8_t *rsp, int rsp_length)
|
||||
{
|
||||
/* Check transaction ID */
|
||||
if (req[0] != rsp[0] || req[1] != rsp[1]) {
|
||||
if (ctx->debug) {
|
||||
fprintf(stderr, "Invalid transaction ID received 0x%X (not 0x%X)\n",
|
||||
(rsp[0] << 8) + rsp[1], (req[0] << 8) + req[1]);
|
||||
}
|
||||
errno = EMBBADDATA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check protocol ID */
|
||||
if (rsp[2] != 0x0 && rsp[3] != 0x0) {
|
||||
if (ctx->debug) {
|
||||
fprintf(stderr, "Invalid protocol ID received 0x%X (not 0x0)\n",
|
||||
(rsp[2] << 8) + rsp[3]);
|
||||
}
|
||||
errno = EMBBADDATA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _modbus_tcp_set_ipv4_options(int s)
|
||||
{
|
||||
int rc;
|
||||
int option;
|
||||
|
||||
/* Set the TCP no delay flag */
|
||||
/* SOL_TCP = IPPROTO_TCP */
|
||||
option = 1;
|
||||
rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
|
||||
(const void *)&option, sizeof(int));
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If the OS does not offer SOCK_NONBLOCK, fall back to setting FIONBIO to
|
||||
* make sockets non-blocking */
|
||||
/* Do not care about the return value, this is optional */
|
||||
#if !defined(SOCK_NONBLOCK) && defined(FIONBIO)
|
||||
#ifdef OS_WIN32
|
||||
{
|
||||
/* Setting FIONBIO expects an unsigned long according to MSDN */
|
||||
u_long loption = 1;
|
||||
ioctlsocket(s, FIONBIO, &loption);
|
||||
}
|
||||
#else
|
||||
option = 1;
|
||||
ioctl(s, FIONBIO, &option);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef OS_WIN32
|
||||
/**
|
||||
* Cygwin defines IPTOS_LOWDELAY but can't handle that flag so it's
|
||||
* necessary to workaround that problem.
|
||||
**/
|
||||
/* Set the IP low delay option */
|
||||
option = IPTOS_LOWDELAY;
|
||||
rc = setsockopt(s, IPPROTO_IP, IP_TOS,
|
||||
(const void *)&option, sizeof(int));
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen,
|
||||
const struct timeval *ro_tv)
|
||||
{
|
||||
int rc = connect(sockfd, addr, addrlen);
|
||||
|
||||
#ifdef OS_WIN32
|
||||
int wsaError = 0;
|
||||
if (rc == -1) {
|
||||
wsaError = WSAGetLastError();
|
||||
}
|
||||
|
||||
if (wsaError == WSAEWOULDBLOCK || wsaError == WSAEINPROGRESS) {
|
||||
#else
|
||||
if (rc == -1 && errno == EINPROGRESS) {
|
||||
#endif
|
||||
fd_set wset;
|
||||
int optval;
|
||||
socklen_t optlen = sizeof(optval);
|
||||
struct timeval tv = *ro_tv;
|
||||
|
||||
/* Wait to be available in writing */
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(sockfd, &wset);
|
||||
rc = select(sockfd + 1, NULL, &wset, NULL, &tv);
|
||||
if (rc <= 0) {
|
||||
/* Timeout or fail */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The connection is established if SO_ERROR and optval are set to 0 */
|
||||
rc = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen);
|
||||
if (rc == 0 && optval == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
errno = ECONNREFUSED;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Establishes a modbus TCP connection with a Modbus server. */
|
||||
static int _modbus_tcp_connect(modbus_t *ctx)
|
||||
{
|
||||
int rc;
|
||||
/* Specialized version of sockaddr for Internet socket address (same size) */
|
||||
struct sockaddr_in addr;
|
||||
modbus_tcp_t *ctx_tcp = ctx->backend_data;
|
||||
int flags = SOCK_STREAM;
|
||||
|
||||
#ifdef OS_WIN32
|
||||
if (_modbus_tcp_init_win32() == -1) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
flags |= SOCK_CLOEXEC;
|
||||
#endif
|
||||
|
||||
#ifdef SOCK_NONBLOCK
|
||||
flags |= SOCK_NONBLOCK;
|
||||
#endif
|
||||
|
||||
ctx->s = socket(PF_INET, flags, 0);
|
||||
if (ctx->s == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = _modbus_tcp_set_ipv4_options(ctx->s);
|
||||
if (rc == -1) {
|
||||
close(ctx->s);
|
||||
ctx->s = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->debug) {
|
||||
printf("Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port);
|
||||
}
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(ctx_tcp->port);
|
||||
addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
|
||||
rc = _connect(ctx->s, (struct sockaddr *)&addr, sizeof(addr), &ctx->response_timeout);
|
||||
if (rc == -1) {
|
||||
close(ctx->s);
|
||||
ctx->s = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Establishes a modbus TCP PI connection with a Modbus server. */
|
||||
static int _modbus_tcp_pi_connect(modbus_t *ctx)
|
||||
{
|
||||
int rc;
|
||||
struct addrinfo *ai_list;
|
||||
struct addrinfo *ai_ptr;
|
||||
struct addrinfo ai_hints;
|
||||
modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data;
|
||||
|
||||
#ifdef OS_WIN32
|
||||
if (_modbus_tcp_init_win32() == -1) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&ai_hints, 0, sizeof(ai_hints));
|
||||
#ifdef AI_ADDRCONFIG
|
||||
ai_hints.ai_flags |= AI_ADDRCONFIG;
|
||||
#endif
|
||||
ai_hints.ai_family = AF_UNSPEC;
|
||||
ai_hints.ai_socktype = SOCK_STREAM;
|
||||
ai_hints.ai_addr = NULL;
|
||||
ai_hints.ai_canonname = NULL;
|
||||
ai_hints.ai_next = NULL;
|
||||
|
||||
ai_list = NULL;
|
||||
rc = getaddrinfo(ctx_tcp_pi->node, ctx_tcp_pi->service,
|
||||
&ai_hints, &ai_list);
|
||||
if (rc != 0) {
|
||||
if (ctx->debug) {
|
||||
fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc));
|
||||
}
|
||||
errno = ECONNREFUSED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
|
||||
int flags = ai_ptr->ai_socktype;
|
||||
int s;
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
flags |= SOCK_CLOEXEC;
|
||||
#endif
|
||||
|
||||
#ifdef SOCK_NONBLOCK
|
||||
flags |= SOCK_NONBLOCK;
|
||||
#endif
|
||||
|
||||
s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol);
|
||||
if (s < 0)
|
||||
continue;
|
||||
|
||||
if (ai_ptr->ai_family == AF_INET)
|
||||
_modbus_tcp_set_ipv4_options(s);
|
||||
|
||||
if (ctx->debug) {
|
||||
printf("Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service);
|
||||
}
|
||||
|
||||
rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout);
|
||||
if (rc == -1) {
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx->s = s;
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai_list);
|
||||
|
||||
if (ctx->s < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Closes the network connection and socket in TCP mode */
|
||||
static void _modbus_tcp_close(modbus_t *ctx)
|
||||
{
|
||||
if (ctx->s != -1) {
|
||||
shutdown(ctx->s, SHUT_RDWR);
|
||||
close(ctx->s);
|
||||
ctx->s = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int _modbus_tcp_flush(modbus_t *ctx)
|
||||
{
|
||||
int rc;
|
||||
int rc_sum = 0;
|
||||
|
||||
do {
|
||||
/* Extract the garbage from the socket */
|
||||
char devnull[MODBUS_TCP_MAX_ADU_LENGTH];
|
||||
#ifndef OS_WIN32
|
||||
rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, MSG_DONTWAIT);
|
||||
#else
|
||||
/* On Win32, it's a bit more complicated to not wait */
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(ctx->s, &rset);
|
||||
rc = select(ctx->s+1, &rset, NULL, NULL, &tv);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc == 1) {
|
||||
/* There is data to flush */
|
||||
rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, 0);
|
||||
}
|
||||
#endif
|
||||
if (rc > 0) {
|
||||
rc_sum += rc;
|
||||
}
|
||||
} while (rc == MODBUS_TCP_MAX_ADU_LENGTH);
|
||||
|
||||
return rc_sum;
|
||||
}
|
||||
|
||||
/* Listens for any request from one or many modbus masters in TCP */
|
||||
int modbus_tcp_listen(modbus_t *ctx, int nb_connection)
|
||||
{
|
||||
int new_s;
|
||||
int enable;
|
||||
struct sockaddr_in addr;
|
||||
modbus_tcp_t *ctx_tcp;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx_tcp = ctx->backend_data;
|
||||
|
||||
#ifdef OS_WIN32
|
||||
if (_modbus_tcp_init_win32() == -1) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
new_s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (new_s == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
enable = 1;
|
||||
if (setsockopt(new_s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&enable, sizeof(enable)) == -1) {
|
||||
close(new_s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
/* If the modbus port is < to 1024, we need the setuid root. */
|
||||
addr.sin_port = htons(ctx_tcp->port);
|
||||
if (ctx_tcp->ip[0] == '0') {
|
||||
/* Listen any addresses */
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
} else {
|
||||
/* Listen only specified IP address */
|
||||
addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
|
||||
}
|
||||
if (bind(new_s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
close(new_s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(new_s, nb_connection) == -1) {
|
||||
close(new_s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return new_s;
|
||||
}
|
||||
|
||||
int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection)
|
||||
{
|
||||
int rc;
|
||||
struct addrinfo *ai_list;
|
||||
struct addrinfo *ai_ptr;
|
||||
struct addrinfo ai_hints;
|
||||
const char *node;
|
||||
const char *service;
|
||||
int new_s;
|
||||
modbus_tcp_pi_t *ctx_tcp_pi;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx_tcp_pi = ctx->backend_data;
|
||||
|
||||
#ifdef OS_WIN32
|
||||
if (_modbus_tcp_init_win32() == -1) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ctx_tcp_pi->node[0] == 0) {
|
||||
node = NULL; /* == any */
|
||||
} else {
|
||||
node = ctx_tcp_pi->node;
|
||||
}
|
||||
|
||||
if (ctx_tcp_pi->service[0] == 0) {
|
||||
service = "502";
|
||||
} else {
|
||||
service = ctx_tcp_pi->service;
|
||||
}
|
||||
|
||||
memset(&ai_hints, 0, sizeof (ai_hints));
|
||||
/* If node is not NULL, than the AI_PASSIVE flag is ignored. */
|
||||
ai_hints.ai_flags |= AI_PASSIVE;
|
||||
#ifdef AI_ADDRCONFIG
|
||||
ai_hints.ai_flags |= AI_ADDRCONFIG;
|
||||
#endif
|
||||
ai_hints.ai_family = AF_UNSPEC;
|
||||
ai_hints.ai_socktype = SOCK_STREAM;
|
||||
ai_hints.ai_addr = NULL;
|
||||
ai_hints.ai_canonname = NULL;
|
||||
ai_hints.ai_next = NULL;
|
||||
|
||||
ai_list = NULL;
|
||||
rc = getaddrinfo(node, service, &ai_hints, &ai_list);
|
||||
if (rc != 0) {
|
||||
if (ctx->debug) {
|
||||
fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc));
|
||||
}
|
||||
errno = ECONNREFUSED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_s = -1;
|
||||
for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
|
||||
int s;
|
||||
|
||||
s = socket(ai_ptr->ai_family, ai_ptr->ai_socktype,
|
||||
ai_ptr->ai_protocol);
|
||||
if (s < 0) {
|
||||
if (ctx->debug) {
|
||||
perror("socket");
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
int enable = 1;
|
||||
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(void *)&enable, sizeof (enable));
|
||||
if (rc != 0) {
|
||||
close(s);
|
||||
if (ctx->debug) {
|
||||
perror("setsockopt");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
rc = bind(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
|
||||
if (rc != 0) {
|
||||
close(s);
|
||||
if (ctx->debug) {
|
||||
perror("bind");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = listen(s, nb_connection);
|
||||
if (rc != 0) {
|
||||
close(s);
|
||||
if (ctx->debug) {
|
||||
perror("listen");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
new_s = s;
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(ai_list);
|
||||
|
||||
if (new_s < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return new_s;
|
||||
}
|
||||
|
||||
int modbus_tcp_accept(modbus_t *ctx, int *s)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
#ifdef HAVE_ACCEPT4
|
||||
/* Inherit socket flags and use accept4 call */
|
||||
ctx->s = accept4(*s, (struct sockaddr *)&addr, &addrlen, SOCK_CLOEXEC);
|
||||
#else
|
||||
ctx->s = accept(*s, (struct sockaddr *)&addr, &addrlen);
|
||||
#endif
|
||||
|
||||
if (ctx->s == -1) {
|
||||
close(*s);
|
||||
*s = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->debug) {
|
||||
printf("The client connection from %s is accepted\n",
|
||||
inet_ntoa(addr.sin_addr));
|
||||
}
|
||||
|
||||
return ctx->s;
|
||||
}
|
||||
|
||||
int modbus_tcp_pi_accept(modbus_t *ctx, int *s)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
#ifdef HAVE_ACCEPT4
|
||||
/* Inherit socket flags and use accept4 call */
|
||||
ctx->s = accept4(*s, (struct sockaddr *)&addr, &addrlen, SOCK_CLOEXEC);
|
||||
#else
|
||||
ctx->s = accept(*s, (struct sockaddr *)&addr, &addrlen);
|
||||
#endif
|
||||
if (ctx->s == -1) {
|
||||
close(*s);
|
||||
*s = -1;
|
||||
}
|
||||
|
||||
if (ctx->debug) {
|
||||
printf("The client connection is accepted.\n");
|
||||
}
|
||||
|
||||
return ctx->s;
|
||||
}
|
||||
|
||||
static int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read)
|
||||
{
|
||||
int s_rc;
|
||||
while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) {
|
||||
if (errno == EINTR) {
|
||||
if (ctx->debug) {
|
||||
fprintf(stderr, "A non blocked signal was caught\n");
|
||||
}
|
||||
/* Necessary after an error */
|
||||
FD_ZERO(rset);
|
||||
FD_SET(ctx->s, rset);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_rc == 0) {
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s_rc;
|
||||
}
|
||||
|
||||
static void _modbus_tcp_free(modbus_t *ctx) {
|
||||
free(ctx->backend_data);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
const modbus_backend_t _modbus_tcp_backend = {
|
||||
_MODBUS_BACKEND_TYPE_TCP,
|
||||
_MODBUS_TCP_HEADER_LENGTH,
|
||||
_MODBUS_TCP_CHECKSUM_LENGTH,
|
||||
MODBUS_TCP_MAX_ADU_LENGTH,
|
||||
_modbus_set_slave,
|
||||
_modbus_tcp_build_request_basis,
|
||||
_modbus_tcp_build_response_basis,
|
||||
_modbus_tcp_prepare_response_tid,
|
||||
_modbus_tcp_send_msg_pre,
|
||||
_modbus_tcp_send,
|
||||
_modbus_tcp_receive,
|
||||
_modbus_tcp_recv,
|
||||
_modbus_tcp_check_integrity,
|
||||
_modbus_tcp_pre_check_confirmation,
|
||||
_modbus_tcp_connect,
|
||||
_modbus_tcp_close,
|
||||
_modbus_tcp_flush,
|
||||
_modbus_tcp_select,
|
||||
_modbus_tcp_free
|
||||
};
|
||||
|
||||
|
||||
const modbus_backend_t _modbus_tcp_pi_backend = {
|
||||
_MODBUS_BACKEND_TYPE_TCP,
|
||||
_MODBUS_TCP_HEADER_LENGTH,
|
||||
_MODBUS_TCP_CHECKSUM_LENGTH,
|
||||
MODBUS_TCP_MAX_ADU_LENGTH,
|
||||
_modbus_set_slave,
|
||||
_modbus_tcp_build_request_basis,
|
||||
_modbus_tcp_build_response_basis,
|
||||
_modbus_tcp_prepare_response_tid,
|
||||
_modbus_tcp_send_msg_pre,
|
||||
_modbus_tcp_send,
|
||||
_modbus_tcp_receive,
|
||||
_modbus_tcp_recv,
|
||||
_modbus_tcp_check_integrity,
|
||||
_modbus_tcp_pre_check_confirmation,
|
||||
_modbus_tcp_pi_connect,
|
||||
_modbus_tcp_close,
|
||||
_modbus_tcp_flush,
|
||||
_modbus_tcp_select,
|
||||
_modbus_tcp_free
|
||||
};
|
||||
|
||||
modbus_t* modbus_new_tcp(const char *ip, int port)
|
||||
{
|
||||
modbus_t *ctx;
|
||||
modbus_tcp_t *ctx_tcp;
|
||||
size_t dest_size;
|
||||
size_t ret_size;
|
||||
|
||||
#if defined(OS_BSD)
|
||||
/* MSG_NOSIGNAL is unsupported on *BSD so we install an ignore
|
||||
handler for SIGPIPE. */
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGPIPE, &sa, NULL) < 0) {
|
||||
/* The debug flag can't be set here... */
|
||||
fprintf(stderr, "Coud not install SIGPIPE handler.\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx = (modbus_t *)malloc(sizeof(modbus_t));
|
||||
_modbus_init_common(ctx);
|
||||
|
||||
/* Could be changed after to reach a remote serial Modbus device */
|
||||
ctx->slave = MODBUS_TCP_SLAVE;
|
||||
|
||||
ctx->backend = &_modbus_tcp_backend;
|
||||
|
||||
ctx->backend_data = (modbus_tcp_t *)malloc(sizeof(modbus_tcp_t));
|
||||
ctx_tcp = (modbus_tcp_t *)ctx->backend_data;
|
||||
|
||||
if (ip != NULL) {
|
||||
dest_size = sizeof(char) * 16;
|
||||
ret_size = strlcpy(ctx_tcp->ip, ip, dest_size);
|
||||
if (ret_size == 0) {
|
||||
fprintf(stderr, "The IP string is empty\n");
|
||||
modbus_free(ctx);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ret_size >= dest_size) {
|
||||
fprintf(stderr, "The IP string has been truncated\n");
|
||||
modbus_free(ctx);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ctx_tcp->ip[0] = '0';
|
||||
}
|
||||
ctx_tcp->port = port;
|
||||
ctx_tcp->t_id = 0;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
modbus_t* modbus_new_tcp_pi(const char *node, const char *service)
|
||||
{
|
||||
modbus_t *ctx;
|
||||
modbus_tcp_pi_t *ctx_tcp_pi;
|
||||
size_t dest_size;
|
||||
size_t ret_size;
|
||||
|
||||
ctx = (modbus_t *)malloc(sizeof(modbus_t));
|
||||
_modbus_init_common(ctx);
|
||||
|
||||
/* Could be changed after to reach a remote serial Modbus device */
|
||||
ctx->slave = MODBUS_TCP_SLAVE;
|
||||
|
||||
ctx->backend = &_modbus_tcp_pi_backend;
|
||||
|
||||
ctx->backend_data = (modbus_tcp_pi_t *)malloc(sizeof(modbus_tcp_pi_t));
|
||||
ctx_tcp_pi = (modbus_tcp_pi_t *)ctx->backend_data;
|
||||
|
||||
if (node == NULL) {
|
||||
/* The node argument can be empty to indicate any hosts */
|
||||
ctx_tcp_pi->node[0] = 0;
|
||||
} else {
|
||||
dest_size = sizeof(char) * _MODBUS_TCP_PI_NODE_LENGTH;
|
||||
ret_size = strlcpy(ctx_tcp_pi->node, node, dest_size);
|
||||
if (ret_size == 0) {
|
||||
fprintf(stderr, "The node string is empty\n");
|
||||
modbus_free(ctx);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ret_size >= dest_size) {
|
||||
fprintf(stderr, "The node string has been truncated\n");
|
||||
modbus_free(ctx);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (service != NULL) {
|
||||
dest_size = sizeof(char) * _MODBUS_TCP_PI_SERVICE_LENGTH;
|
||||
ret_size = strlcpy(ctx_tcp_pi->service, service, dest_size);
|
||||
} else {
|
||||
/* Empty service is not allowed, error catched below. */
|
||||
ret_size = 0;
|
||||
}
|
||||
|
||||
if (ret_size == 0) {
|
||||
fprintf(stderr, "The service string is empty\n");
|
||||
modbus_free(ctx);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ret_size >= dest_size) {
|
||||
fprintf(stderr, "The service string has been truncated\n");
|
||||
modbus_free(ctx);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx_tcp_pi->t_id = 0;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
52
Applications/qModMaster/3rdparty/libmodbus/modbus-tcp.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright © 2001-2010 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef MODBUS_TCP_H
|
||||
#define MODBUS_TCP_H
|
||||
|
||||
#include "modbus.h"
|
||||
|
||||
MODBUS_BEGIN_DECLS
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Win32 with MinGW, supplement to <errno.h> */
|
||||
#include <winsock2.h>
|
||||
#if !defined(ECONNRESET)
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#endif
|
||||
#if !defined(ECONNREFUSED)
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#endif
|
||||
#if !defined(ETIMEDOUT)
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#endif
|
||||
#if !defined(ENOPROTOOPT)
|
||||
#define ENOPROTOOPT WSAENOPROTOOPT
|
||||
#endif
|
||||
#if !defined(EINPROGRESS)
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MODBUS_TCP_DEFAULT_PORT 502
|
||||
#define MODBUS_TCP_SLAVE 0xFF
|
||||
|
||||
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
|
||||
* TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes
|
||||
*/
|
||||
#define MODBUS_TCP_MAX_ADU_LENGTH 260
|
||||
|
||||
MODBUS_API modbus_t* modbus_new_tcp(const char *ip_address, int port);
|
||||
MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
|
||||
MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s);
|
||||
|
||||
MODBUS_API modbus_t* modbus_new_tcp_pi(const char *node, const char *service);
|
||||
MODBUS_API int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection);
|
||||
MODBUS_API int modbus_tcp_pi_accept(modbus_t *ctx, int *s);
|
||||
|
||||
MODBUS_END_DECLS
|
||||
|
||||
#endif /* MODBUS_TCP_H */
|
||||
53
Applications/qModMaster/3rdparty/libmodbus/modbus-version.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MODBUS_VERSION_H
|
||||
#define MODBUS_VERSION_H
|
||||
|
||||
/* The major version, (1, if %LIBMODBUS_VERSION is 1.2.3) */
|
||||
#define LIBMODBUS_VERSION_MAJOR (3)
|
||||
|
||||
/* The minor version (2, if %LIBMODBUS_VERSION is 1.2.3) */
|
||||
#define LIBMODBUS_VERSION_MINOR (1)
|
||||
|
||||
/* The micro version (3, if %LIBMODBUS_VERSION is 1.2.3) */
|
||||
#define LIBMODBUS_VERSION_MICRO (4)
|
||||
|
||||
/* The full version, like 1.2.3 */
|
||||
#define LIBMODBUS_VERSION 3.1.4
|
||||
|
||||
/* The full version, in string form (suited for string concatenation)
|
||||
*/
|
||||
#define LIBMODBUS_VERSION_STRING "3.1.4"
|
||||
|
||||
/* Numerically encoded version, like 0x010203 */
|
||||
#define LIBMODBUS_VERSION_HEX ((LIBMODBUS_VERSION_MAJOR << 24) | \
|
||||
(LIBMODBUS_VERSION_MINOR << 16) | \
|
||||
(LIBMODBUS_VERSION_MICRO << 8))
|
||||
|
||||
/* Evaluates to True if the version is greater than @major, @minor and @micro
|
||||
*/
|
||||
#define LIBMODBUS_VERSION_CHECK(major,minor,micro) \
|
||||
(LIBMODBUS_VERSION_MAJOR > (major) || \
|
||||
(LIBMODBUS_VERSION_MAJOR == (major) && \
|
||||
LIBMODBUS_VERSION_MINOR > (minor)) || \
|
||||
(LIBMODBUS_VERSION_MAJOR == (major) && \
|
||||
LIBMODBUS_VERSION_MINOR == (minor) && \
|
||||
LIBMODBUS_VERSION_MICRO >= (micro)))
|
||||
|
||||
#endif /* MODBUS_VERSION_H */
|
||||
1867
Applications/qModMaster/3rdparty/libmodbus/modbus.c
vendored
Normal file
289
Applications/qModMaster/3rdparty/libmodbus/modbus.h
vendored
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#ifndef MODBUS_H
|
||||
#define MODBUS_H
|
||||
|
||||
/* Add this for macros that defined unix flavor */
|
||||
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include "stdint.h"
|
||||
#endif
|
||||
|
||||
#include "modbus-version.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# if defined(DLLBUILD)
|
||||
/* define DLLBUILD when building the DLL */
|
||||
# define MODBUS_API __declspec(dllexport)
|
||||
# else
|
||||
# define MODBUS_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define MODBUS_API
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define MODBUS_BEGIN_DECLS extern "C" {
|
||||
# define MODBUS_END_DECLS }
|
||||
#else
|
||||
# define MODBUS_BEGIN_DECLS
|
||||
# define MODBUS_END_DECLS
|
||||
#endif
|
||||
|
||||
MODBUS_BEGIN_DECLS
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef OFF
|
||||
#define OFF 0
|
||||
#endif
|
||||
|
||||
#ifndef ON
|
||||
#define ON 1
|
||||
#endif
|
||||
|
||||
/* Modbus function codes */
|
||||
#define MODBUS_FC_READ_COILS 0x01
|
||||
#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
|
||||
#define MODBUS_FC_READ_HOLDING_REGISTERS 0x03
|
||||
#define MODBUS_FC_READ_INPUT_REGISTERS 0x04
|
||||
#define MODBUS_FC_WRITE_SINGLE_COIL 0x05
|
||||
#define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06
|
||||
#define MODBUS_FC_READ_EXCEPTION_STATUS 0x07
|
||||
#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
|
||||
#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
|
||||
#define MODBUS_FC_REPORT_SLAVE_ID 0x11
|
||||
#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
|
||||
#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
|
||||
|
||||
#define MODBUS_BROADCAST_ADDRESS 0
|
||||
|
||||
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
|
||||
* Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
|
||||
* (chapter 6 section 11 page 29)
|
||||
* Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0)
|
||||
*/
|
||||
#define MODBUS_MAX_READ_BITS 2000
|
||||
#define MODBUS_MAX_WRITE_BITS 1968
|
||||
|
||||
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
|
||||
* Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
|
||||
* (chapter 6 section 12 page 31)
|
||||
* Quantity of Registers to write (2 bytes) 1 to 123 (0x7B)
|
||||
* (chapter 6 section 17 page 38)
|
||||
* Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79)
|
||||
*/
|
||||
#define MODBUS_MAX_READ_REGISTERS 125
|
||||
#define MODBUS_MAX_WRITE_REGISTERS 123
|
||||
#define MODBUS_MAX_WR_WRITE_REGISTERS 121
|
||||
#define MODBUS_MAX_WR_READ_REGISTERS 125
|
||||
|
||||
/* The size of the MODBUS PDU is limited by the size constraint inherited from
|
||||
* the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256
|
||||
* bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server
|
||||
* address (1 byte) - CRC (2 bytes) = 253 bytes.
|
||||
*/
|
||||
#define MODBUS_MAX_PDU_LENGTH 253
|
||||
|
||||
/* Consequently:
|
||||
* - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256
|
||||
* bytes.
|
||||
* - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
|
||||
* so the maximum of both backend in 260 bytes. This size can used to allocate
|
||||
* an array of bytes to store responses and it will be compatible with the two
|
||||
* backends.
|
||||
*/
|
||||
#define MODBUS_MAX_ADU_LENGTH 260
|
||||
|
||||
/* Random number to avoid errno conflicts */
|
||||
#define MODBUS_ENOBASE 112345678
|
||||
|
||||
/* Protocol exceptions */
|
||||
enum {
|
||||
MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
|
||||
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
|
||||
MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
|
||||
MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
|
||||
MODBUS_EXCEPTION_ACKNOWLEDGE,
|
||||
MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
|
||||
MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
|
||||
MODBUS_EXCEPTION_MEMORY_PARITY,
|
||||
MODBUS_EXCEPTION_NOT_DEFINED,
|
||||
MODBUS_EXCEPTION_GATEWAY_PATH,
|
||||
MODBUS_EXCEPTION_GATEWAY_TARGET,
|
||||
MODBUS_EXCEPTION_MAX
|
||||
};
|
||||
|
||||
#define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
|
||||
#define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
|
||||
#define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
|
||||
#define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
|
||||
#define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
|
||||
#define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
|
||||
#define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
|
||||
#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
|
||||
#define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
|
||||
#define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
|
||||
|
||||
/* Native libmodbus error codes */
|
||||
#define EMBBADCRC (EMBXGTAR + 1)
|
||||
#define EMBBADDATA (EMBXGTAR + 2)
|
||||
#define EMBBADEXC (EMBXGTAR + 3)
|
||||
#define EMBUNKEXC (EMBXGTAR + 4)
|
||||
#define EMBMDATA (EMBXGTAR + 5)
|
||||
#define EMBBADSLAVE (EMBXGTAR + 6)
|
||||
|
||||
extern const unsigned int libmodbus_version_major;
|
||||
extern const unsigned int libmodbus_version_minor;
|
||||
extern const unsigned int libmodbus_version_micro;
|
||||
|
||||
typedef struct _modbus modbus_t;
|
||||
|
||||
typedef struct {
|
||||
int nb_bits;
|
||||
int start_bits;
|
||||
int nb_input_bits;
|
||||
int start_input_bits;
|
||||
int nb_input_registers;
|
||||
int start_input_registers;
|
||||
int nb_registers;
|
||||
int start_registers;
|
||||
uint8_t *tab_bits;
|
||||
uint8_t *tab_input_bits;
|
||||
uint16_t *tab_input_registers;
|
||||
uint16_t *tab_registers;
|
||||
} modbus_mapping_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MODBUS_ERROR_RECOVERY_NONE = 0,
|
||||
MODBUS_ERROR_RECOVERY_LINK = (1<<1),
|
||||
MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
|
||||
} modbus_error_recovery_mode;
|
||||
|
||||
MODBUS_API int modbus_set_slave(modbus_t* ctx, int slave);
|
||||
MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
|
||||
MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
|
||||
MODBUS_API int modbus_get_socket(modbus_t *ctx);
|
||||
|
||||
MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
|
||||
MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
|
||||
|
||||
MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
|
||||
MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
|
||||
|
||||
MODBUS_API int modbus_get_header_length(modbus_t *ctx);
|
||||
|
||||
MODBUS_API int modbus_connect(modbus_t *ctx);
|
||||
MODBUS_API void modbus_close(modbus_t *ctx);
|
||||
|
||||
MODBUS_API void modbus_free(modbus_t *ctx);
|
||||
|
||||
MODBUS_API int modbus_flush(modbus_t *ctx);
|
||||
MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);
|
||||
|
||||
MODBUS_API const char *modbus_strerror(int errnum);
|
||||
|
||||
MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
|
||||
MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
|
||||
MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
|
||||
MODBUS_API int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
|
||||
MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
|
||||
MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, int value);
|
||||
MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
|
||||
MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
|
||||
MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
|
||||
MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,
|
||||
const uint16_t *src, int read_addr, int read_nb,
|
||||
uint16_t *dest);
|
||||
MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
|
||||
|
||||
MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address(
|
||||
unsigned int start_bits, unsigned int nb_bits,
|
||||
unsigned int start_input_bits, unsigned int nb_input_bits,
|
||||
unsigned int start_registers, unsigned int nb_registers,
|
||||
unsigned int start_input_registers, unsigned int nb_input_registers);
|
||||
|
||||
MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
|
||||
int nb_registers, int nb_input_registers);
|
||||
MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
|
||||
|
||||
MODBUS_API int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length);
|
||||
|
||||
MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);
|
||||
|
||||
MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
|
||||
|
||||
MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req,
|
||||
int req_length, modbus_mapping_t *mb_mapping);
|
||||
MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
|
||||
unsigned int exception_code);
|
||||
|
||||
/**
|
||||
* UTILS FUNCTIONS
|
||||
**/
|
||||
|
||||
#define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
|
||||
#define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
|
||||
#define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
|
||||
(((int64_t)tab_int16[(index) ] << 48) + \
|
||||
((int64_t)tab_int16[(index) + 1] << 32) + \
|
||||
((int64_t)tab_int16[(index) + 2] << 16) + \
|
||||
(int64_t)tab_int16[(index) + 3])
|
||||
#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
|
||||
#define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
|
||||
#define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
|
||||
do { \
|
||||
tab_int8[(index)] = (value) >> 8; \
|
||||
tab_int8[(index) + 1] = (value) & 0xFF; \
|
||||
} while (0)
|
||||
#define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
|
||||
do { \
|
||||
tab_int16[(index) ] = (value) >> 16; \
|
||||
tab_int16[(index) + 1] = (value); \
|
||||
} while (0)
|
||||
#define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
|
||||
do { \
|
||||
tab_int16[(index) ] = (value) >> 48; \
|
||||
tab_int16[(index) + 1] = (value) >> 32; \
|
||||
tab_int16[(index) + 2] = (value) >> 16; \
|
||||
tab_int16[(index) + 3] = (value); \
|
||||
} while (0)
|
||||
|
||||
MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value);
|
||||
MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
|
||||
const uint8_t *tab_byte);
|
||||
MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits);
|
||||
MODBUS_API float modbus_get_float(const uint16_t *src);
|
||||
MODBUS_API float modbus_get_float_abcd(const uint16_t *src);
|
||||
MODBUS_API float modbus_get_float_dcba(const uint16_t *src);
|
||||
MODBUS_API float modbus_get_float_badc(const uint16_t *src);
|
||||
MODBUS_API float modbus_get_float_cdab(const uint16_t *src);
|
||||
|
||||
MODBUS_API void modbus_set_float(float f, uint16_t *dest);
|
||||
MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest);
|
||||
MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest);
|
||||
MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest);
|
||||
MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest);
|
||||
|
||||
#include "modbus-tcp.h"
|
||||
#include "modbus-rtu.h"
|
||||
|
||||
MODBUS_END_DECLS
|
||||
|
||||
#endif /* MODBUS_H */
|
||||
674
Applications/qModMaster/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -0,0 +1,8 @@
|
||||
[{000214A0-0000-0000-C000-000000000046}]
|
||||
Prop3=19,2
|
||||
[InternetShortcut]
|
||||
IDList=
|
||||
URL=http://www.html5webtemplates.co.uk/
|
||||
HotKey=0
|
||||
IconFile=C:\Windows\system32\SHELL32.dll
|
||||
IconIndex=277
|
||||
13
Applications/qModMaster/ManModbus/READ_ME/PLEASE READ.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Thanks for downloading this template from HTML5WebTemplates.co.uk
|
||||
|
||||
I hope that it suits your needs.
|
||||
|
||||
If you wish to remove the footer link (to http://www.html5webtemplates.co.uk/) I ask that you make a donation of £15 via Paypal.
|
||||
|
||||
You can make a donation at the following address:http://www.html5webtemplates.co.uk/faqs.html
|
||||
|
||||
If you have any questions please feel free to e-mail me at contact@html5webtemplates.co.uk
|
||||
|
||||
Best regards,
|
||||
|
||||
HTML5WebTemplates.co.uk
|
||||
@@ -0,0 +1,6 @@
|
||||
[InternetShortcut]
|
||||
URL=http://www.html5webtemplates.co.uk/faqs.html
|
||||
IDList=
|
||||
HotKey=0
|
||||
IconFile=C:\Windows\system32\SHELL32.dll
|
||||
IconIndex=44
|
||||
110
Applications/qModMaster/ManModbus/exceptions.html
Normal file
775
Applications/qModMaster/ManModbus/func_descr.html
Normal file
123
Applications/qModMaster/ManModbus/funcs.html
Normal file
282
Applications/qModMaster/ManModbus/index.html
Normal file
87
Applications/qModMaster/ManModbus/links.html
Normal file
@@ -0,0 +1,87 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=windows-1252" http-equiv="content-type">
|
||||
<title>MODBUS_MANUAL</title>
|
||||
<meta name="description" content="website description">
|
||||
<meta name="keywords" content="website keywords, website keywords">
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css" title="style">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="header">
|
||||
<div id="logo">
|
||||
<div id="logo_text"> <!-- class="logo_colour", allows you to change the colour of the text -->
|
||||
<h1><a href="index.html">MODBUS Manual<span class="logo_colour"></span></a></h1>
|
||||
<h2><br>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div id="menubar">
|
||||
<ul id="menu">
|
||||
<!-- put class="selected" in the li tag for the selected page - to highlight which page you're on -->
|
||||
<li><a href="index.html">oVERVIEW</a></li>
|
||||
<li><a href="funcs.html">FUNCs</a></li>
|
||||
<li><a href="func_descr.html">FUNCs DESCR</a></li>
|
||||
<li><a href="exceptions.html">EXCEPTIONS</a></li>
|
||||
<li class="selected"><a href="links.html">LINKS</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="site_content">
|
||||
<div class="sidebar">
|
||||
<!-- insert your sidebar items here -->
|
||||
<h3>Menu</h3>
|
||||
<ul>
|
||||
<li><a href="#links_modbus">MODBUS</a></li>
|
||||
<li><a href="#links_prog_libs">Programs - Libs</a></li>
|
||||
</ul>
|
||||
<br>
|
||||
</div>
|
||||
<div id="content">
|
||||
<!-- insert the page content here -->
|
||||
<h1><br>
|
||||
</h1>
|
||||
<h1> <a id="links_modbus">MODBUS</a></h1>
|
||||
<ul>
|
||||
<li><a target="_blank" href="www.modbus.org">Modbus org</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li> <a target="_blank" href="https://en.wikipedia.org/wiki/RS-232">RS-232</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://en.wikipedia.org/wiki/RS-485">RS-485</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://en.wikipedia.org/wiki/RS-422">RS-422</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol">TCP
|
||||
Protocol</a> </li>
|
||||
</ul>
|
||||
<h1> <a id="links_prog_libs">Programs - Libs</a></h1>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://sourceforge.net/projects/qmodmaster/">QModmaster</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://sourceforge.net/projects/pymodslave/">pyModSlave</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a target="_blank" href="http://libmodbus.org/">libmodbus C
|
||||
Library</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://github.com/ljean/modbus-tk">modbus-tk
|
||||
Python Library</a></li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer"> Copyright © textured_industrial | <a href="http://validator.w3.org/check?uri=referer">HTML5</a>
|
||||
| <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a> |
|
||||
<a href="http://www.html5webtemplates.co.uk">design from
|
||||
HTML5webtemplates.co.uk</a> </div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
Applications/qModMaster/ManModbus/style/Thumbs.db
Normal file
BIN
Applications/qModMaster/ManModbus/style/background.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
Applications/qModMaster/ManModbus/style/bullet.png
Normal file
|
After Width: | Height: | Size: 989 B |
BIN
Applications/qModMaster/ManModbus/style/graphic.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
Applications/qModMaster/ManModbus/style/header.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
Applications/qModMaster/ManModbus/style/link.png
Normal file
|
After Width: | Height: | Size: 911 B |
BIN
Applications/qModMaster/ManModbus/style/search.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
296
Applications/qModMaster/ManModbus/style/style.css
Normal file
@@ -0,0 +1,296 @@
|
||||
html
|
||||
{ height: 100%;}
|
||||
|
||||
*
|
||||
{ margin: 0;
|
||||
padding: 0;}
|
||||
|
||||
body
|
||||
{ font: normal .80em 'trebuchet ms', arial, sans-serif;
|
||||
background: #F0EFE2 url(background.png) repeat;
|
||||
color: #777;}
|
||||
|
||||
p
|
||||
{ padding: 0 0 20px 0;
|
||||
line-height: 1.7em;}
|
||||
|
||||
img
|
||||
{ border: 0;}
|
||||
|
||||
h1, h2, h3, h4, h5, h6
|
||||
{ font: normal 175% 'century gothic', arial, sans-serif;
|
||||
color: #43423F;
|
||||
margin: 0 0 15px 0;
|
||||
padding: 15px 0 5px 0;}
|
||||
|
||||
h2
|
||||
{ font: normal 175% 'century gothic', arial, sans-serif;
|
||||
color: #000;}
|
||||
|
||||
h4, h5, h6
|
||||
{ margin: 0;
|
||||
padding: 0 0 5px 0;
|
||||
font: normal 120% arial, sans-serif;
|
||||
color: #000;}
|
||||
|
||||
h5, h6
|
||||
{ font: italic 95% arial, sans-serif;
|
||||
padding: 0 0 15px 0;
|
||||
color: #000;}
|
||||
|
||||
h6
|
||||
{ color: #362C20;}
|
||||
|
||||
a, a:hover
|
||||
{ outline: none;
|
||||
text-decoration: underline;
|
||||
color: #000;}
|
||||
|
||||
a:hover
|
||||
{ text-decoration: none;}
|
||||
|
||||
.left
|
||||
{ float: left;
|
||||
width: auto;
|
||||
margin-right: 10px;}
|
||||
|
||||
.right
|
||||
{ float: right;
|
||||
width: auto;
|
||||
margin-left: 10px;}
|
||||
|
||||
.center
|
||||
{ display: block;
|
||||
text-align: center;
|
||||
margin: 20px auto;}
|
||||
|
||||
blockquote
|
||||
{ margin: 20px 0;
|
||||
padding: 10px 20px 0 20px;
|
||||
border: 1px solid #E5E5DB;
|
||||
background: #FFF;}
|
||||
|
||||
ul
|
||||
{ margin: 2px 0 22px 17px;}
|
||||
|
||||
ul li
|
||||
{ list-style-type: circle;
|
||||
margin: 0 0 6px 0;
|
||||
padding: 0 0 4px 5px;}
|
||||
|
||||
ol
|
||||
{ margin: 8px 0 22px 20px;}
|
||||
|
||||
ol li
|
||||
{ margin: 0 0 11px 0;}
|
||||
|
||||
#main, #logo, #menubar, #site_content, #footer
|
||||
{ margin-left: auto;
|
||||
margin-right: auto;}
|
||||
|
||||
#header
|
||||
{ background: #1D1D1D url(header.jpg) repeat;
|
||||
height: 240px;}
|
||||
|
||||
#logo
|
||||
{ width: 825px;
|
||||
position: relative;
|
||||
height: 168px;}
|
||||
|
||||
#logo #logo_text
|
||||
{ position: absolute;
|
||||
top: 20px;
|
||||
left: 0;}
|
||||
|
||||
#logo h1, #logo h2
|
||||
{ font: normal 300% 'century gothic', arial, sans-serif;
|
||||
border-bottom: 0;
|
||||
text-transform: none;
|
||||
margin: 0;}
|
||||
|
||||
#logo_text h1, #logo_text h1 a, #logo_text h1 a:hover
|
||||
{ padding: 22px 0 0 0;
|
||||
color: #FFF;
|
||||
letter-spacing: 0.1em;
|
||||
text-decoration: none;}
|
||||
|
||||
#logo_text h1 a .logo_colour
|
||||
{ color: #000;}
|
||||
|
||||
#logo_text h2
|
||||
{ font-size: 100%;
|
||||
padding: 4px 0 0 0;
|
||||
color: #DDD;}
|
||||
|
||||
#menubar
|
||||
{ width: 900px;
|
||||
height: 72px;
|
||||
padding: 0;
|
||||
background: transparent url(transparent_light.png) repeat;}
|
||||
|
||||
ul#menu, ul#menu li
|
||||
{ float: left;
|
||||
margin: 0;
|
||||
padding: 0;}
|
||||
|
||||
ul#menu li
|
||||
{ list-style: none;}
|
||||
|
||||
ul#menu li a
|
||||
{ letter-spacing: 0.1em;
|
||||
font: normal 100% arial, sans-serif;
|
||||
display: block;
|
||||
float: left;
|
||||
height: 37px;
|
||||
padding: 29px 26px 6px 26px;
|
||||
text-align: center;
|
||||
color: #000;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
background: transparent;}
|
||||
|
||||
ul#menu li a:hover, ul#menu li.selected a, ul#menu li.selected a:hover
|
||||
{ color: #FFF;
|
||||
background: transparent url(transparent.png) repeat;}
|
||||
|
||||
#site_content
|
||||
{ width: 854px;
|
||||
overflow: hidden;
|
||||
margin: 0 auto 0 auto;
|
||||
padding: 20px 24px 20px 20px;
|
||||
background: transparent url(transparent_light.png) repeat;}
|
||||
|
||||
.sidebar
|
||||
{ float: left;
|
||||
width: 190px;
|
||||
padding: 0 15px 20px 15px;}
|
||||
|
||||
.sidebar ul
|
||||
{ width: 178px;
|
||||
padding: 4px 0 0 0;
|
||||
margin: 4px 0 30px 0;}
|
||||
|
||||
.sidebar li
|
||||
{ list-style: none;
|
||||
padding: 0 0 7px 0; }
|
||||
|
||||
.sidebar li a, .sidebar li a:hover
|
||||
{ padding: 0 0 0 40px;
|
||||
display: block;
|
||||
background: transparent url(link.png) no-repeat left center;}
|
||||
|
||||
.sidebar li a.selected
|
||||
{ color: #444;
|
||||
text-decoration: none;}
|
||||
|
||||
#content
|
||||
{ text-align: left;
|
||||
float: right;
|
||||
width: 595px;
|
||||
padding: 0;}
|
||||
|
||||
#content ul
|
||||
{ margin: 2px 0 22px 0px;}
|
||||
|
||||
#content ul li
|
||||
{ list-style-type: none;
|
||||
background: url(bullet.png) no-repeat;
|
||||
margin: 0 0 6px 0;
|
||||
padding: 0 0 4px 25px;
|
||||
line-height: 1.5em;}
|
||||
|
||||
#footer
|
||||
{ width: 900px;
|
||||
font: normal 100% 'lucida sans unicode', arial, sans-serif;
|
||||
height: 33px;
|
||||
padding: 24px 0 5px 0;
|
||||
text-align: center;
|
||||
background: transparent url(transparent_light.png) repeat;
|
||||
color: #000;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;}
|
||||
|
||||
#footer a
|
||||
{ color: #000;
|
||||
text-decoration: none;}
|
||||
|
||||
#footer a:hover
|
||||
{ color: #000;
|
||||
text-decoration: underline;}
|
||||
|
||||
.search
|
||||
{ color: #5D5D5D;
|
||||
border: 1px solid #BBB;
|
||||
width: 134px;
|
||||
padding: 4px;
|
||||
font: 100% arial, sans-serif;}
|
||||
|
||||
#colours
|
||||
{ height: 0px;
|
||||
text-align: right;
|
||||
padding: 66px 16px 0px 300px;}
|
||||
|
||||
.form_settings
|
||||
{ margin: 15px 0 0 0;}
|
||||
|
||||
.form_settings p
|
||||
{ padding: 0 0 4px 0;}
|
||||
|
||||
.form_settings span
|
||||
{ float: left;
|
||||
width: 200px;
|
||||
text-align: left;}
|
||||
|
||||
.form_settings input, .form_settings textarea
|
||||
{ padding: 5px;
|
||||
width: 299px;
|
||||
font: 100% arial;
|
||||
border: 1px solid #E5E5DB;
|
||||
background: #FFF;
|
||||
color: #47433F;}
|
||||
|
||||
.form_settings .submit
|
||||
{ font: 100% arial;
|
||||
border: 1px solid;
|
||||
width: 99px;
|
||||
margin: 0 0 0 212px;
|
||||
height: 33px;
|
||||
padding: 2px 0 3px 0;
|
||||
cursor: pointer;
|
||||
background: #000;
|
||||
color: #FFF;}
|
||||
|
||||
.form_settings textarea, .form_settings select
|
||||
{ font: 100% arial;
|
||||
width: 299px;}
|
||||
|
||||
.form_settings select
|
||||
{ width: 310px;}
|
||||
|
||||
.form_settings .checkbox
|
||||
{ margin: 4px 0;
|
||||
padding: 0;
|
||||
width: 14px;
|
||||
border: 0;
|
||||
background: none;}
|
||||
|
||||
.separator
|
||||
{ width: 100%;
|
||||
height: 0;
|
||||
border-top: 1px solid #D9D5CF;
|
||||
border-bottom: 1px solid #FFF;
|
||||
margin: 0 0 20px 0;}
|
||||
|
||||
table
|
||||
{ margin: 10px 0 30px 0;}
|
||||
|
||||
table tr th, table tr td
|
||||
{ background: #3B3B3B;
|
||||
color: #FFF;
|
||||
padding: 7px 4px;
|
||||
text-align: left;}
|
||||
|
||||
table tr td
|
||||
{ background: #F0EFE2;
|
||||
color: #47433F;
|
||||
border-top: 1px solid #FFF;}
|
||||
BIN
Applications/qModMaster/ManModbus/style/transparent.png
Normal file
|
After Width: | Height: | Size: 199 B |
BIN
Applications/qModMaster/ManModbus/style/transparent_light.png
Normal file
|
After Width: | Height: | Size: 147 B |
31
Applications/qModMaster/README.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
1.Description
|
||||
QModMaster is a free Qt-based implementation of a ModBus master application. A graphical user interface allows easy communication with ModBus RTU and TCP slaves. QModMaster also includes a bus monitor for examining all traffic on the bus.
|
||||
|
||||
2.Software
|
||||
QModMaster is based on libmodbus 3.1.0-1 <http://www.libmodbus.org/> for modbus communication and on QsLog <https://bitbucket.org/razvanpetru/qt-components/wiki/QsLog> for logging. Supports both Windows and Linux.
|
||||
|
||||
3.Source code is availiable for Windows and Linux for compilation using Qt 5.2.1 <http://www.qt.io/download/> . Install Qt on your system,open QModMaster project file (QModMaster.pro) and compile.
|
||||
|
||||
4.For Windows a pre-compiled binary is availiable. It does not require instalation, just unzip and run.
|
||||
|
||||
5.To configure the logging level set the 'LoggingLevel' in QModMaster.ini file
|
||||
- TraceLevel : 0
|
||||
- DebugLevel : 1
|
||||
- InfoLevel : 2
|
||||
- WarnLevel : 3 [default]
|
||||
- ErrorLevel : 4
|
||||
- FatalLevel : 5
|
||||
- OffLevel : 6
|
||||
5
Applications/qModMaster/READMEWin32.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
libmodbus - config.h
|
||||
--------------------
|
||||
#define HAVE_DECL_TIOCSRS485 0
|
||||
#define HAVE_DECL_TIOCM_RTS 0
|
||||
22
Applications/qModMaster/forms/about.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "about.h"
|
||||
#include "ui_about.h"
|
||||
#include "modbus-version.h"
|
||||
|
||||
const QString VER = "QModMaster 0.5.3-beta";
|
||||
const QString LIB_VER = LIBMODBUS_VERSION_STRING;
|
||||
const QString URL = "<a href = ""http://sourceforge.net/projects/qmodmaster"">Sourceforge Project Home Page</a>";
|
||||
|
||||
About::About(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::About)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->lblVersion->setText(VER);
|
||||
ui->lblLibVersion->setText("libmodbus " + LIB_VER);
|
||||
ui->lblURL->setText(URL);
|
||||
}
|
||||
|
||||
About::~About()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
25
Applications/qModMaster/forms/about.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef ABOUT_H
|
||||
#define ABOUT_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class About;
|
||||
}
|
||||
|
||||
class About : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit About(QWidget *parent = 0);
|
||||
~About();
|
||||
|
||||
private:
|
||||
Ui::About *ui;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
#endif // ABOUT_H
|
||||
92
Applications/qModMaster/forms/about.ui
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>About</class>
|
||||
<widget class="QDialog" name="About">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>320</width>
|
||||
<height>90</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>About</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/info16.png</normaloff>:/icons/info16.png</iconset>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblVersion">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>18</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">QModMaster</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblLibVersion">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>lib version</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblURL">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">http://</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
353
Applications/qModMaster/forms/busmonitor.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
#include <QtDebug>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QCloseEvent>
|
||||
#include <QShowEvent>
|
||||
#include "busmonitor.h"
|
||||
#include "ui_busmonitor.h"
|
||||
#include "./src/rawdatadelegate.h"
|
||||
|
||||
|
||||
BusMonitor::BusMonitor(QWidget *parent, RawDataModel *rawDataModel) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::BusMonitor),
|
||||
m_rawDataModel(rawDataModel)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->lstRawData->setModel(m_rawDataModel->model);
|
||||
//TODO : use delegate
|
||||
//ui->lstRawData->setItemDelegate(new RawDataDelegate());
|
||||
//Setup Toolbar
|
||||
ui->toolBar->addAction(ui->actionSave);
|
||||
ui->toolBar->addAction(ui->actionClear);
|
||||
ui->toolBar->addAction(ui->actionSxS);
|
||||
ui->toolBar->addAction(ui->actionExit);
|
||||
connect(ui->actionSave,SIGNAL(triggered()),this,SLOT(save()));
|
||||
connect(ui->actionClear,SIGNAL(triggered()),this,SLOT(clear()));
|
||||
connect(ui->actionSxS,SIGNAL(triggered()),this,SLOT(SxS()));
|
||||
connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(exit()));
|
||||
connect(ui->lstRawData,SIGNAL(activated(QModelIndex)),this,SLOT(selectedRow(QModelIndex)));
|
||||
connect(ui->lstRawData,SIGNAL(clicked(QModelIndex)),this,SLOT(selectedRow(QModelIndex)));
|
||||
ui->lblADU2->setVisible(false);
|
||||
ui->txtADU2->setVisible(false);
|
||||
|
||||
}
|
||||
|
||||
BusMonitor::~BusMonitor()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BusMonitor::save()
|
||||
{
|
||||
|
||||
|
||||
//Select file
|
||||
QString fileName = QFileDialog::getSaveFileName(NULL,"Save File As...",
|
||||
QDir::homePath(),"Text (*.txt)",0,
|
||||
QFileDialog::DontConfirmOverwrite);
|
||||
|
||||
//Open File
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
//continue only if a file name exists
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::WriteOnly)) return;
|
||||
|
||||
//Text Stream
|
||||
QTextStream ts(&file);
|
||||
QStringList sl = m_rawDataModel->model->stringList();
|
||||
|
||||
//iterate
|
||||
for (int i = 0; i < sl.size(); ++i)
|
||||
ts << sl.at(i) << Qt::endl;
|
||||
|
||||
//Close File
|
||||
file.close();
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::clear()
|
||||
{
|
||||
|
||||
//qDebug()<< "BusMonitor : clear" ;
|
||||
|
||||
m_rawDataModel->clear();
|
||||
ui->txtADU1->clear();
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::SxS()
|
||||
{
|
||||
|
||||
//qDebug()<< "BusMonitor : SxS" ;
|
||||
if (ui->actionSxS->isChecked()) {
|
||||
ui->lblADU1->setText("Tx ADU");
|
||||
ui->lblADU2->setVisible(true);
|
||||
ui->txtADU2->setVisible(true);
|
||||
}
|
||||
else {
|
||||
ui->lblADU1->setText("ADU");
|
||||
ui->lblADU2->setVisible(false);
|
||||
ui->txtADU2->setVisible(false);
|
||||
}
|
||||
|
||||
ui->txtADU1->setPlainText("");
|
||||
ui->txtADU2->setPlainText("");
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::exit()
|
||||
{
|
||||
|
||||
//qDebug()<< "BusMonitor : exit" ;
|
||||
|
||||
this->close();
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
|
||||
m_rawDataModel->enableAddLines(false);
|
||||
clear();
|
||||
event->accept();
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::showEvent(QShowEvent *event)
|
||||
{
|
||||
|
||||
m_rawDataModel->enableAddLines(true);
|
||||
event->accept();
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::selectedRow(const QModelIndex & selected)
|
||||
{
|
||||
int rowCount;
|
||||
int currRow;
|
||||
QModelIndex next;
|
||||
QModelIndex prev;
|
||||
|
||||
rowCount = ui->lstRawData->model()->rowCount();
|
||||
currRow = selected.row();
|
||||
if (currRow < rowCount - 1){
|
||||
next = ui->lstRawData->model()->index(currRow +1, 0);
|
||||
qDebug()<< "Next Row : "<< next.row();
|
||||
qDebug()<< "Next Data : "<< next.data();
|
||||
}
|
||||
|
||||
|
||||
if (ui->actionSxS->isChecked()) { //Side by Side Tx - Rx packests
|
||||
if (selected.data().canConvert(QVariant::String)) {
|
||||
QString val = selected.data().value<QString>();
|
||||
qDebug()<< "BusMonitor : selectedRow - " << val;
|
||||
if (val.indexOf("Sys") > -1)
|
||||
parseSysMsg(val, ui->txtADU1);
|
||||
else if (val.indexOf("Tx") > -1){
|
||||
parseTxMsg(val, ui->txtADU1);
|
||||
if (currRow < rowCount - 1){
|
||||
next = ui->lstRawData->model()->index(currRow + 1, 0);
|
||||
QString valNext = next.data().value<QString>();
|
||||
if (valNext.indexOf("Rx") > -1)
|
||||
parseRxMsg(valNext, ui->txtADU2);
|
||||
}
|
||||
else {
|
||||
ui->txtADU2->setPlainText("-");
|
||||
}
|
||||
}
|
||||
else if (val.indexOf("Rx") > -1){
|
||||
parseRxMsg(val, ui->txtADU2);
|
||||
if (currRow > 0){
|
||||
prev = ui->lstRawData->model()->index(currRow - 1, 0);
|
||||
QString valPrev = prev.data().value<QString>();
|
||||
if (valPrev.indexOf("Tx") > -1)
|
||||
parseTxMsg(valPrev, ui->txtADU1);
|
||||
}
|
||||
else {
|
||||
ui->txtADU1->setPlainText("-");
|
||||
}
|
||||
}
|
||||
else
|
||||
ui->txtADU1->setPlainText("Type : Unknown Message");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (selected.data().canConvert(QVariant::String)) {
|
||||
QString val = selected.data().value<QString>();
|
||||
qDebug()<< "BusMonitor : selectedRow - " << val;
|
||||
if (val.indexOf("Sys") > -1)
|
||||
parseSysMsg(val, ui->txtADU1);
|
||||
else if (val.indexOf("Tx") > -1)
|
||||
parseTxMsg(val, ui->txtADU1);
|
||||
else if (val.indexOf("Rx") > -1)
|
||||
parseRxMsg(val, ui->txtADU1);
|
||||
else
|
||||
ui->txtADU1->setPlainText("Type : Unknown Message");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BusMonitor::parseTxMsg(QString msg, QPlainTextEdit* txtADU)
|
||||
{
|
||||
txtADU->setPlainText("Type : Tx Message");
|
||||
QStringList row = msg.split(QRegularExpression("\\s+"));
|
||||
txtADU->appendPlainText("Timestamp : " + row[2]);
|
||||
if (msg.indexOf("RTU") > -1){//RTU message
|
||||
QStringList pdu;
|
||||
if (row.length() < 5){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
for (int i = 4; i < row.length() - 1 ; i++)
|
||||
pdu.append(row[i]);
|
||||
parseTxPDU(pdu, "Slave Addr : ", txtADU);
|
||||
txtADU->appendPlainText("CRC : " + pdu[pdu.length() - 2] + pdu[pdu.length() - 1]);
|
||||
}
|
||||
else if (msg.indexOf("TCP") > -1){//TCP message
|
||||
if (row.length() < 11){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText("Transaction ID : " + row[4] + row[5]);
|
||||
txtADU->appendPlainText("Protocol ID : " + row[6] + row[7]);
|
||||
txtADU->appendPlainText("Length : " + row[8] + row[9]);
|
||||
QStringList pdu;
|
||||
for (int i = 10; i < row.length() - 1 ; i++)
|
||||
pdu.append(row[i]);
|
||||
parseTxPDU(pdu, "Unit ID : ", txtADU);
|
||||
}
|
||||
else
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::parseTxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU)
|
||||
{
|
||||
|
||||
if (pdu.length() < 6){//check message length
|
||||
txtADU->appendPlainText(slave + pdu[0]);
|
||||
txtADU->appendPlainText("Function Code : " + pdu[1]);
|
||||
//txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText(slave + pdu[0]);
|
||||
txtADU->appendPlainText("Function Code : " + pdu[1]);
|
||||
txtADU->appendPlainText("Starting Address : " + pdu[2] + pdu[3]);
|
||||
bool ok;
|
||||
int fcode = pdu[1].toInt(&ok,16);
|
||||
if (fcode == 1 || fcode == 2 || fcode == 3 || fcode == 4){//read
|
||||
txtADU->appendPlainText("Quantity of Registers : " + pdu[4] + pdu[5]);
|
||||
}
|
||||
else if (fcode == 5 || fcode == 6){//write
|
||||
txtADU->appendPlainText("Output Value : " + pdu[4] + pdu[5]);
|
||||
}
|
||||
else if (fcode == 15 || fcode == 16){//write multiple
|
||||
txtADU->appendPlainText("Quantity of Registers : " + pdu[4] + pdu[5]);
|
||||
if (pdu.length() < 8){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText("Byte Count : " + pdu[6]);
|
||||
int byteCount = pdu[6].toInt(&ok,16);
|
||||
QString outputValues = "";
|
||||
for (int i = 7; i < 7 + byteCount; i++)
|
||||
outputValues += pdu[i] + " ";
|
||||
txtADU->appendPlainText("Output Values : " + outputValues);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::parseRxMsg(QString msg, QPlainTextEdit* txtADU)
|
||||
{
|
||||
txtADU->setPlainText("Type : Rx Message");
|
||||
QStringList row = msg.split(QRegularExpression("\\s+"));
|
||||
txtADU->appendPlainText("Timestamp : " + row[2]);
|
||||
if (msg.indexOf("RTU") > -1){//RTU message
|
||||
QStringList pdu;
|
||||
if (row.length() < 5){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
for (int i = 4; i < row.length() - 1 ; i++)
|
||||
pdu.append(row[i]);
|
||||
parseRxPDU(pdu, "Slave Addr : ", txtADU);
|
||||
txtADU->appendPlainText("CRC : " + pdu[pdu.length() - 2] + pdu[pdu.length() - 1]);
|
||||
}
|
||||
else if (msg.indexOf("TCP") > -1){//TCP message
|
||||
if (row.length() < 11){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText("Transaction ID : " + row[4] + row[5]);
|
||||
txtADU->appendPlainText("Protocol ID : " + row[6] + row[7]);
|
||||
txtADU->appendPlainText("Length : " + row[8] + row[9]);
|
||||
QStringList pdu;
|
||||
for (int i = 10; i < row.length() - 1 ; i++)
|
||||
pdu.append(row[i]);
|
||||
parseRxPDU(pdu, "Unit ID : ", txtADU);
|
||||
}
|
||||
else
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::parseRxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU)
|
||||
{
|
||||
|
||||
bool ok;
|
||||
int fcode = pdu[1].toInt(&ok,16);
|
||||
if (fcode == 1 || fcode == 2 || fcode == 3 || fcode == 4){//read
|
||||
if (pdu.length() < 4){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText(slave + pdu[0]);
|
||||
txtADU->appendPlainText("Function Code : " + pdu[1]);
|
||||
txtADU->appendPlainText("Byte Count : " + pdu[2]);
|
||||
int byteCount = pdu[2].toInt(&ok,16);
|
||||
QString inputValues = "";
|
||||
for (int i = 3; i < 3 + byteCount; i++)
|
||||
inputValues += pdu[i] + " ";
|
||||
txtADU->appendPlainText("Register Values : " + inputValues);
|
||||
}
|
||||
else if (fcode == 5 || fcode == 6){//write
|
||||
if (pdu.length() < 6){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText(slave + pdu[0]);
|
||||
txtADU->appendPlainText("Function Code : " + pdu[1]);
|
||||
txtADU->appendPlainText("Starting Address : " + pdu[2] + pdu[3]);
|
||||
txtADU->appendPlainText("Output Value : " + pdu[4] + pdu[5]);
|
||||
}
|
||||
else if (fcode == 15 || fcode == 16){//write multiple
|
||||
if (pdu.length() < 6){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText(slave + pdu[0]);
|
||||
txtADU->appendPlainText("Function Code : " + pdu[1]);
|
||||
txtADU->appendPlainText("Starting Address : " + pdu[2] + pdu[3]);
|
||||
txtADU->appendPlainText("Quantity of Registers : " + pdu[4] + pdu[5]);
|
||||
}
|
||||
else if (fcode > 0x80){//exception
|
||||
if (pdu.length() < 3){//check message length
|
||||
txtADU->appendPlainText("Error! Cannot parse Message");
|
||||
return;
|
||||
}
|
||||
txtADU->appendPlainText(slave + pdu[0]);
|
||||
txtADU->appendPlainText("Function Code [80 + Rx Function Code] : " + pdu[1]);
|
||||
txtADU->appendPlainText("Exception Code : " + pdu[2]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BusMonitor::parseSysMsg(QString msg, QPlainTextEdit* txtADU)
|
||||
{
|
||||
txtADU->setPlainText("Type : System Message");
|
||||
QStringList row = msg.split(QRegularExpression("\\s+"));
|
||||
txtADU->appendPlainText("Timestamp : " + row[2]);
|
||||
txtADU->appendPlainText("Message" + msg.mid(msg.indexOf(" : ")));
|
||||
}
|
||||
43
Applications/qModMaster/forms/busmonitor.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef BUSMONITOR_H
|
||||
#define BUSMONITOR_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QLabel>
|
||||
#include <QPlainTextEdit>
|
||||
#include "src/rawdatamodel.h"
|
||||
|
||||
namespace Ui {
|
||||
class BusMonitor;
|
||||
}
|
||||
|
||||
class BusMonitor : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BusMonitor(QWidget *parent, RawDataModel *rawDataModel);
|
||||
~BusMonitor();
|
||||
|
||||
private:
|
||||
Ui::BusMonitor *ui;
|
||||
RawDataModel *m_rawDataModel;
|
||||
void parseTxMsg(QString msg, QPlainTextEdit* txtADU);
|
||||
void parseTxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU);
|
||||
void parseRxMsg(QString msg, QPlainTextEdit* txtADU);
|
||||
void parseRxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU);
|
||||
void parseSysMsg(QString msg, QPlainTextEdit* txtADU);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void showEvent(QShowEvent *event);
|
||||
|
||||
private slots:
|
||||
void clear();
|
||||
void exit();
|
||||
void save();
|
||||
void SxS();
|
||||
void selectedRow(const QModelIndex & selected);
|
||||
|
||||
};
|
||||
|
||||
#endif // BUSMONITOR_H
|
||||
233
Applications/qModMaster/forms/busmonitor.ui
Normal file
@@ -0,0 +1,233 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BusMonitor</class>
|
||||
<widget class="QMainWindow" name="BusMonitor">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>542</width>
|
||||
<height>474</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>540</width>
|
||||
<height>474</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>720</width>
|
||||
<height>720</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Bus Monitor</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/TV-16.png</normaloff>:/icons/TV-16.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>540</width>
|
||||
<height>460</height>
|
||||
</size>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>12</x>
|
||||
<y>2</y>
|
||||
<width>522</width>
|
||||
<height>432</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblRawData">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Raw Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="lstRawData">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="selectionRectVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblADU1">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">ADU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblADU2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Rx ADU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPlainTextEdit" name="txtADU1">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="tabChangesFocus">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::NoTextInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPlainTextEdit" name="txtADU2">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string notr="true">toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<action name="actionClear">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/edit-clear-16.png</normaloff>:/icons/edit-clear-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExit">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/Close-16.png</normaloff>:/icons/Close-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/save-16.png</normaloff>:/icons/save-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSxS">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/data-sort-16.png</normaloff>:/icons/data-sort-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>actionSxS</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Tx-Rx Side by Side</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
779
Applications/qModMaster/forms/mainwindow.ui
Normal file
@@ -0,0 +1,779 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>564</width>
|
||||
<height>400</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>720</width>
|
||||
<height>720</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>QModMaster</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/connect-24.png</normaloff>:/icons/connect-24.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="InfoBar" name="infobar">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_1">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>38</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblModbusMode">
|
||||
<property name="text">
|
||||
<string>Modbus Mode</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>cmbModbusMode</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cmbModbusMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">RTU</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">TCP</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSlave">
|
||||
<property name="text">
|
||||
<string>Slave Addr</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sbSlaveID</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbSlaveID">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblScan">
|
||||
<property name="text">
|
||||
<string>Scan Rate (ms)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spInterval">
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>38</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblFunctionCode">
|
||||
<property name="text">
|
||||
<string>Function Code</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>cmbFunctionCode</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cmbFunctionCode">
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Read Coils (0x01)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Read Discrete Inputs (0x02)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Read Holding Registers (0x03)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Read Input Registers (0x04)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Write Single Coil (0x05)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Write Single Register (0x06)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Write Multiple Coils (0x0f)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Write Multiple Registers (0x10)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblStartAddress">
|
||||
<property name="text">
|
||||
<string>Start Address</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sbStartAddress</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbStartAddress">
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cmbStartAddrBase">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Hex</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>38</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblNoOfCoils">
|
||||
<property name="text">
|
||||
<string>Number of Coils</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sbNoOfRegs</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbNoOfRegs">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblDataFormat">
|
||||
<property name="text">
|
||||
<string>Data Format</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sbStartAddress</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cmbFrmt">
|
||||
<property name="currentText">
|
||||
<string>Bin</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bin</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Hex</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Float</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkSigned">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Signed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPrecision">
|
||||
<property name="text">
|
||||
<string>Precision</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbPrecision">
|
||||
<property name="minimum">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tblRegisters">
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderHighlightSections">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderHighlightSections">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionLoad_Session"/>
|
||||
<addaction name="actionSave_Session"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuOptions">
|
||||
<property name="title">
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<addaction name="actionSerial_RTU"/>
|
||||
<addaction name="actionTCP"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSettings"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionModbus_Manual"/>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<addaction name="actionOpenLogFile"/>
|
||||
<addaction name="actionBus_Monitor"/>
|
||||
<addaction name="actionTools"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionHeaders"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuCommands">
|
||||
<property name="title">
|
||||
<string>Commands</string>
|
||||
</property>
|
||||
<addaction name="actionConnect"/>
|
||||
<addaction name="actionRead_Write"/>
|
||||
<addaction name="actionScan"/>
|
||||
<addaction name="actionClear"/>
|
||||
<addaction name="actionReset_Counters"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuOptions"/>
|
||||
<addaction name="menuCommands"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<action name="actionExit">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/exit-16.png</normaloff>:/icons/exit-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSerial_RTU">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/serial-pot-16.png</normaloff>:/icons/serial-pot-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Modbus RTU...</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTCP">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/ethernet-port-16.png</normaloff>:/icons/ethernet-port-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Modbus TCP...</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/info-sign-16.png</normaloff>:/icons/info-sign-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>About...</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBus_Monitor">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/TV-16.png</normaloff>:/icons/TV-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bus Monitor</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSettings">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/options-16.png</normaloff>:/icons/options-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settings...</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRead_Write">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/data-sort-16.png</normaloff>:/icons/data-sort-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Read / Write</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionConnect">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/plug-disconnect-16.png</normaloff>
|
||||
<normalon>:/icons/plug-connect-16.png</normalon>:/icons/plug-disconnect-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionScan">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/cyclic-process-16.png</normaloff>:/icons/cyclic-process-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scan</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionReset_Counters">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/reset-16.png</normaloff>:/icons/reset-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset Counters</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSimplified_Chinese_zh_CN">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/China-flag-16.png</normaloff>:/icons/China-flag-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">简体中文 (zh_CN)</string>
|
||||
</property>
|
||||
<property name="iconText">
|
||||
<string notr="true">简体中文 (zh_CN)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string notr="true">简体中文 (zh_CN)</string>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTraditional_Chinese_zh_TW">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/Taiwan-flag-16.png</normaloff>:/icons/Taiwan-flag-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">繁體中文 (zh_TW)</string>
|
||||
</property>
|
||||
<property name="iconText">
|
||||
<string notr="true">繁體中文 (zh_TW)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string notr="true">繁體中文 (zh_TW)</string>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEnglish_en_US">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/usa-flag-16.png</normaloff>:/icons/usa-flag-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">English (en_US)</string>
|
||||
</property>
|
||||
<property name="iconText">
|
||||
<string notr="true">English (en_US)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string notr="true">English (en_US)</string>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpenLogFile">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/text-x-log-16.png</normaloff>:/icons/text-x-log-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Log File</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClear">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/edit-clear-16.png</normaloff>:/icons/edit-clear-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear Table</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionModbus_Manual">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/help-desk-icon-16.png</normaloff>:/icons/help-desk-icon-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Modbus Manual</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoad_Session">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/document-import-16.png</normaloff>:/icons/document-import-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load Session...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_Session">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/document-export-16.png</normaloff>:/icons/document-export-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Session...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHeaders">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/Header16.png</normaloff>:/icons/Header16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Headers</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTools">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/tools-16.png</normaloff>:/icons/tools-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>InfoBar</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>src/infobar.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tblRegisters</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>actionExit</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>close()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
49
Applications/qModMaster/forms/settings.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <QtDebug>
|
||||
#include "settings.h"
|
||||
#include "ui_settings.h"
|
||||
|
||||
Settings::Settings(QWidget *parent ,ModbusCommSettings *settings) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::Settings),
|
||||
m_settings(settings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->buttonBox,SIGNAL(accepted()),this,SLOT(changesAccepted()));
|
||||
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Settings::showEvent(QShowEvent * event)
|
||||
{
|
||||
|
||||
//Load Settings
|
||||
ui->sbMaxNoOfRawDataLines->setEnabled(!modbus_connected);
|
||||
ui->sbResponseTimeout->setEnabled(!modbus_connected);
|
||||
if (m_settings != NULL) {
|
||||
ui->sbMaxNoOfRawDataLines->setValue(m_settings->maxNoOfLines().toInt());
|
||||
ui->sbResponseTimeout->setValue(m_settings->timeOut().toInt());
|
||||
ui->sbBaseAddr->setValue(m_settings->baseAddr().toInt());
|
||||
ui->cmbEndian->setCurrentIndex(m_settings->endian());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Settings::changesAccepted()
|
||||
{
|
||||
|
||||
//Save Settings
|
||||
if (m_settings != NULL) {
|
||||
m_settings->setMaxNoOfLines(ui->sbMaxNoOfRawDataLines->cleanText());
|
||||
m_settings->setTimeOut(ui->sbResponseTimeout->cleanText());
|
||||
m_settings->setBaseAddr(ui->sbBaseAddr->cleanText());
|
||||
if (m_settings->endian() != ui->cmbEndian->currentIndex())
|
||||
emit changedEndianess(ui->cmbEndian->currentIndex());
|
||||
m_settings->setEndian(ui->cmbEndian->currentIndex());
|
||||
}
|
||||
|
||||
}
|
||||
38
Applications/qModMaster/forms/settings.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSettings>
|
||||
|
||||
#include "src/modbuscommsettings.h"
|
||||
|
||||
namespace Ui {
|
||||
class Settings;
|
||||
}
|
||||
|
||||
class Settings : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Settings(QWidget *parent = 0 ,ModbusCommSettings * settings = 0);
|
||||
~Settings();
|
||||
bool modbus_connected;
|
||||
|
||||
private:
|
||||
Ui::Settings *ui;
|
||||
ModbusCommSettings *m_settings;
|
||||
|
||||
signals:
|
||||
void changedEndianess(int endian);
|
||||
|
||||
private slots:
|
||||
void changesAccepted();
|
||||
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent * event);
|
||||
|
||||
};
|
||||
|
||||
#endif // SETTINGS_H
|
||||
212
Applications/qModMaster/forms/settings.ui
Normal file
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Settings</class>
|
||||
<widget class="QDialog" name="Settings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>220</width>
|
||||
<height>150</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>220</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/options-16.png</normaloff>:/icons/options-16.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="sbResponseTimeout">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="lblBaseAddr">
|
||||
<property name="text">
|
||||
<string>Base Addr</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblMaxNoOfRawDataLines">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>132</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Max No Of Bus Monitor Lines</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="lblTimeout">
|
||||
<property name="text">
|
||||
<string>Response Timeout (sec)</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="sbMaxNoOfRawDataLines">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>600</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>60</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>60</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="sbBaseAddr">
|
||||
<property name="maximum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="lblEndian">
|
||||
<property name="text">
|
||||
<string>Endian</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QComboBox" name="cmbEndian">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Little</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Big</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Settings</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Settings</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
81
Applications/qModMaster/forms/settingsmodbusrtu.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <QtDebug>
|
||||
#include "settingsmodbusrtu.h"
|
||||
#include "ui_settingsmodbusrtu.h"
|
||||
|
||||
SettingsModbusRTU::SettingsModbusRTU(QWidget *parent,ModbusCommSettings * settings) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::SettingsModbusRTU),
|
||||
m_settings(settings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
/* device name is needed only in Linux */
|
||||
#ifdef Q_OS_WIN32
|
||||
ui->cmbDev->setDisabled(true);
|
||||
#else
|
||||
ui->cmbDev->setDisabled(false);
|
||||
#endif
|
||||
|
||||
connect(ui->buttonBox,SIGNAL(accepted()),this,SLOT(changesAccepted()));
|
||||
|
||||
}
|
||||
|
||||
SettingsModbusRTU::~SettingsModbusRTU()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SettingsModbusRTU::showEvent(QShowEvent * event)
|
||||
{
|
||||
|
||||
//Load Settings
|
||||
ui->cmbDataBits->setEnabled(!modbus_connected);
|
||||
ui->cmbBaud->setEnabled(!modbus_connected);
|
||||
ui->sbPort->setEnabled(!modbus_connected);
|
||||
ui->cmbParity->setEnabled(!modbus_connected);
|
||||
ui->cmbRTS->setEnabled(!modbus_connected);
|
||||
ui->cmbStopBits->setEnabled(!modbus_connected);
|
||||
if (m_settings != NULL) {
|
||||
|
||||
ui->cmbRTS->clear();
|
||||
|
||||
//Populate cmbPort-cmbRTS
|
||||
#ifdef Q_OS_WIN32
|
||||
ui->cmbRTS->addItem("Disable");
|
||||
ui->cmbRTS->addItem("Enable");
|
||||
ui->cmbRTS->addItem("HandShake");
|
||||
ui->cmbRTS->addItem("Toggle");
|
||||
#else
|
||||
ui->cmbRTS->addItem("None");
|
||||
ui->cmbRTS->addItem("Up");
|
||||
ui->cmbRTS->addItem("Down");
|
||||
#endif
|
||||
|
||||
ui->cmbDev->setCurrentText(m_settings->serialDev());
|
||||
ui->sbPort->setValue(m_settings->serialPort().toInt());
|
||||
ui->cmbBaud->setCurrentIndex(ui->cmbBaud->findText(m_settings->baud()));
|
||||
ui->cmbDataBits->setCurrentIndex(ui->cmbDataBits->findText(m_settings->dataBits()));
|
||||
ui->cmbStopBits->setCurrentIndex(ui->cmbStopBits->findText(m_settings->stopBits()));
|
||||
ui->cmbParity->setCurrentIndex(ui->cmbParity->findText(m_settings->parity()));
|
||||
ui->cmbRTS->setCurrentIndex(ui->cmbRTS->findText(m_settings->RTS()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SettingsModbusRTU::changesAccepted()
|
||||
{
|
||||
|
||||
//Save Settings
|
||||
if (m_settings != NULL) {
|
||||
|
||||
m_settings->setSerialPort(QString::number(ui->sbPort->value()), ui->cmbDev->currentText());
|
||||
m_settings->setBaud(ui->cmbBaud->currentText());
|
||||
m_settings->setDataBits(ui->cmbDataBits->currentText());
|
||||
m_settings->setStopBits(ui->cmbStopBits->currentText());
|
||||
m_settings->setParity(ui->cmbParity->currentText());
|
||||
m_settings->setRTS((QString)ui->cmbRTS->currentText());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
34
Applications/qModMaster/forms/settingsmodbusrtu.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef SETTINGSMODBUSRTU_H
|
||||
#define SETTINGSMODBUSRTU_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSettings>
|
||||
|
||||
#include "src/modbuscommsettings.h"
|
||||
|
||||
namespace Ui {
|
||||
class SettingsModbusRTU;
|
||||
}
|
||||
|
||||
class SettingsModbusRTU : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SettingsModbusRTU(QWidget *parent = 0 ,ModbusCommSettings * settings = 0);
|
||||
~SettingsModbusRTU();
|
||||
bool modbus_connected;
|
||||
|
||||
private:
|
||||
Ui::SettingsModbusRTU *ui;
|
||||
ModbusCommSettings * m_settings;
|
||||
|
||||
private slots:
|
||||
void changesAccepted();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent * event);
|
||||
|
||||
};
|
||||
|
||||
#endif // SETTINGSMODBUSRTU_H
|
||||
352
Applications/qModMaster/forms/settingsmodbusrtu.ui
Normal file
@@ -0,0 +1,352 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SettingsModbusRTU</class>
|
||||
<widget class="QDialog" name="SettingsModbusRTU">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>220</width>
|
||||
<height>256</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>220</width>
|
||||
<height>256</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>220</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Modbus RTU Settings</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/options-16.png</normaloff>:/icons/options-16.png</iconset>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="cmbDev">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>/dev/ttyS</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>/dev/ttyUSB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblDev">
|
||||
<property name="text">
|
||||
<string>Serial device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lblBaud">
|
||||
<property name="text">
|
||||
<string>Baud</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>cmbBaud</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="sbPort">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="cmbBaud">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">110</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">300</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">600</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">1200</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">2400</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">4800</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">9600</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">14400</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">19200</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">28800</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">38400</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">57600</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">115200</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">128000</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">256000</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">921600</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="cmbDataBits">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">7</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">8</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lblDataBits">
|
||||
<property name="text">
|
||||
<string>Data Bits</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>cmbDataBits</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="lblRTS">
|
||||
<property name="text">
|
||||
<string notr="true">RTS</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lblStopBits">
|
||||
<property name="text">
|
||||
<string>Stop Bits</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>cmbStopBits</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="cmbRTS"/>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="cmbParity">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Odd</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Even</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="cmbStopBits">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">1.5</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">2</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="lblParity">
|
||||
<property name="text">
|
||||
<string>Parity</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>cmbParity</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblPort">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Serial port</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>SettingsModbusRTU</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>SettingsModbusRTU</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
81
Applications/qModMaster/forms/settingsmodbustcp.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <QtDebug>
|
||||
#include <QMessageBox>
|
||||
#include "settingsmodbustcp.h"
|
||||
#include "ui_settingsmodbustcp.h"
|
||||
|
||||
SettingsModbusTCP::SettingsModbusTCP(QWidget *parent, ModbusCommSettings * settings) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::SettingsModbusTCP),
|
||||
m_settings(settings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->buttonBox,SIGNAL(accepted()),this,SLOT(changesAccepted()));
|
||||
}
|
||||
|
||||
SettingsModbusTCP::~SettingsModbusTCP()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SettingsModbusTCP::showEvent(QShowEvent * event)
|
||||
{
|
||||
|
||||
//Load Settings
|
||||
ui->leSlaveIP->setEnabled(!modbus_connected);
|
||||
ui->leTCPPort->setEnabled(!modbus_connected);
|
||||
if (m_settings != NULL) {
|
||||
ui->leTCPPort->setText(m_settings->TCPPort());
|
||||
ui->leSlaveIP->setText(m_settings->slaveIP());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SettingsModbusTCP::changesAccepted()
|
||||
{
|
||||
int validation;
|
||||
|
||||
validation = validateInputs();
|
||||
switch(validation){
|
||||
case 0 : // ok
|
||||
//Save Settings
|
||||
if (m_settings != NULL) {
|
||||
m_settings->setTCPPort(ui->leTCPPort->text());
|
||||
m_settings->setSlaveIP(ui->leSlaveIP->text());
|
||||
}
|
||||
break;
|
||||
case 1 : // wrong ip
|
||||
QMessageBox::critical(NULL, "Modbus TCP Settings","Wrong IP Address.");
|
||||
break;
|
||||
case 2 : // wrong port
|
||||
QMessageBox::critical(NULL, "Modbus TCP Settings","Wrong Port Number.");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int SettingsModbusTCP::validateInputs()
|
||||
{
|
||||
//Strip zero's from IP
|
||||
QStringList ipBytes;
|
||||
bool ok;
|
||||
int i, ipByte, port;
|
||||
|
||||
ipBytes = (ui->leSlaveIP->text()).split(".");
|
||||
if (ipBytes.size() == 4){
|
||||
for (i = 0; i < ipBytes.size(); i++){
|
||||
ipByte = ipBytes[i].toInt(&ok);
|
||||
if (!ok || ipByte > 255 )
|
||||
return 1; // wrong ip
|
||||
}
|
||||
}
|
||||
else
|
||||
return 1; // wrong ip
|
||||
|
||||
port = (ui->leTCPPort->text()).toInt(&ok);
|
||||
if (!ok || port <= 0 || port > 65535)
|
||||
return 2; // wrong port
|
||||
|
||||
return 0; // validate ok
|
||||
|
||||
}
|
||||
37
Applications/qModMaster/forms/settingsmodbustcp.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef SETTINGSMODBUSTCP_H
|
||||
#define SETTINGSMODBUSTCP_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSettings>
|
||||
#include <QAbstractButton>
|
||||
|
||||
#include "src/modbuscommsettings.h"
|
||||
|
||||
namespace Ui {
|
||||
class SettingsModbusTCP;
|
||||
}
|
||||
|
||||
class SettingsModbusTCP : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SettingsModbusTCP(QWidget *parent = 0 ,ModbusCommSettings * settings = 0);
|
||||
~SettingsModbusTCP();
|
||||
bool modbus_connected;
|
||||
|
||||
private:
|
||||
Ui::SettingsModbusTCP *ui;
|
||||
ModbusCommSettings * m_settings;
|
||||
int validateInputs();
|
||||
|
||||
private slots:
|
||||
void changesAccepted();
|
||||
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent * event);
|
||||
|
||||
};
|
||||
|
||||
#endif // SETTINGSMODBUSTCP_H
|
||||
127
Applications/qModMaster/forms/settingsmodbustcp.ui
Normal file
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SettingsModbusTCP</class>
|
||||
<widget class="QDialog" name="SettingsModbusTCP">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>240</width>
|
||||
<height>110</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>110</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>160</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Modbus TCP Settings</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>:/img/network-16.png</normaloff>:/img/network-16.png</iconset>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblSlaveIP">
|
||||
<property name="text">
|
||||
<string>Slave IP</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lblTCPPort">
|
||||
<property name="text">
|
||||
<string>TCP Port</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>leTCPPort</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="leTCPPort">
|
||||
<property name="inputMask">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="leSlaveIP">
|
||||
<property name="inputMask">
|
||||
<string notr="true">999.999.999.999;_</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>SettingsModbusTCP</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>SettingsModbusTCP</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
216
Applications/qModMaster/forms/tools.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "tools.h"
|
||||
#include "ui_tools.h"
|
||||
|
||||
#include "QsLog.h"
|
||||
|
||||
Tools::Tools(QWidget *parent, ModbusAdapter *adapter, ModbusCommSettings *settings) :
|
||||
QMainWindow(parent),
|
||||
m_modbusAdapter(adapter), m_modbusCommSettings(settings),
|
||||
ui(new Ui::Tools)
|
||||
{
|
||||
//setup UI
|
||||
ui->setupUi(this);
|
||||
cmbModbusMode = new QComboBox(this);
|
||||
cmbModbusMode->setMinimumWidth(96);
|
||||
cmbModbusMode->addItem("RTU/TCP");cmbModbusMode->addItem("TCP");
|
||||
cmbCmd = new QComboBox(this);
|
||||
cmbCmd->setMinimumWidth(96);
|
||||
cmbCmd->addItem("Report Slave ID");
|
||||
ui->toolBar->addWidget(cmbModbusMode);
|
||||
ui->toolBar->addWidget(cmbCmd);
|
||||
ui->toolBar->addSeparator();
|
||||
ui->toolBar->addAction(ui->actionExec);
|
||||
ui->toolBar->addAction(ui->actionClear);
|
||||
ui->toolBar->addAction(ui->actionExit);
|
||||
|
||||
//UI - connections
|
||||
connect(cmbModbusMode,SIGNAL(currentIndexChanged(int)),this,SLOT(changedModbusMode(int)));
|
||||
connect(ui->actionExec,SIGNAL(triggered(bool)),this,SLOT(execCmd()));
|
||||
connect(ui->actionClear,SIGNAL(triggered(bool)),this,SLOT(clear()));
|
||||
connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(exit()));
|
||||
connect(&m_pingProc,SIGNAL(readyReadStandardOutput()),this,SLOT(pingData()));
|
||||
connect(&m_pingProc,SIGNAL(readyReadStandardError()),this,SLOT(pingData()));
|
||||
|
||||
}
|
||||
|
||||
Tools::~Tools()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void Tools::exit()
|
||||
{
|
||||
|
||||
this->close();
|
||||
|
||||
}
|
||||
|
||||
QString Tools::ipConv(QString ip)
|
||||
{
|
||||
/* convert ip - remove leding 0's */
|
||||
|
||||
QStringList m_ip;
|
||||
QStringList m_ip_conv;
|
||||
QString m_ip_byte;
|
||||
|
||||
m_ip = ip.split(".");
|
||||
for (int i = 0; i < m_ip.size(); i++){
|
||||
m_ip_byte = m_ip.at(i);
|
||||
if (m_ip_byte.at(0)=='0')
|
||||
m_ip_conv << m_ip_byte.remove(0,1);
|
||||
else
|
||||
m_ip_conv << m_ip_byte;
|
||||
}
|
||||
|
||||
return (m_ip_conv.at(0) + "." + m_ip_conv.at(1) + "." + m_ip_conv.at(2) + "." + m_ip_conv.at(3));
|
||||
|
||||
}
|
||||
|
||||
void Tools::changedModbusMode(int currIndex)
|
||||
{
|
||||
|
||||
QLOG_TRACE()<< "Modbus Mode changed. Index = " << currIndex;
|
||||
|
||||
cmbCmd->clear();
|
||||
if (currIndex == 0) { //RTU/TCP
|
||||
cmbCmd->addItem("Report Slave ID");
|
||||
}
|
||||
else { //TCP
|
||||
cmbCmd->addItem("Report Slave ID");cmbCmd->addItem("Ping");cmbCmd->addItem("Port Status");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Tools::execCmd()
|
||||
{
|
||||
|
||||
ui->txtOutput->moveCursor(QTextCursor::End);
|
||||
|
||||
QLOG_TRACE()<< "Tools Execute Cmd " << cmbCmd->currentText();
|
||||
switch (cmbCmd->currentIndex()){
|
||||
case 0:
|
||||
ui->txtOutput->appendPlainText(QString("------- Modbus Diagnotics : Report Slave ID %1 -------\n").arg(m_modbusCommSettings->slaveID()));
|
||||
diagnosticsProc();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ui->txtOutput->appendPlainText(QString("------- Modbus TCP : Ping IP %1 -------\n").arg(m_modbusCommSettings->slaveIP()));
|
||||
pingProc();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ui->txtOutput->appendPlainText(QString("------- Modbus TCP : Check Port %1:%2 Status -------\n").arg(m_modbusCommSettings->slaveIP(),m_modbusCommSettings->TCPPort()));
|
||||
portProc();
|
||||
break;
|
||||
|
||||
default:
|
||||
ui->txtOutput->appendPlainText("------- No Valid Selection -------\n");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Tools::clear()
|
||||
{
|
||||
|
||||
QLOG_TRACE()<< "Tools Clear Ouput";
|
||||
ui->txtOutput->clear();
|
||||
|
||||
}
|
||||
|
||||
void Tools::diagnosticsProc()
|
||||
{
|
||||
|
||||
qApp->processEvents();
|
||||
ui->txtOutput->moveCursor(QTextCursor::End);
|
||||
if(m_modbusAdapter->m_modbus != NULL){
|
||||
modbusDiagnostics();
|
||||
}
|
||||
else{
|
||||
ui->txtOutput->insertPlainText("Not Connected.\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Tools::pingProc()
|
||||
{
|
||||
|
||||
qApp->processEvents();
|
||||
m_pingProc.start("ping", QStringList() << ipConv(m_modbusCommSettings->slaveIP()));
|
||||
if (m_pingProc.waitForFinished(5000)){
|
||||
//just wait -> execute button is pressed
|
||||
}
|
||||
}
|
||||
|
||||
void Tools::pingData()
|
||||
{
|
||||
|
||||
qApp->processEvents();
|
||||
ui->txtOutput->moveCursor(QTextCursor::End);
|
||||
ui->txtOutput->insertPlainText(m_pingProc.readAll());
|
||||
|
||||
}
|
||||
|
||||
void Tools::portProc()
|
||||
{
|
||||
|
||||
qApp->processEvents();
|
||||
ui->txtOutput->moveCursor(QTextCursor::End);
|
||||
m_portProc.connectToHost(ipConv(m_modbusCommSettings->slaveIP()),m_modbusCommSettings->TCPPort().toInt());
|
||||
if (m_portProc.waitForConnected(5000)){//wait -> execute button is pressed
|
||||
ui->txtOutput->insertPlainText("Connected.Port is opened\n");
|
||||
m_portProc.close();
|
||||
}
|
||||
else{
|
||||
ui->txtOutput->insertPlainText("Not connected.Port is closed\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Tools::modbusDiagnostics()
|
||||
{
|
||||
//Modbus diagnostics - RTU/TCP
|
||||
QLOG_TRACE()<< "Modbus diagnostics.";
|
||||
|
||||
//Modbus data
|
||||
m_modbusAdapter->setFunctionCode(0x11);
|
||||
uint8_t dest[1024]; //setup memory for data
|
||||
memset(dest, 0, 1024);
|
||||
int ret = -1; //return value from read functions
|
||||
|
||||
modbus_set_slave(m_modbusAdapter->m_modbus, m_modbusCommSettings->slaveID());
|
||||
//request data from modbus
|
||||
ret = modbus_report_slave_id(m_modbusAdapter->m_modbus, MODBUS_MAX_PDU_LENGTH, dest);
|
||||
QLOG_TRACE() << "Modbus Read Data return value = " << ret << ", errno = " << errno;
|
||||
|
||||
//update data model
|
||||
if(ret > 1)
|
||||
{
|
||||
QString line;
|
||||
line = dest[1]?"ON":"OFF";
|
||||
ui->txtOutput->insertPlainText("Run Status : " + line + "\n");
|
||||
QString id = QString::fromUtf8((char*)dest);
|
||||
ui->txtOutput->insertPlainText("ID : " + id.right(id.size()-2) + "\n");;
|
||||
}
|
||||
else
|
||||
{
|
||||
QString line = "";
|
||||
if(ret < 0) {
|
||||
line = QString("Error : ") + EUtils::libmodbus_strerror(errno);
|
||||
QLOG_ERROR() << "Read diagnostics data failed. " << line;
|
||||
line = QString(tr("Read diagnostics data failed.\nError : ")) + EUtils::libmodbus_strerror(errno);
|
||||
ui->txtOutput->insertPlainText(line);
|
||||
}
|
||||
else {
|
||||
line = QString("Unknown Error : ") + EUtils::libmodbus_strerror(errno);
|
||||
QLOG_ERROR() << "Read diagnostics data failed. " << line;
|
||||
line = QString(tr("Read diagnostics data failed.\nUnknown Error : ")) + EUtils::libmodbus_strerror(errno);
|
||||
ui->txtOutput->insertPlainText(line);
|
||||
}
|
||||
|
||||
modbus_flush(m_modbusAdapter->m_modbus); //flush data
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
47
Applications/qModMaster/forms/tools.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef TOOLS_H
|
||||
#define TOOLS_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QProcess>
|
||||
#include <QTcpSocket>
|
||||
#include <qcombobox.h>
|
||||
|
||||
#include "src/modbusadapter.h"
|
||||
#include "src/modbuscommsettings.h"
|
||||
|
||||
namespace Ui {
|
||||
class Tools;
|
||||
}
|
||||
|
||||
class Tools : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Tools(QWidget *parent = 0, ModbusAdapter *adapter = 0, ModbusCommSettings *settings = 0);
|
||||
~Tools();
|
||||
|
||||
private:
|
||||
Ui::Tools *ui;
|
||||
QComboBox *cmbModbusMode;
|
||||
QComboBox *cmbCmd;
|
||||
ModbusAdapter *m_modbusAdapter;
|
||||
ModbusCommSettings *m_modbusCommSettings;
|
||||
QProcess m_pingProc;
|
||||
QTcpSocket m_portProc;
|
||||
QString ipConv(QString ip);
|
||||
void pingProc();
|
||||
void portProc();
|
||||
void diagnosticsProc();
|
||||
void modbusDiagnostics();
|
||||
|
||||
private slots:
|
||||
void exit();
|
||||
void changedModbusMode(int currIndex);
|
||||
void execCmd();
|
||||
void clear();
|
||||
void pingData();
|
||||
|
||||
};
|
||||
|
||||
#endif // TOOLS_H
|
||||
99
Applications/qModMaster/forms/tools.ui
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Tools</class>
|
||||
<widget class="QMainWindow" name="Tools">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>400</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>720</width>
|
||||
<height>720</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="txtOutput">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Tahoma</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<action name="actionExit">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/Close-16.png</normaloff>:/icons/Close-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExec">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/play-16.png</normaloff>:/icons/play-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exec</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Execute Command</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClear">
|
||||
<property name="icon">
|
||||
<iconset resource="../icons/icons.qrc">
|
||||
<normaloff>:/icons/edit-clear-16.png</normaloff>:/icons/edit-clear-16.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Clear Output</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
BIN
Applications/qModMaster/icons/China-flag-16.png
Normal file
|
After Width: | Height: | Size: 509 B |
BIN
Applications/qModMaster/icons/Close-16.png
Normal file
|
After Width: | Height: | Size: 834 B |
BIN
Applications/qModMaster/icons/Header16.png
Normal file
|
After Width: | Height: | Size: 836 B |
BIN
Applications/qModMaster/icons/TV-16.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
Applications/qModMaster/icons/Taiwan-flag-16.png
Normal file
|
After Width: | Height: | Size: 723 B |
BIN
Applications/qModMaster/icons/bullet-green-16.png
Normal file
|
After Width: | Height: | Size: 267 B |
BIN
Applications/qModMaster/icons/bullet-red-16.png
Normal file
|
After Width: | Height: | Size: 274 B |
BIN
Applications/qModMaster/icons/close8-black.png
Normal file
|
After Width: | Height: | Size: 93 B |
BIN
Applications/qModMaster/icons/close8-red.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
Applications/qModMaster/icons/connect-24.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Applications/qModMaster/icons/cyclic-process-16.png
Normal file
|
After Width: | Height: | Size: 606 B |