Merge branch 'master' of https://git.shs.tools/SHS/pip
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
/src_main/piversion.h
|
/src_main/piversion.h
|
||||||
/.svn
|
/.svn
|
||||||
/doc/rtf
|
/doc/rtf
|
||||||
|
_unsused
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
|
|||||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||||
project(pip)
|
project(pip)
|
||||||
set(_PIP_MAJOR 1)
|
set(_PIP_MAJOR 1)
|
||||||
set(_PIP_MINOR 16)
|
set(_PIP_MINOR 17)
|
||||||
set(_PIP_REVISION 0)
|
set(_PIP_REVISION 0)
|
||||||
set(_PIP_SUFFIX alpha)
|
set(_PIP_SUFFIX alpha)
|
||||||
set(_PIP_COMPANY SHS)
|
set(_PIP_COMPANY SHS)
|
||||||
@@ -84,6 +84,8 @@ set(PIP_SRC_DIRS "src_main" "src_crypt" "src_compress" "src_usb" "src_fftw" "src
|
|||||||
set(PIP_LIBS_TARGETS pip)
|
set(PIP_LIBS_TARGETS pip)
|
||||||
set(LIBS_MAIN)
|
set(LIBS_MAIN)
|
||||||
set(LIBS_STATUS)
|
set(LIBS_STATUS)
|
||||||
|
set(HDRS)
|
||||||
|
set(PHDRS)
|
||||||
|
|
||||||
if (TESTS)
|
if (TESTS)
|
||||||
set(PIP_SRC_CONCURRENT_TEST "src_concurrent/test")
|
set(PIP_SRC_CONCURRENT_TEST "src_concurrent/test")
|
||||||
@@ -110,12 +112,16 @@ set_version(PIP
|
|||||||
REVISION "${_PIP_REVISION}"
|
REVISION "${_PIP_REVISION}"
|
||||||
BUILD "${BUILD_NUMBER}"
|
BUILD "${BUILD_NUMBER}"
|
||||||
SUFFIX "${_PIP_SUFFIX}"
|
SUFFIX "${_PIP_SUFFIX}"
|
||||||
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${PIP_SRC_MAIN}/piversion.h")
|
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/piversion.h")
|
||||||
set_deploy_property(pip ${PIP_LIB_TYPE}
|
set_deploy_property(pip ${PIP_LIB_TYPE}
|
||||||
LABEL "PIP main library"
|
LABEL "PIP main library"
|
||||||
FULLNAME "${_PIP_DOMAIN}.pip"
|
FULLNAME "${_PIP_DOMAIN}.pip"
|
||||||
COMPANY "${_PIP_COMPANY}"
|
COMPANY "${_PIP_COMPANY}"
|
||||||
INFO "Platform-Independent Primitives")
|
INFO "Platform-Independent Primitives")
|
||||||
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PIP_SRC_MAIN}/piversion.h")
|
||||||
|
file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/${PIP_SRC_MAIN}/piversion.h")
|
||||||
|
endif()
|
||||||
|
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/piversion.h")
|
||||||
message(STATUS "Building PIP version ${PIP_VERSION} (${PIP_LIB_TYPE})")
|
message(STATUS "Building PIP version ${PIP_VERSION} (${PIP_LIB_TYPE})")
|
||||||
|
|
||||||
|
|
||||||
@@ -352,7 +358,7 @@ if(NOT PIP_FREERTOS)
|
|||||||
if(WIN32)
|
if(WIN32)
|
||||||
if(${C_COMPILER} STREQUAL "cl.exe")
|
if(${C_COMPILER} STREQUAL "cl.exe")
|
||||||
else()
|
else()
|
||||||
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi)
|
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
list(APPEND LIBS_MAIN dl)
|
list(APPEND LIBS_MAIN dl)
|
||||||
|
|||||||
16
main.cpp
16
main.cpp
@@ -111,14 +111,18 @@ private:
|
|||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PIKbdListener kbd;
|
|
||||||
|
PIKbdListener kbd(0, 0, false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
/*PIStringList dl = PISerial::availableDevices();
|
//piCout << PISerial::availableDevicesInfo();
|
||||||
piCout << dl;
|
PIIODevice * d = PIIODevice::createFromFullPath(argv[1]);
|
||||||
PISerial ser(dl[0]);
|
piCout << d;
|
||||||
piCout << ser.open(PIIODevice::ReadWrite) << &ser;
|
if (d) {
|
||||||
*/
|
d->open();
|
||||||
|
piCout << d->constructFullPath() << d->isOpened();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,15 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wnonnull"
|
||||||
|
#endif
|
||||||
#include "pistreampacker.h"
|
#include "pistreampacker.h"
|
||||||
#include "piiodevice.h"
|
#include "piiodevice.h"
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
/** \class PIStreamPacker
|
/** \class PIStreamPacker
|
||||||
* \brief Simple packet wrap aroud any PIIODevice
|
* \brief Simple packet wrap aroud any PIIODevice
|
||||||
|
|||||||
@@ -215,9 +215,9 @@
|
|||||||
#define PRIVATE_DEFINITION_END(c) \
|
#define PRIVATE_DEFINITION_END(c) \
|
||||||
}; \
|
}; \
|
||||||
c::__PrivateInitializer__::__PrivateInitializer__() {p = new c::__Private__();} \
|
c::__PrivateInitializer__::__PrivateInitializer__() {p = new c::__Private__();} \
|
||||||
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ & o) {/*if (p) delete p;*/ p = new c::__Private__();} \
|
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ & ) {/*if (p) delete p;*/ p = new c::__Private__();} \
|
||||||
c::__PrivateInitializer__::~__PrivateInitializer__() {delete p; p = 0;} \
|
c::__PrivateInitializer__::~__PrivateInitializer__() {delete p; p = 0;} \
|
||||||
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator =(const c::__PrivateInitializer__ & o) {if (p) delete p; p = new c::__Private__(); return *this;}
|
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator =(const c::__PrivateInitializer__ & ) {if (p) delete p; p = new c::__Private__(); return *this;}
|
||||||
|
|
||||||
#define PRIVATE (__privateinitializer__.p)
|
#define PRIVATE (__privateinitializer__.p)
|
||||||
#define PRIVATEWB __privateinitializer__.p
|
#define PRIVATEWB __privateinitializer__.p
|
||||||
|
|||||||
@@ -201,9 +201,9 @@
|
|||||||
typedef name __PIObject__; \
|
typedef name __PIObject__; \
|
||||||
public: \
|
public: \
|
||||||
static const PIString __classNameS() {return PIStringAscii(#name);} \
|
static const PIString __classNameS() {return PIStringAscii(#name);} \
|
||||||
static const uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
static uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||||
virtual const char * className() const {return #name;} \
|
virtual const char * className() const {return #name;} \
|
||||||
virtual const uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
virtual uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||||
private: \
|
private: \
|
||||||
virtual int ptrOffset() const {name * o = (name*)100; return int(llong((PIObject*)o) - llong(o));} \
|
virtual int ptrOffset() const {name * o = (name*)100; return int(llong((PIObject*)o) - llong(o));} \
|
||||||
class __BaseInitializer__ { \
|
class __BaseInitializer__ { \
|
||||||
@@ -515,10 +515,10 @@ public:
|
|||||||
//! Returns object class name
|
//! Returns object class name
|
||||||
virtual const char * className() const {return "PIObject";}
|
virtual const char * className() const {return "PIObject";}
|
||||||
|
|
||||||
virtual const uint classNameID() const {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
|
virtual uint classNameID() const {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
|
||||||
|
|
||||||
static const PIString __classNameS() {return PIStringAscii("PIObject");}
|
static const PIString __classNameS() {return PIStringAscii("PIObject");}
|
||||||
static const uint __classNameIDS() {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
|
static uint __classNameIDS() {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
|
||||||
|
|
||||||
//! Returns parent object class name
|
//! Returns parent object class name
|
||||||
virtual const char * parentClassName() const {return "";}
|
virtual const char * parentClassName() const {return "";}
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ PIIntrospectionThreads::PIIntrospectionThreads() {
|
|||||||
|
|
||||||
void PIIntrospectionThreads::threadNew(PIThread * t) {
|
void PIIntrospectionThreads::threadNew(PIThread * t) {
|
||||||
PIMutexLocker _ml(mutex);
|
PIMutexLocker _ml(mutex);
|
||||||
ThreadInfo & ti(threads[t]);
|
//ThreadInfo & ti(threads[t]);
|
||||||
|
threads.insert(t, ThreadInfo());
|
||||||
//piCout << "register thread" << id << name;
|
//piCout << "register thread" << id << name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,14 @@
|
|||||||
* debug = true
|
* debug = true
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
|
* You can use multiline values ends with " \"
|
||||||
|
* \code
|
||||||
|
* value = start \ #s comment
|
||||||
|
* _mid \
|
||||||
|
* _end
|
||||||
|
* \endcode
|
||||||
|
* In this example value = "start_mid_end"
|
||||||
|
*
|
||||||
* \section PIConfig_sec1 Concepts
|
* \section PIConfig_sec1 Concepts
|
||||||
* Each node of internal tree has type PIConfig::Entry. %PIConfig
|
* Each node of internal tree has type PIConfig::Entry. %PIConfig
|
||||||
* has one root element \a rootEntry(). Any entry of configuration file is a
|
* has one root element \a rootEntry(). Any entry of configuration file is a
|
||||||
@@ -249,7 +257,7 @@ void PIConfig::Entry::coutt(std::ostream & s, const PIString & p) const {
|
|||||||
|
|
||||||
void PIConfig::Entry::piCoutt(PICout s, const PIString & p) const {
|
void PIConfig::Entry::piCoutt(PICout s, const PIString & p) const {
|
||||||
PIString nl = p + " ";
|
PIString nl = p + " ";
|
||||||
if (!_value.isEmpty()) s << p << _name << " = " << _value << PICoutManipulators::NewLine;
|
if (!_value.isEmpty()) s << p << _name << " = " << _value << " (" << _type << " " << _comment << ")" << PICoutManipulators::NewLine;
|
||||||
else std::cout << p << _name << std::endl;
|
else std::cout << p << _name << std::endl;
|
||||||
piForeachC (Entry * i, _children) i->piCoutt(s, nl);
|
piForeachC (Entry * i, _children) i->piCoutt(s, nl);
|
||||||
}
|
}
|
||||||
@@ -261,6 +269,7 @@ PIConfig::PIConfig(const PIString & path, PIIODevice::DeviceMode mode) {
|
|||||||
dev = new PIFile(path, mode);
|
dev = new PIFile(path, mode);
|
||||||
if (!dev->isOpened())
|
if (!dev->isOpened())
|
||||||
dev->open(path, mode);
|
dev->open(path, mode);
|
||||||
|
incdirs << PIFile::fileInfo(path).dir();
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +286,11 @@ PIConfig::PIConfig(PIIODevice * device, PIIODevice::DeviceMode mode) {
|
|||||||
_init();
|
_init();
|
||||||
own_dev = false;
|
own_dev = false;
|
||||||
dev = device;
|
dev = device;
|
||||||
if (dev) dev->open(mode);
|
if (dev) {
|
||||||
|
dev->open(mode);
|
||||||
|
if (PIString(dev->className()) == "PIFile")
|
||||||
|
incdirs << PIFile::fileInfo(((PIFile*)dev)->path()).dir();
|
||||||
|
}
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,9 +729,9 @@ void PIConfig::parse() {
|
|||||||
//piCout << "[PIConfig] charset" << PIFile::defaultCharset();
|
//piCout << "[PIConfig] charset" << PIFile::defaultCharset();
|
||||||
PIString src, str, tab, comm, all, name, type, prefix, tprefix;
|
PIString src, str, tab, comm, all, name, type, prefix, tprefix;
|
||||||
PIStringList tree;
|
PIStringList tree;
|
||||||
Entry * entry, * te, * ce;
|
Entry * entry = 0, * te = 0, * ce = 0;
|
||||||
int ind, sind;
|
int ind, sind;
|
||||||
bool isNew, isPrefix;
|
bool isNew = false, isPrefix = false, wasMultiline = false, isMultiline = false;
|
||||||
piForeach (PIConfig * c, inc_devs)
|
piForeach (PIConfig * c, inc_devs)
|
||||||
delete c;
|
delete c;
|
||||||
inc_devs.clear();
|
inc_devs.clear();
|
||||||
@@ -739,27 +752,45 @@ void PIConfig::parse() {
|
|||||||
//piCout << "line \"" << str << "\"";
|
//piCout << "line \"" << str << "\"";
|
||||||
tab = str.left(str.find(str.trimmed().left(1)));
|
tab = str.left(str.find(str.trimmed().left(1)));
|
||||||
str.trim();
|
str.trim();
|
||||||
//cout << endl << str << endl << endl;
|
|
||||||
// piCout << "[PIConfig] str" << str.size() << str << str.toUTF8();
|
|
||||||
all = str;
|
all = str;
|
||||||
ind = str.find('=');
|
|
||||||
if ((ind > 0) && (str[0] != '#')) {
|
|
||||||
sind = str.find('#');
|
sind = str.find('#');
|
||||||
if (sind > 0) {
|
if (sind > 0) {
|
||||||
comm = str.right(str.length() - sind - 1).trimmed();
|
comm = str.mid(sind + 1).trimmed();
|
||||||
if (comm.length() > 0) type = comm[0];
|
if (!comm.isEmpty()) {
|
||||||
else type = "s";
|
type = comm[0];
|
||||||
comm = comm.right(comm.length() - 1).trimmed();
|
comm.cutLeft(1).trim();
|
||||||
str = str.left(sind);
|
} else type = "s";
|
||||||
|
str = str.left(sind).trim();
|
||||||
} else {
|
} else {
|
||||||
type = "s";
|
type = "s";
|
||||||
comm = "";
|
comm = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (str.endsWith(" \\")) {
|
||||||
|
isMultiline = true;
|
||||||
|
str.cutRight(2).trim();
|
||||||
|
} else
|
||||||
|
isMultiline = false;
|
||||||
|
|
||||||
|
if (wasMultiline) {
|
||||||
|
wasMultiline = false;
|
||||||
|
if (ce) {
|
||||||
|
ce->_value += str;
|
||||||
|
ce->_all += " \\\n" + all;
|
||||||
|
}
|
||||||
|
str.clear();
|
||||||
|
} else
|
||||||
|
ce = 0;
|
||||||
|
wasMultiline = isMultiline;
|
||||||
|
|
||||||
|
//piCout << "[PIConfig] str" << str.size() << str << str.toUTF8();
|
||||||
|
ind = str.find('=');
|
||||||
|
if ((ind > 0) && (str[0] != '#')) {
|
||||||
//name = str.left(ind).trimmed();
|
//name = str.left(ind).trimmed();
|
||||||
tree = (prefix + str.left(ind).trimmed()).split(delim);
|
tree = (prefix + str.left(ind).trimmed()).split(delim);
|
||||||
if (tree.front() == "include") {
|
if (tree.front() == "include") {
|
||||||
name = str.right(str.length() - ind - 1).trimmed();
|
name = str.mid(ind + 1).trimmed();
|
||||||
PIConfig * iconf = new PIConfig(name, incdirs);
|
PIConfig * iconf = new PIConfig(name, incdirs);
|
||||||
//piCout << "include" << name << iconf->dev;
|
//piCout << "include" << name << iconf->dev;
|
||||||
if (!iconf->dev) {
|
if (!iconf->dev) {
|
||||||
@@ -797,7 +828,7 @@ void PIConfig::parse() {
|
|||||||
ce->delim = delim;
|
ce->delim = delim;
|
||||||
ce->_tab = tab;
|
ce->_tab = tab;
|
||||||
ce->_name = name;
|
ce->_name = name;
|
||||||
ce->_value = str.right(str.length() - ind - 1).trimmed();
|
ce->_value = str.mid(ind + 1).trimmed();
|
||||||
ce->_type = type;
|
ce->_type = type;
|
||||||
ce->_comment = comm;
|
ce->_comment = comm;
|
||||||
//piCout << "[PIConfig] comm" << comm.size() << comm << comm.toUTF8();
|
//piCout << "[PIConfig] comm" << comm.size() << comm << comm.toUTF8();
|
||||||
|
|||||||
@@ -512,7 +512,10 @@ std::ostream & operator <<(std::ostream & s, const PIConfig::Entry & v);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline PICout operator <<(PICout s, const PIConfig::Branch & v) {s.setControl(0, true); v.piCoutt(s, ""); s.restoreControl(); return s;}
|
inline PICout operator <<(PICout s, const PIConfig::Branch & v) {s.setControl(0, true); v.piCoutt(s, ""); s.restoreControl(); return s;}
|
||||||
inline PICout operator <<(PICout s, const PIConfig::Entry & v) {s << v.value(); return s;}
|
inline PICout operator <<(PICout s, const PIConfig::Entry & v) {
|
||||||
|
s << v.value() << "(" << v.type() << v.comment() << ")";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** \relatesalso PIConfig \relatesalso PIIODevice
|
/** \relatesalso PIConfig \relatesalso PIIODevice
|
||||||
|
|||||||
268
src_main/io_devices/pigpio.cpp
Normal file
268
src_main/io_devices/pigpio.cpp
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
GPIO
|
||||||
|
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pigpio.h"
|
||||||
|
#ifdef LINUX
|
||||||
|
# define GPIO_SYS_CLASS
|
||||||
|
#endif
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
# include <fcntl.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <cstdlib>
|
||||||
|
#endif
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*! \class PIGPIO
|
||||||
|
* \brief GPIO support
|
||||||
|
*
|
||||||
|
* \section PIGPIO_sec0 Synopsis
|
||||||
|
* This class provide initialize, get/set and watch functions for GPIO.
|
||||||
|
*
|
||||||
|
* Currently supported only \"/sys/class/gpio\" mechanism on Linux.
|
||||||
|
*
|
||||||
|
* This class should be used with \a PIGPIO::instance() singleton.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \section PIGPIO_sec1 API
|
||||||
|
* There are several function to directly read or write pin states.
|
||||||
|
*
|
||||||
|
* Also you can start %PIGPIO as thread to watch pin states and receive
|
||||||
|
* \a pinChanged() event.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
PIGPIO::PIGPIO(): PIThread() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIGPIO::~PIGPIO() {
|
||||||
|
stop();
|
||||||
|
waitForFinish(100);
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
PIVector<int> ids = gpio_.keys();
|
||||||
|
for(int i = 0; i < ids.size_s(); i++) {
|
||||||
|
GPIOData & g(gpio_[ids[i]]);
|
||||||
|
if (g.fd != -1) {
|
||||||
|
::close(g.fd);
|
||||||
|
g.fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gpio_.clear();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIGPIO * PIGPIO::instance() {
|
||||||
|
static PIGPIO ret;
|
||||||
|
return &ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PIString PIGPIO::GPIOName(int gpio_num) {
|
||||||
|
return PIStringAscii("gpio") + PIString::fromNumber(gpio_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::exportGPIO(int gpio_num) {
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
PIString valfile = "/sys/class/gpio/" + GPIOName(gpio_num) + "/value";
|
||||||
|
int fd = ::open(valfile.dataAscii(), O_RDONLY);
|
||||||
|
if (fd != -1) {
|
||||||
|
::close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int ret = 0;
|
||||||
|
ret = system(PIString("echo " + PIString::fromNumber(gpio_num) + " >> /sys/class/gpio/export").dataAscii());
|
||||||
|
if (ret == 0) {
|
||||||
|
PITimeMeasurer tm;
|
||||||
|
while (tm.elapsed_s() < 1.) {
|
||||||
|
fd = ::open(valfile.dataAscii(), O_RDWR);
|
||||||
|
if (fd != -1) {
|
||||||
|
::close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
piMSleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::openGPIO(GPIOData & g) {
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
if (g.fd != -1) {
|
||||||
|
::close(g.fd);
|
||||||
|
g.fd = -1;
|
||||||
|
}
|
||||||
|
PIString fp = "/sys/class/gpio/" + g.name + "/value";
|
||||||
|
g.fd = ::open(fp.dataAscii(), O_RDWR);
|
||||||
|
//piCoutObj << "initGPIO" << g.num << ":" << fp << g.fd << errorString();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIGPIO::getPinState(int gpio_num) {
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
GPIOData & g(gpio_[gpio_num]);
|
||||||
|
char r = 0;
|
||||||
|
int ret = 0;
|
||||||
|
if (g.fd != -1) {
|
||||||
|
::lseek(g.fd, 0, SEEK_SET);
|
||||||
|
ret = ::read(g.fd, &r, sizeof(r));
|
||||||
|
if (ret > 0) {
|
||||||
|
if (r == '1') return true;
|
||||||
|
if (r == '0') return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//piCoutObj << "pinState" << gpio_num << ":" << ret << (int)r << errorString();
|
||||||
|
//initGPIO(gpio_num, PIGPIO::In); TODO: discuss - why?
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::begin() {
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
if (watch_state.isEmpty()) return;
|
||||||
|
PIVector<int> ids = watch_state.keys();
|
||||||
|
for(int i = 0; i < ids.size_s(); i++) {
|
||||||
|
GPIOData & g(gpio_[ids[i]]);
|
||||||
|
if (g.num != -1 && !g.name.isEmpty()) {
|
||||||
|
openGPIO(g);
|
||||||
|
watch_state[ids[i]] = getPinState(ids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::run() {
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
if (watch_state.isEmpty()) return;
|
||||||
|
PIVector<int> ids = watch_state.keys();
|
||||||
|
for(int i = 0; i < ids.size_s(); i++) {
|
||||||
|
GPIOData & g(gpio_[ids[i]]);
|
||||||
|
if (g.num != -1 && !g.name.isEmpty()) {
|
||||||
|
bool v = getPinState(g.num);
|
||||||
|
//piCoutObj << "*** pin state ***" << ids[i] << "=" << v;
|
||||||
|
if (watch_state[g.num] != v) {
|
||||||
|
watch_state[g.num] = v;
|
||||||
|
pinChanged(g.num, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::end() {
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
if (watch_state.isEmpty()) return;
|
||||||
|
PIVector<int> ids = watch_state.keys();
|
||||||
|
for(int i = 0; i < ids.size_s(); i++) {
|
||||||
|
GPIOData & g(gpio_[ids[i]]);
|
||||||
|
if (g.fd != -1) {
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
::close(g.fd);
|
||||||
|
#endif
|
||||||
|
g.fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::initPin(int gpio_num, Direction dir) { //, PullUpDownControl pull) {
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
GPIOData & g(gpio_[gpio_num]);
|
||||||
|
if (g.num == -1) {
|
||||||
|
g.num = gpio_num;
|
||||||
|
g.name = GPIOName(gpio_num);
|
||||||
|
exportGPIO(gpio_num);
|
||||||
|
}
|
||||||
|
g.dir = dir;
|
||||||
|
int ret = 0;
|
||||||
|
switch(dir) {
|
||||||
|
case In:
|
||||||
|
ret = system(("echo in >> /sys/class/gpio/" + g.name + "/direction").dataAscii());
|
||||||
|
break;
|
||||||
|
case Out:
|
||||||
|
ret = system(("echo out >> /sys/class/gpio/" + g.name + "/direction").dataAscii());
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
openGPIO(g);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::pinSet(int gpio_num, bool value) {
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
GPIOData & g(gpio_[gpio_num]);
|
||||||
|
int ret = 0;
|
||||||
|
if (g.fd != -1) {
|
||||||
|
if (value) ret = ::write(g.fd, "1", 1);
|
||||||
|
else ret = ::write(g.fd, "0", 1);
|
||||||
|
}
|
||||||
|
//piCoutObj << "pinSet" << gpio_num << ":" << ret << errorString();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIGPIO::pinState(int gpio_num) {
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
return getPinState(gpio_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::pinBeginWatch(int gpio_num) {
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
GPIOData & g(gpio_[gpio_num]);
|
||||||
|
if (g.fd != -1) {
|
||||||
|
#ifdef GPIO_SYS_CLASS
|
||||||
|
::close(g.fd);
|
||||||
|
#endif
|
||||||
|
g.fd = -1;
|
||||||
|
}
|
||||||
|
watch_state.insert(gpio_num, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::pinEndWatch(int gpio_num) {
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
watch_state.remove(gpio_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIGPIO::clearWatch() {
|
||||||
|
PIMutexLocker ml(mutex);
|
||||||
|
watch_state.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
117
src_main/io_devices/pigpio.h
Normal file
117
src_main/io_devices/pigpio.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*! \file pigpio.h
|
||||||
|
* \brief GPIO
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
GPIO
|
||||||
|
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PIGPIO_H
|
||||||
|
#define PIGPIO_H
|
||||||
|
|
||||||
|
#include "pithread.h"
|
||||||
|
|
||||||
|
|
||||||
|
class PIGPIO: public PIThread
|
||||||
|
{
|
||||||
|
PIOBJECT_SUBCLASS(PIGPIO, PIThread)
|
||||||
|
public:
|
||||||
|
PIGPIO();
|
||||||
|
virtual ~PIGPIO();
|
||||||
|
|
||||||
|
//! \brief Work mode for pin
|
||||||
|
enum Direction {
|
||||||
|
In /** Input direction (read) */,
|
||||||
|
Out /** Output direction (write) */
|
||||||
|
};
|
||||||
|
//enum PullUpDownControl {NoPull, PullUp, PullDown};
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief Returns singleton object of %PIGPIO
|
||||||
|
static PIGPIO * instance();
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief Initialize pin \"gpio_num\" for \"dir\" mode
|
||||||
|
void initPin(int gpio_num, Direction dir = PIGPIO::In);//, PullUpDownControl pull);
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief Set pin \"gpio_num\" value to \"value\"
|
||||||
|
void pinSet (int gpio_num, bool value);
|
||||||
|
|
||||||
|
//! \brief Set pin \"gpio_num\" value to \b true
|
||||||
|
void pinHigh (int gpio_num) {pinSet(gpio_num, true );}
|
||||||
|
|
||||||
|
//! \brief Set pin \"gpio_num\" value to \b false
|
||||||
|
void pinLow (int gpio_num) {pinSet(gpio_num, false);}
|
||||||
|
|
||||||
|
//! \brief Returns pin \"gpio_num\" state
|
||||||
|
bool pinState(int gpio_num);
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief Starts watch for pin \"gpio_num\".
|
||||||
|
//! \details Pins watching starts only with \a PIThread::start() function!
|
||||||
|
//! This function doesn`t affect thread state
|
||||||
|
void pinBeginWatch(int gpio_num);
|
||||||
|
|
||||||
|
//! \brief End watch for pin \"gpio_num\".
|
||||||
|
//! \details Pins watching starts only with \a PIThread::start() function!
|
||||||
|
//! This function doesn`t affect thread state
|
||||||
|
void pinEndWatch (int gpio_num);
|
||||||
|
|
||||||
|
//! \brief End watch for all pins.
|
||||||
|
//! \details Pins watching starts only with \a PIThread::start() function!
|
||||||
|
//! This function doesn`t affect thread state
|
||||||
|
void clearWatch();
|
||||||
|
|
||||||
|
|
||||||
|
EVENT2(pinChanged, int, gpio_num, bool, new_value)
|
||||||
|
|
||||||
|
//! \events
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! \fn void pinChanged(int gpio_num, bool new_value)
|
||||||
|
//! \brief Raise on pin \"gpio_num\" state changes to \"new_value\"
|
||||||
|
//! \details Important! This event will be raised only with started
|
||||||
|
//! thread.
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct GPIOData {
|
||||||
|
GPIOData() {dir = PIGPIO::In; num = fd = -1;}
|
||||||
|
PIString name;
|
||||||
|
int dir;
|
||||||
|
int num;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
void exportGPIO(int gpio_num);
|
||||||
|
void openGPIO(GPIOData & g);
|
||||||
|
bool getPinState(int gpio_num);
|
||||||
|
void begin();
|
||||||
|
void run();
|
||||||
|
void end();
|
||||||
|
|
||||||
|
static PIString GPIOName(int gpio_num);
|
||||||
|
|
||||||
|
PIMap<int, GPIOData> gpio_;
|
||||||
|
PIMap<int, bool> watch_state;
|
||||||
|
PIMutex mutex;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // PIDIR_H
|
||||||
@@ -23,10 +23,10 @@
|
|||||||
#include "pipropertystorage.h"
|
#include "pipropertystorage.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#if defined(WINDOWS) || defined(FREERTOS)
|
#if defined(FREERTOS)
|
||||||
# define PISERIAL_NO_PINS
|
# define PISERIAL_NO_PINS
|
||||||
#endif
|
#endif
|
||||||
#ifdef PISERIAL_NO_PINS
|
#if defined(PISERIAL_NO_PINS) || defined(WINDOWS)
|
||||||
# define TIOCM_LE 1
|
# define TIOCM_LE 1
|
||||||
# define TIOCM_DTR 4
|
# define TIOCM_DTR 4
|
||||||
# define TIOCM_RTS 7
|
# define TIOCM_RTS 7
|
||||||
@@ -38,7 +38,19 @@
|
|||||||
# define TIOCM_DSR 6
|
# define TIOCM_DSR 6
|
||||||
#endif
|
#endif
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
# ifndef INITGUID
|
||||||
|
# define INITGUID
|
||||||
|
# include <guiddef.h>
|
||||||
|
# undef INITGUID
|
||||||
|
# else
|
||||||
|
# include <guiddef.h>
|
||||||
|
# endif
|
||||||
|
# include <ntddmodm.h>
|
||||||
# include <winreg.h>
|
# include <winreg.h>
|
||||||
|
# include <windows.h>
|
||||||
|
# include <winioctl.h>
|
||||||
|
# include <cfgmgr32.h>
|
||||||
|
# include <setupapi.h>
|
||||||
# define B50 50
|
# define B50 50
|
||||||
# define B75 75
|
# define B75 75
|
||||||
# define B110 110
|
# define B110 110
|
||||||
@@ -131,6 +143,12 @@
|
|||||||
* This class provide access to serial device, e.g. COM port. It can read,
|
* This class provide access to serial device, e.g. COM port. It can read,
|
||||||
* write, wait for write. There are several read and write functions.
|
* write, wait for write. There are several read and write functions.
|
||||||
*
|
*
|
||||||
|
* \section PISerial_sec0 FullPath
|
||||||
|
* Since version 1.16.0 you can use as \a path DeviceInfo::id() USB identifier.
|
||||||
|
* \code
|
||||||
|
* PISerial * s = new PISerial("0403:6001");
|
||||||
|
* PIIODevice * d = PIIODevice::createFromFullPath("ser://0403:6001:115200");
|
||||||
|
* \endcode
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -149,6 +167,21 @@ PRIVATE_DEFINITION_START(PISerial)
|
|||||||
PRIVATE_DEFINITION_END(PISerial)
|
PRIVATE_DEFINITION_END(PISerial)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PISerial::DeviceInfo::DeviceInfo() {
|
||||||
|
vID = pID = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIString PISerial::DeviceInfo::id() const {
|
||||||
|
return PIString::fromNumber(vID, 16).toLowerCase().expandLeftTo(4, '0') + ":" +
|
||||||
|
PIString::fromNumber(pID, 16).toLowerCase().expandLeftTo(4, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PISerial::PISerial(): PIIODevice("", ReadWrite) {
|
PISerial::PISerial(): PIIODevice("", ReadWrite) {
|
||||||
construct();
|
construct();
|
||||||
}
|
}
|
||||||
@@ -255,37 +288,51 @@ bool PISerial::isDSR() const {return isBit(TIOCM_DSR, "DSR");}
|
|||||||
|
|
||||||
|
|
||||||
bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
||||||
#ifndef PISERIAL_NO_PINS
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!";
|
piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifndef PISERIAL_NO_PINS
|
||||||
|
# ifdef WINDOWS
|
||||||
|
static int bit_map_on [] = {0, 0, 0, 0, SETDTR, 0, 0, SETRTS, 0, 0, 0};
|
||||||
|
static int bit_map_off[] = {0, 0, 0, 0, CLRDTR, 0, 0, CLRRTS, 0, 0, 0};
|
||||||
|
int action = (on ? bit_map_on : bit_map_off)[bit];
|
||||||
|
if (action > 0) {
|
||||||
|
if (EscapeCommFunction(PRIVATE->hCom, action) == 0) {
|
||||||
|
piCoutObj << "setBit" << bname << " error: " << errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
# else
|
||||||
if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) {
|
if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) {
|
||||||
piCoutObj << "setBit" << bname << " error: " << errorString();
|
piCoutObj << "setBit" << bname << " error: " << errorString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
#else
|
# endif
|
||||||
|
#endif
|
||||||
piCoutObj << "setBit" << bname << " doesn`t implemented, sorry :-(";
|
piCoutObj << "setBit" << bname << " doesn`t implemented, sorry :-(";
|
||||||
return false;
|
return false;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PISerial::isBit(int bit, const PIString & bname) const {
|
bool PISerial::isBit(int bit, const PIString & bname) const {
|
||||||
#ifndef PISERIAL_NO_PINS
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
piCoutObj << "isBit" << bname << " error: \"" << path() << "\" is not opened!";
|
piCoutObj << "isBit" << bname << " error: \"" << path() << "\" is not opened!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifndef PISERIAL_NO_PINS
|
||||||
|
# ifdef WINDOWS
|
||||||
|
# else
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if (ioctl(fd, TIOCMGET, &ret) < 0)
|
if (ioctl(fd, TIOCMGET, &ret) < 0)
|
||||||
piCoutObj << "isBit" << bname << " error: " << errorString();
|
piCoutObj << "isBit" << bname << " error: " << errorString();
|
||||||
return ret & bit;
|
return ret & bit;
|
||||||
#else
|
# endif
|
||||||
|
#endif
|
||||||
piCoutObj << "isBit" << bname << " doesn`t implemented, sorry :-(";
|
piCoutObj << "isBit" << bname << " doesn`t implemented, sorry :-(";
|
||||||
return false;
|
return false;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -296,28 +343,6 @@ void PISerial::flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PISerial::closeDevice() {
|
|
||||||
if (isRunning() && !isStopping()) {
|
|
||||||
stop();
|
|
||||||
PIThread::terminate();
|
|
||||||
}
|
|
||||||
if (fd != -1) {
|
|
||||||
#ifdef WINDOWS
|
|
||||||
SetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
|
|
||||||
SetCommMask(PRIVATE->hCom, PRIVATE->mask);
|
|
||||||
// piCoutObj << "close" <<
|
|
||||||
CloseHandle(PRIVATE->hCom);
|
|
||||||
PRIVATE->hCom = 0;
|
|
||||||
#else
|
|
||||||
tcsetattr(fd, TCSANOW, &PRIVATE->sdesc);
|
|
||||||
::close(fd);
|
|
||||||
#endif
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int PISerial::convertSpeed(PISerial::Speed speed) {
|
int PISerial::convertSpeed(PISerial::Speed speed) {
|
||||||
switch (speed) {
|
switch (speed) {
|
||||||
case S50: return B50;
|
case S50: return B50;
|
||||||
@@ -509,16 +534,31 @@ bool PISerial::send(const void * data, int size) {
|
|||||||
|
|
||||||
|
|
||||||
bool PISerial::openDevice() {
|
bool PISerial::openDevice() {
|
||||||
//piCout << "ser open" << path();
|
PIString p = path();
|
||||||
if (path().isEmpty()) return false;
|
//piCout << "ser open" << p;
|
||||||
|
PIString pl = p.toLowerCase().removeAll(' ');
|
||||||
|
if (!pl.startsWith("/") && !pl.startsWith("com")) {
|
||||||
|
p.clear();
|
||||||
|
PIVector<DeviceInfo> devs = availableDevicesInfo();
|
||||||
|
piForeachC (DeviceInfo & d, devs) {
|
||||||
|
if (d.id() == pl) {
|
||||||
|
p = d.path;
|
||||||
|
piBreak;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p.isEmpty()) {
|
||||||
|
piCoutObj << "Unable to find device \"" << pl << "\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p.isEmpty()) return false;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
DWORD ds = 0, sm = 0;
|
DWORD ds = 0, sm = 0;
|
||||||
if (isReadable()) {ds |= GENERIC_READ; sm |= FILE_SHARE_READ;}
|
if (isReadable()) {ds |= GENERIC_READ; sm |= FILE_SHARE_READ;}
|
||||||
if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;}
|
if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;}
|
||||||
PIString wp = "//./" + path();
|
PIString wp = "//./" + p;
|
||||||
PRIVATE->hCom = CreateFileA(wp.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
PRIVATE->hCom = CreateFileA(wp.dataAscii(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||||
if (PRIVATE->hCom == INVALID_HANDLE_VALUE) {
|
if (PRIVATE->hCom == INVALID_HANDLE_VALUE) {
|
||||||
piCoutObj << "Unable to open \"" << path() << "\"";
|
piCoutObj << "Unable to open \"" << p << "\"";
|
||||||
fd = -1;
|
fd = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -530,21 +570,42 @@ bool PISerial::openDevice() {
|
|||||||
case PIIODevice::WriteOnly: om = O_WRONLY; break;
|
case PIIODevice::WriteOnly: om = O_WRONLY; break;
|
||||||
case PIIODevice::ReadWrite: om = O_RDWR; break;
|
case PIIODevice::ReadWrite: om = O_RDWR; break;
|
||||||
}
|
}
|
||||||
//cout << "init ser " << path_ << " mode " << om << " param " << params << endl;
|
fd = ::open(p.data(), O_NOCTTY | om);
|
||||||
fd = ::open(path().data(), O_NOCTTY | om);
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
piCoutObj << "Unable to open \"" << path() << "\"";
|
piCoutObj << "Unable to open \"" << p << "\"";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tcgetattr(fd, &PRIVATE->desc);
|
tcgetattr(fd, &PRIVATE->desc);
|
||||||
PRIVATE->sdesc = PRIVATE->desc;
|
PRIVATE->sdesc = PRIVATE->desc;
|
||||||
//piCoutObj << "Initialized " << path_;
|
//piCoutObj << "Initialized " << p;
|
||||||
#endif
|
#endif
|
||||||
applySettings();
|
applySettings();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PISerial::closeDevice() {
|
||||||
|
if (isRunning() && !isStopping()) {
|
||||||
|
stop();
|
||||||
|
PIThread::terminate();
|
||||||
|
}
|
||||||
|
if (fd != -1) {
|
||||||
|
#ifdef WINDOWS
|
||||||
|
SetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
|
||||||
|
SetCommMask(PRIVATE->hCom, PRIVATE->mask);
|
||||||
|
// piCoutObj << "close" <<
|
||||||
|
CloseHandle(PRIVATE->hCom);
|
||||||
|
PRIVATE->hCom = 0;
|
||||||
|
#else
|
||||||
|
tcsetattr(fd, TCSANOW, &PRIVATE->sdesc);
|
||||||
|
::close(fd);
|
||||||
|
#endif
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PISerial::applySettings() {
|
void PISerial::applySettings() {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
if (fd == -1) return;
|
if (fd == -1) return;
|
||||||
@@ -718,6 +779,13 @@ PIString PISerial::constructFullPathDevice() const {
|
|||||||
|
|
||||||
void PISerial::configureFromFullPathDevice(const PIString & full_path) {
|
void PISerial::configureFromFullPathDevice(const PIString & full_path) {
|
||||||
PIStringList pl = full_path.split(":");
|
PIStringList pl = full_path.split(":");
|
||||||
|
if (pl.size_s() > 1) {
|
||||||
|
PIString _s = pl[0].toLowerCase().removeAll(' ').trim();
|
||||||
|
if (!_s.startsWith("/") && !_s.startsWith("com")) {
|
||||||
|
pl[0] += ":" + pl[1];
|
||||||
|
pl.remove(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int i = 0; i < pl.size_s(); ++i) {
|
for (int i = 0; i < pl.size_s(); ++i) {
|
||||||
PIString p(pl[i]);
|
PIString p(pl[i]);
|
||||||
switch (i) {
|
switch (i) {
|
||||||
@@ -792,24 +860,134 @@ PIVector<int> PISerial::availableSpeeds() {
|
|||||||
|
|
||||||
|
|
||||||
PIStringList PISerial::availableDevices(bool test) {
|
PIStringList PISerial::availableDevices(bool test) {
|
||||||
PIStringList dl;
|
PIVector<DeviceInfo> devs = availableDevicesInfo(test);
|
||||||
|
PIStringList ret;
|
||||||
|
piForeachC (DeviceInfo & d, devs)
|
||||||
|
ret << d.path;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
HKEY key = 0;
|
PIString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) {
|
||||||
|
PIString ret;
|
||||||
|
const HKEY key = SetupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
|
||||||
|
if (key == INVALID_HANDLE_VALUE)
|
||||||
|
return ret;
|
||||||
|
static const wchar_t * const keyTokens[] = {
|
||||||
|
L"PortName\0",
|
||||||
|
L"PortNumber\0"
|
||||||
|
};
|
||||||
|
static const int keys_count = sizeof(keyTokens) / sizeof(keyTokens[0]);
|
||||||
|
for (int i = 0; i < keys_count; ++i) {
|
||||||
|
DWORD dataType = 0;
|
||||||
|
DWORD bytesRequired = MAX_PATH;
|
||||||
|
PIVector<wchar_t> outputBuffer(MAX_PATH + 1);
|
||||||
|
for (;;) {
|
||||||
|
LONG res = RegQueryValueExW(key, keyTokens[i], NULL, &dataType, (LPBYTE)outputBuffer.data(), &bytesRequired);
|
||||||
|
if (res == ERROR_MORE_DATA) {
|
||||||
|
outputBuffer.resize(bytesRequired / sizeof(wchar_t) + 2);
|
||||||
|
continue;
|
||||||
|
} else if (res == ERROR_SUCCESS) {
|
||||||
|
if (dataType == REG_SZ)
|
||||||
|
ret = PIString(outputBuffer.data());
|
||||||
|
else if (dataType == REG_DWORD)
|
||||||
|
ret = PIStringAscii("COM") + PIString::fromNumber(*(PDWORD(&outputBuffer[0])));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ret.isEmpty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIString deviceRegistryProperty(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData, DWORD property) {
|
||||||
|
DWORD dataType = 0;
|
||||||
|
DWORD bytesRequired = MAX_PATH;
|
||||||
|
PIVector<wchar_t> outputBuffer(MAX_PATH + 1);
|
||||||
|
for (;;) {
|
||||||
|
if (SetupDiGetDeviceRegistryPropertyW(deviceInfoSet, deviceInfoData, property, &dataType, (PBYTE)outputBuffer.data(), bytesRequired, &bytesRequired))
|
||||||
|
break;
|
||||||
|
if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (dataType != REG_SZ && dataType != REG_EXPAND_SZ))
|
||||||
|
return PIString();
|
||||||
|
outputBuffer.resize(bytesRequired / sizeof(wchar_t) + 2, 0);
|
||||||
|
}
|
||||||
|
return PIString(outputBuffer.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIString deviceInstanceIdentifier(DEVINST deviceInstanceNumber) {
|
||||||
|
PIVector<wchar_t> outputBuffer(MAX_DEVICE_ID_LEN + 1);
|
||||||
|
if (CM_Get_Device_IDW(deviceInstanceNumber, (PWCHAR)outputBuffer.data(), MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) {
|
||||||
|
return PIString();
|
||||||
|
}
|
||||||
|
return PIString(outputBuffer.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool parseID(PIString str, PISerial::DeviceInfo & di) {
|
||||||
|
if (str.isEmpty()) return false;
|
||||||
|
int i = str.find("VID_");
|
||||||
|
if (i > 0) di.vID = str.mid(i + 4, 4).toInt(16);
|
||||||
|
i = str.find("PID_");
|
||||||
|
if (i > 0) di.pID = str.mid(i + 4, 4).toInt(16);
|
||||||
|
return (di.vID > 0) && (di.pID > 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
||||||
|
PIVector<DeviceInfo> ret;
|
||||||
|
DeviceInfo di;
|
||||||
|
#ifdef WINDOWS
|
||||||
|
/*HKEY key = 0;
|
||||||
RegOpenKey(HKEY_LOCAL_MACHINE, (LPCTSTR)"HARDWARE\\DEVICEMAP\\SERIALCOMM", &key);
|
RegOpenKey(HKEY_LOCAL_MACHINE, (LPCTSTR)"HARDWARE\\DEVICEMAP\\SERIALCOMM", &key);
|
||||||
if (key != 0) {
|
if (key != 0) {
|
||||||
char name[1024], data[1024];
|
char name[1024], data[1024];
|
||||||
DWORD index = 0;
|
DWORD index = 0;
|
||||||
LONG ret = ERROR_SUCCESS;
|
LONG res = ERROR_SUCCESS;
|
||||||
while (ret != ERROR_NO_MORE_ITEMS) {
|
while (res != ERROR_NO_MORE_ITEMS) {
|
||||||
memset(name, 0, 1024);
|
memset(name, 0, 1024);
|
||||||
memset(data, 0, 1024);
|
memset(data, 0, 1024);
|
||||||
DWORD name_len = 1024, data_len = 1024, type = 0;
|
DWORD name_len = 1024, data_len = 1024, type = 0;
|
||||||
ret = RegEnumValue(key, index, (LPTSTR)name, &name_len, NULL, &type, (uchar * )data, &data_len);
|
res = RegEnumValue(key, index, (LPTSTR)name, &name_len, NULL, &type, (uchar * )data, &data_len);
|
||||||
if (ret == ERROR_NO_MORE_ITEMS) break;
|
if (res == ERROR_NO_MORE_ITEMS) break;
|
||||||
dl << PIString(data, data_len).trim();
|
di.path = PIString(data, data_len).trim();
|
||||||
|
ret << di;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
|
}*/
|
||||||
|
static const GUID guids[] = {GUID_DEVINTERFACE_MODEM, GUID_DEVINTERFACE_COMPORT};
|
||||||
|
static const int guids_cnt = sizeof(guids) / sizeof(GUID);
|
||||||
|
for (int i = 0; i < guids_cnt; ++i) {
|
||||||
|
const HDEVINFO dis = SetupDiGetClassDevs(&(guids[i]), NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||||
|
if (dis == INVALID_HANDLE_VALUE) continue;
|
||||||
|
SP_DEVINFO_DATA did;
|
||||||
|
memset(&did, 0, sizeof(did));
|
||||||
|
did.cbSize = sizeof(did);
|
||||||
|
DWORD index = 0;
|
||||||
|
while (SetupDiEnumDeviceInfo(dis, index++, &did)) {
|
||||||
|
di = DeviceInfo();
|
||||||
|
di.path = devicePortName(dis, &did);
|
||||||
|
if (!di.path.startsWith("COM")) continue;
|
||||||
|
di.description = deviceRegistryProperty(dis, &did, SPDRP_DEVICEDESC);
|
||||||
|
di.manufacturer = deviceRegistryProperty(dis, &did, SPDRP_MFG);
|
||||||
|
PIString id_str = deviceInstanceIdentifier(did.DevInst);
|
||||||
|
if (!parseID(id_str, di)) {
|
||||||
|
DEVINST pdev = 0;
|
||||||
|
if (CM_Get_Parent(&pdev, did.DevInst, 0) == CR_SUCCESS) {
|
||||||
|
id_str = deviceInstanceIdentifier(pdev);
|
||||||
|
parseID(id_str, di);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret << di;
|
||||||
|
//piCout << "dev" << did.DevInst << di;
|
||||||
|
}
|
||||||
|
SetupDiDestroyDeviceInfoList(dis);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# ifndef ANDROID
|
# ifndef ANDROID
|
||||||
@@ -849,24 +1027,51 @@ PIStringList PISerial::availableDevices(bool test) {
|
|||||||
# endif
|
# endif
|
||||||
PIDir dir("/dev");
|
PIDir dir("/dev");
|
||||||
PIVector<PIFile::FileInfo> de = dir.entries();
|
PIVector<PIFile::FileInfo> de = dir.entries();
|
||||||
|
# ifdef LINUX
|
||||||
|
char linkbuf[1024];
|
||||||
|
# endif
|
||||||
piForeachC (PIFile::FileInfo & e, de) { // TODO changes in FileInfo
|
piForeachC (PIFile::FileInfo & e, de) { // TODO changes in FileInfo
|
||||||
piForeachC (PIString & p, prefixes) {
|
piForeachC (PIString & p, prefixes) {
|
||||||
if (e.name().startsWith(p))
|
if (e.name().startsWith(p)) {
|
||||||
dl << e.path;
|
di = DeviceInfo();
|
||||||
|
di.path = e.path;
|
||||||
|
# ifdef LINUX
|
||||||
|
ssize_t lsz = readlink(("/sys/class/tty/" + e.name()).dataAscii(), linkbuf, 1024);
|
||||||
|
if (lsz > 0) {
|
||||||
|
PIString fpath = "/sys/class/tty/" + PIString(linkbuf, lsz) + "/";
|
||||||
|
PIFile _f;
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
fpath += "../";
|
||||||
|
//piCout << "try" << fpath;
|
||||||
|
if (_f.open(fpath + "idVendor", PIIODevice::ReadOnly))
|
||||||
|
di.vID = PIString(_f.readAll()).trim().toInt(16);
|
||||||
|
if (_f.open(fpath + "idProduct", PIIODevice::ReadOnly))
|
||||||
|
di.pID = PIString(_f.readAll()).trim().toInt(16);
|
||||||
|
if (_f.open(fpath + "product", PIIODevice::ReadOnly))
|
||||||
|
di.description = PIString(_f.readAll()).trim();
|
||||||
|
if (_f.open(fpath + "manufacturer", PIIODevice::ReadOnly))
|
||||||
|
di.manufacturer = PIString(_f.readAll()).trim();
|
||||||
|
if (di.pID > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
ret << di;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
if (test) {
|
if (test) {
|
||||||
for (int i = 0; i < dl.size_s(); ++i) {
|
for (int i = 0; i < ret.size_s(); ++i) {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
void * hComm = CreateFileA(dl[i].data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
void * hComm = CreateFileA(ret[i].path.dataAscii(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||||
if (hComm == INVALID_HANDLE_VALUE) {
|
if (hComm == INVALID_HANDLE_VALUE) {
|
||||||
#else
|
#else
|
||||||
int fd = ::open(dl[i].data(), O_NOCTTY | O_RDONLY);
|
int fd = ::open(ret[i].path.dataAscii(), O_NOCTTY | O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
#endif
|
#endif
|
||||||
dl.remove(i);
|
ret.remove(i);
|
||||||
--i;
|
--i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -889,7 +1094,7 @@ PIStringList PISerial::availableDevices(bool test) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
if (!rok) {
|
if (!rok) {
|
||||||
dl.remove(i);
|
ret.remove(i);
|
||||||
--i;
|
--i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -900,7 +1105,7 @@ PIStringList PISerial::availableDevices(bool test) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dl;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,29 @@ public:
|
|||||||
S4000000 /*! 4000000 baud */ = 4000000
|
S4000000 /*! 4000000 baud */ = 4000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \brief Information about serial device
|
||||||
|
struct DeviceInfo {
|
||||||
|
DeviceInfo();
|
||||||
|
|
||||||
|
//! \brief String representation of USB ID in format \"xxxx:xxxx\"
|
||||||
|
PIString id() const;
|
||||||
|
|
||||||
|
//! \brief USB Vendor ID
|
||||||
|
uint vID;
|
||||||
|
|
||||||
|
//! \brief USB Product ID
|
||||||
|
uint pID;
|
||||||
|
|
||||||
|
//! \brief Path to device, e.g. "COM2" or "/dev/ttyUSB0"
|
||||||
|
PIString path;
|
||||||
|
|
||||||
|
//! \brief Device description
|
||||||
|
PIString description;
|
||||||
|
|
||||||
|
//! \brief Device manufacturer
|
||||||
|
PIString manufacturer;
|
||||||
|
};
|
||||||
|
|
||||||
//! Contructs %PISerial with device name "device", speed "speed" and parameters "params"
|
//! Contructs %PISerial with device name "device", speed "speed" and parameters "params"
|
||||||
explicit PISerial(const PIString & device, PISerial::Speed speed = S115200, PIFlags<PISerial::Parameters> params = 0);
|
explicit PISerial(const PIString & device, PISerial::Speed speed = S115200, PIFlags<PISerial::Parameters> params = 0);
|
||||||
|
|
||||||
@@ -173,9 +196,12 @@ public:
|
|||||||
//! \brief Returns all available speeds for serial devices
|
//! \brief Returns all available speeds for serial devices
|
||||||
static PIVector<int> availableSpeeds();
|
static PIVector<int> availableSpeeds();
|
||||||
|
|
||||||
//! \brief Returns all available system devices. If "test" each device will be tried to open
|
//! \brief Returns all available system devices path. If "test" each device will be tried to open
|
||||||
static PIStringList availableDevices(bool test = false);
|
static PIStringList availableDevices(bool test = false);
|
||||||
|
|
||||||
|
//! \brief Returns all available system devices. If "test" each device will be tried to open
|
||||||
|
static PIVector<DeviceInfo> availableDevicesInfo(bool test = false);
|
||||||
|
|
||||||
//! \ioparams
|
//! \ioparams
|
||||||
//! \{
|
//! \{
|
||||||
#ifdef DOXYGEN
|
#ifdef DOXYGEN
|
||||||
@@ -232,4 +258,16 @@ protected:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline PICout operator <<(PICout s, const PISerial::DeviceInfo & v) {
|
||||||
|
s << v.path << " (" << v.id() << ", \"" << v.manufacturer << "\", \"" << v.description << "\")";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator ==(const PISerial::DeviceInfo & v0, const PISerial::DeviceInfo & v1) {return v0.path == v1.path;}
|
||||||
|
inline bool operator !=(const PISerial::DeviceInfo & v0, const PISerial::DeviceInfo & v1) {return v0.path != v1.path;}
|
||||||
|
inline PIByteArray & operator <<(PIByteArray & s, const PISerial::DeviceInfo & v) {s << v.vID << v.pID << v.path << v.description << v.manufacturer; return s;}
|
||||||
|
inline PIByteArray & operator >>(PIByteArray & s, PISerial::DeviceInfo & v) {s >> v.vID >> v.pID >> v.path >> v.description >> v.manufacturer; return s;}
|
||||||
|
|
||||||
|
|
||||||
#endif // PISERIAL_H
|
#endif // PISERIAL_H
|
||||||
|
|||||||
@@ -375,7 +375,6 @@ void PISystemMonitor::gatherThread(llong id) {
|
|||||||
ts.name = tbid.value(id, "<PIThread>");
|
ts.name = tbid.value(id, "<PIThread>");
|
||||||
#else
|
#else
|
||||||
ts.name = tbid.value(id, "<non-PIThread>");
|
ts.name = tbid.value(id, "<non-PIThread>");
|
||||||
PISystemTime ct = PISystemTime::current();
|
|
||||||
# ifndef WINDOWS
|
# ifndef WINDOWS
|
||||||
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
|
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
|
||||||
//piCout << f.path();
|
//piCout << f.path();
|
||||||
@@ -399,6 +398,7 @@ void PISystemMonitor::gatherThread(llong id) {
|
|||||||
ts.user_time = PISystemTime::fromMilliseconds(sl[12].toInt() * 10.);
|
ts.user_time = PISystemTime::fromMilliseconds(sl[12].toInt() * 10.);
|
||||||
ts.kernel_time = PISystemTime::fromMilliseconds(sl[13].toInt() * 10.);
|
ts.kernel_time = PISystemTime::fromMilliseconds(sl[13].toInt() * 10.);
|
||||||
# else
|
# else
|
||||||
|
PISystemTime ct = PISystemTime::current();
|
||||||
FILETIME times[4];
|
FILETIME times[4];
|
||||||
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
|
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
|
||||||
if (thdl == NULL) {
|
if (thdl == NULL) {
|
||||||
|
|||||||
Reference in New Issue
Block a user