Merge branch 'master' into pico_sdk

This commit is contained in:
2026-08-11 09:56:27 +03:00
33 changed files with 749 additions and 405 deletions
+2 -2
View File
@@ -5,8 +5,8 @@ if (POLICY CMP0177)
endif() endif()
project(PIP) project(PIP)
set(PIP_MAJOR 5) set(PIP_MAJOR 5)
set(PIP_MINOR 7) set(PIP_MINOR 8)
set(PIP_REVISION 0) set(PIP_REVISION 1)
set(PIP_SUFFIX _beta) set(PIP_SUFFIX _beta)
set(PIP_COMPANY SHS) set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS) set(PIP_DOMAIN org.SHS)
@@ -37,6 +37,7 @@ PIClientServer::Server::Server() {
auto sc = client_factory(); auto sc = client_factory();
if (!sc) { if (!sc) {
piCout << "ClientFactory returns nullptr!"_tr("PIClientServer"); piCout << "ClientFactory returns nullptr!"_tr("PIClientServer");
delete c;
return; return;
} }
sc->createForServer(this, c); sc->createForServer(this, c);
+1 -1
View File
@@ -880,7 +880,7 @@ bool PITerminal::initialize() {
execvp(argv[0], argv); execvp(argv[0], argv);
delete[] argv[0]; delete[] argv[0];
delete[] argv; delete[] argv;
exit(0); exit(errno);
} else { } else {
if (fr < 0 || PRIVATE->fd < 0) { if (fr < 0 || PRIVATE->fd < 0) {
piCoutObj << "forkpty error," << errorString(); piCoutObj << "forkpty error," << errorString();
+21 -133
View File
@@ -1,14 +1,25 @@
#include "pihttpserver.h" #include "pihttpserver.h"
#include "piliterals_string.h" #include "piserverendpoint_p.h"
struct Endpoint: public PIHTTP::ServerEndpoint {
PIHTTP::Method method = PIHTTP::Method::Unknown;
PIHTTPServer::RequestFunction function;
};
PRIVATE_DEFINITION_START(PIHTTPServer)
PIMap<uint, PIVector<Endpoint>> endpoints;
PRIVATE_DEFINITION_END(PIHTTPServer)
PIHTTPServer::PIHTTPServer() { PIHTTPServer::PIHTTPServer() {
setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable { setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable {
PIHTTP::MessageMutable reply; PIHTTP::MessageMutable reply;
reply.setCode(PIHTTP::Code::NotFound); reply.setCode(PIHTTP::Code::NotFound);
auto in_path = splitPath(r.path()); auto in_path = PIHTTP::ServerEndpoint::splitPath(r.path());
auto it = endpoints.makeReverseIterator(); auto it = PRIVATE->endpoints.makeReverseIterator();
bool found = false; bool found = false;
while (it.next()) { while (it.next()) {
for (const auto & ep: it.value()) { for (const auto & ep: it.value()) {
@@ -46,7 +57,7 @@ bool PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, Re
if (!ep.create(path)) return false; if (!ep.create(path)) return false;
ep.method = method; ep.method = method;
ep.function = std::move(functor); ep.function = std::move(functor);
endpoints[ep.priority] << ep; PRIVATE->endpoints[ep.priority] << ep;
return true; return true;
} }
@@ -57,143 +68,20 @@ void PIHTTPServer::registerUnhandled(RequestFunction functor) {
void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) { void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) {
auto pl = splitPath(path); auto pl = PIHTTP::ServerEndpoint::splitPath(path);
auto it = endpoints.makeIterator(); auto it = PRIVATE->endpoints.makeIterator();
while (it.next()) { while (it.next()) {
it.value().removeWhere([&pl, method](const Endpoint & ep) { return ep.path == pl && ep.method == method; }); it.value().removeWhere([&pl, method](const Endpoint & ep) { return ep.path == pl && ep.method == method; });
} }
endpoints.removeWhere([](uint, const PIVector<Endpoint> & epl) { return epl.isEmpty(); }); PRIVATE->endpoints.removeWhere([](uint, const PIVector<Endpoint> & epl) { return epl.isEmpty(); });
} }
void PIHTTPServer::unregisterPath(const PIString & path) { void PIHTTPServer::unregisterPath(const PIString & path) {
auto pl = splitPath(path); auto pl = PIHTTP::ServerEndpoint::splitPath(path);
auto it = endpoints.makeIterator(); auto it = PRIVATE->endpoints.makeIterator();
while (it.next()) { while (it.next()) {
it.value().removeWhere([&pl](const Endpoint & ep) { return ep.path == pl; }); it.value().removeWhere([&pl](const Endpoint & ep) { return ep.path == pl; });
} }
endpoints.removeWhere([](uint, const PIVector<Endpoint> & epl) { return epl.isEmpty(); }); PRIVATE->endpoints.removeWhere([](uint, const PIVector<Endpoint> & epl) { return epl.isEmpty(); });
}
PIStringList PIHTTPServer::splitPath(const PIString & path) {
auto ret = path.split("/");
ret.removeAll({});
return ret;
}
PIHTTPServer::PathElement::PathElement(const PIString & reg) {
source = reg;
if (reg == "*"_a) {
type = Type::AnyOne;
} else if (reg == "**"_a) {
type = Type::AnyMany;
} else if (reg.contains('*')) {
type = Type::AnyPart;
parts = reg.split('*');
} else if (reg.contains('{')) {
type = Type::Arguments;
int ind = 0, eind = 0, pind = 0;
for (;;) {
ind = reg.find('{', ind);
if (ind < 0) break;
eind = reg.find('}', ind + 1);
if (eind < 0) break;
arguments.insert(arguments.size_s(), reg.mid(ind + 1, eind - ind - 1));
if (ind == 0)
parts << PIString();
else {
if (ind > pind)
parts << reg.mid(pind, ind - pind);
else if (parts.isNotEmpty()) {
piCout << "[PIHTTPServer] Warning: sequential arguments, ignoring this path!";
type = Type::Invalid;
return;
}
}
ind = pind = eind + 1;
}
if (eind < reg.size_s() - 1) parts << reg.mid(eind + 1);
}
}
bool PIHTTPServer::PathElement::match(const PIString & in, PIMap<PIString, PIString> & ext_args) const {
// piCout << "match" << source << "with" << in;
if (type == Type::AnyOne) return true;
if (type == Type::AnyPart) {
int ind = 0;
for (const auto & m: parts) {
ind = in.find(m, ind);
if (ind < 0) return false;
}
return true;
}
if (type == Type::Arguments) {
int ind = 0, eind = 0;
for (int i = 0; i < parts.size_s(); ++i) {
const auto & m(parts[i]);
if (m.isNotEmpty()) {
ind = in.find(m, eind);
if (ind < 0) return false;
}
if (i > 0) {
ext_args[arguments.value(i - 1)] = in.mid(eind, ind - eind);
}
eind = ind + m.size_s();
}
if (parts.size() == arguments.size()) {
ext_args[arguments.value(arguments.size_s() - 1)] = in.mid(eind);
}
return true;
}
return source == in;
}
uint PIHTTPServer::PathElement::priority() const {
switch (type) {
case Type::Fixed: return 0x10000; break;
case Type::Arguments: return 0x1000; break;
case Type::AnyPart: return 0x100; break;
case Type::AnyOne: return 0x10; break;
case Type::AnyMany: return 0x1; break;
default: break;
}
return 0;
}
bool PIHTTPServer::Endpoint::create(const PIString & p) {
path = splitPath(p);
prepared_path.clear();
priority = 0;
for (const auto & i: path) {
PathElement pe(i);
prepared_path << pe;
path_types |= pe.type;
priority += pe.priority();
}
return !path_types[PathElement::Type::Invalid];
}
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const {
if (path_types[PathElement::Type::AnyMany]) {
int any_ind = path.indexOf("**"_a);
for (int i = 0; i < any_ind; ++i) {
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
}
int si = prepared_path.size_s() - 1, ii = in_path.size_s() - 1;
for (; si > any_ind && ii >= 0; --si, --ii) {
if (!prepared_path[si].match(in_path[ii], ext_args)) return false;
}
} else {
if (in_path.size() != prepared_path.size()) return false;
for (int i = 0; i < prepared_path.size_s(); ++i) {
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
}
}
return true;
} }
+20 -14
View File
@@ -577,28 +577,36 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc) { PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc) {
static const PIString s_ss = PIStringAscii(" "); static const PIString s_ss = PIStringAscii(" ");
static const PIString s_M = PIStringAscii("$M"); static const PIString s_M = PIStringAscii("$M");
static const PIString s_class = PIStringAscii("class"); static const PIString s_class = PIStringAscii("class");
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn; static const PIString s_public = PIStringAscii("public");
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
MetaMap meta; MetaMap meta;
int ind = cd.find(s_M); int ind = cd.find(s_M);
if (ind >= 0) { if (ind >= 0) {
meta = tmp_meta.value(cd.takeMid(ind, 5)); meta = tmp_meta.value(cd.takeMid(ind, 5));
cd.replaceAll(s_ss, ' '); cd.replaceAll(s_ss, ' ');
} }
PIString typename_ = cd.left(6).trim();
bool is_class = typename_ == s_class;
ind = cd.find(':');
// piCout << "found class <****\n" << cd << "\n****>"; // piCout << "found class <****\n" << cd << "\n****>";
ind = cd.find(':');
PIVector<Entity *> parents; PIVector<Entity *> parents;
if (ind > 0) { if (ind > 0) {
PIStringList pl = cd.takeMid(ind + 1).trim().split(','); PIStringList pl = cd.takeMid(ind + 1).trim().split(',');
cd.cutRight(1); cd.cutRight(1);
Entity * pe = 0; Entity * pe = 0;
for (const auto & p: pl) { for (const auto & p: pl) {
if (p.contains(' ')) PIString access;
pn = p.mid(p.find(' ') + 1); if (p.contains(' ')) {
else access = p.left(p.find(' ')).trim();
pn = p.mid(p.find(' ') + 1);
} else {
pn = p; pn = p;
}
bool is_public = access.isEmpty() ? !is_class : access == s_public;
if (!is_public) continue;
pe = findEntityByName(pn); pe = findEntityByName(pn);
if (pe == 0) if (pe == 0)
; //{piCout << "Error: can`t find" << pn;} ; //{piCout << "Error: can`t find" << pn;}
@@ -606,12 +614,10 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
parents << pe; parents << pe;
} }
} }
PIString typename_ = cd.left(6).trim(); Visibility vis = cur_def_vis;
bool is_class = typename_ == s_class; cur_def_vis = (is_class ? Private : Public);
Visibility vis = cur_def_vis; PIString cn = cd.mid(6).trim();
cur_def_vis = (is_class ? Private : Public); bool is_anonymous = cn.isEmpty();
PIString cn = cd.mid(6).trim();
bool is_anonymous = cn.isEmpty();
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>'; if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
// piCout << "found " << typename_ << cn; // piCout << "found " << typename_ << cn;
Entity * e = new Entity(); Entity * e = new Entity();
+8 -7
View File
@@ -66,9 +66,9 @@ void PIWaitEvent::destroy() {
} }
# else # else
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
if (pipe_fd[i] != 0) { if (pipe_fd[i] != -1) {
::close(pipe_fd[i]); ::close(pipe_fd[i]);
pipe_fd[i] = 0; pipe_fd[i] = -1;
} }
} }
# endif # endif
@@ -90,12 +90,13 @@ bool PIWaitEvent::wait(int fd, CheckRole role) {
FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead])); FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead]));
FD_SET(fd, &(fds[CheckExeption])); FD_SET(fd, &(fds[CheckExeption]));
if (fd_index != CheckExeption) FD_SET(fd, &(fds[fd_index])); if (fd_index != CheckExeption) FD_SET(fd, &(fds[fd_index]));
int sr = ::select(nfds, &(fds[CheckRead]), &(fds[CheckWrite]), &(fds[CheckExeption]), nullptr); int sr = ::select(nfds, &(fds[CheckRead]), &(fds[CheckWrite]), &(fds[CheckExeption]), nullptr);
if (sr < 0) return false;
errorClear();
int buf = 0; int buf = 0;
while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0) while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0) {}
;
// piCout << "wait result" << sr << FD_ISSET(fd, &(fds[CheckExeption])) << FD_ISSET(fd, &(fds[fd_index])); // piCout << "wait result" << sr << FD_ISSET(fd, &(fds[CheckExeption])) << FD_ISSET(fd, &(fds[fd_index]));
if (sr == EBADF || sr == EINTR) return false; if (errno == EBADF || errno == EINTR) return false;
if (FD_ISSET(fd, &(fds[CheckExeption]))) return true; if (FD_ISSET(fd, &(fds[CheckExeption]))) return true;
return FD_ISSET(fd, &(fds[fd_index])); return FD_ISSET(fd, &(fds[fd_index]));
# endif # endif
@@ -140,7 +141,7 @@ bool PIWaitEvent::isCreate() const {
# ifdef WINDOWS # ifdef WINDOWS
return event; return event;
# else # else
return pipe_fd[ReadEnd] != 0; return pipe_fd[ReadEnd] != -1;
# endif # endif
} }
+1 -1
View File
@@ -57,7 +57,7 @@ private:
# ifdef WINDOWS # ifdef WINDOWS
void * event = nullptr; void * event = nullptr;
# else # else
int pipe_fd[2] = {0, 0}; int pipe_fd[2] = {-1, -1};
fd_set fds[3]; fd_set fds[3];
enum { enum {
ReadEnd = 0, ReadEnd = 0,
+125
View File
@@ -0,0 +1,125 @@
#include "piliterals_string.h"
#include "piserverendpoint_p.h"
PIStringList PIHTTP::ServerEndpoint::splitPath(const PIString & path) {
auto ret = path.split("/");
ret.removeAll({});
return ret;
}
PIHTTP::ServerEndpoint::PathElement::PathElement(const PIString & reg) {
source = reg;
if (reg == "*"_a) {
type = Type::AnyOne;
} else if (reg == "**"_a) {
type = Type::AnyMany;
} else if (reg.contains('*')) {
type = Type::AnyPart;
parts = reg.split('*');
} else if (reg.contains('{')) {
type = Type::Arguments;
int ind = 0, eind = 0, pind = 0;
for (;;) {
ind = reg.find('{', ind);
if (ind < 0) break;
eind = reg.find('}', ind + 1);
if (eind < 0) break;
arguments.insert(arguments.size_s(), reg.mid(ind + 1, eind - ind - 1));
if (ind == 0)
parts << PIString();
else {
if (ind > pind)
parts << reg.mid(pind, ind - pind);
else if (parts.isNotEmpty()) {
piCout << "[PIHTTP::ServerEndpoint] Warning: sequential arguments, ignoring this path!";
type = Type::Invalid;
return;
}
}
ind = pind = eind + 1;
}
if (eind < reg.size_s() - 1) parts << reg.mid(eind + 1);
}
}
bool PIHTTP::ServerEndpoint::PathElement::match(const PIString & in, PIMap<PIString, PIString> & ext_args) const {
// piCout << "match" << source << "with" << in;
if (type == Type::AnyOne) return true;
if (type == Type::AnyPart) {
int ind = 0;
for (const auto & m: parts) {
ind = in.find(m, ind);
if (ind < 0) return false;
}
return true;
}
if (type == Type::Arguments) {
int ind = 0, eind = 0;
for (int i = 0; i < parts.size_s(); ++i) {
const auto & m(parts[i]);
if (m.isNotEmpty()) {
ind = in.find(m, eind);
if (ind < 0) return false;
}
if (i > 0) {
ext_args[arguments.value(i - 1)] = in.mid(eind, ind - eind);
}
eind = ind + m.size_s();
}
if (parts.size() == arguments.size()) {
ext_args[arguments.value(arguments.size_s() - 1)] = in.mid(eind);
}
return true;
}
return source == in;
}
uint PIHTTP::ServerEndpoint::PathElement::priority() const {
switch (type) {
case Type::Fixed: return 0x10000; break;
case Type::Arguments: return 0x1000; break;
case Type::AnyPart: return 0x100; break;
case Type::AnyOne: return 0x10; break;
case Type::AnyMany: return 0x1; break;
default: break;
}
return 0;
}
bool PIHTTP::ServerEndpoint::create(const PIString & p) {
path = splitPath(p);
prepared_path.clear();
priority = 0;
for (const auto & i: path) {
PathElement pe(i);
prepared_path << pe;
path_types |= pe.type;
priority += pe.priority();
}
return !path_types[PathElement::Type::Invalid];
}
bool PIHTTP::ServerEndpoint::match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const {
if (path_types[PathElement::Type::AnyMany]) {
int any_ind = path.indexOf("**"_a);
for (int i = 0; i < any_ind; ++i) {
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
}
int si = prepared_path.size_s() - 1, ii = in_path.size_s() - 1;
for (; si > any_ind && ii >= 0; --si, --ii) {
if (!prepared_path[si].match(in_path[ii], ext_args)) return false;
}
} else {
if (in_path.size() != prepared_path.size()) return false;
for (int i = 0; i < prepared_path.size_s(); ++i) {
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
}
}
return true;
}
@@ -0,0 +1,72 @@
//! \~\file piserverendpoint_p.h
//! \~\ingroup HTTP
//! \~\brief
//! \~english Shared HTTP message container types
//! \~russian Общие типы контейнеров HTTP-сообщений
/*
PIP - Platform Independent Primitives
Shared HTTP message container types
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 piserverendpoint_p_h
#define piserverendpoint_p_h
#include "pip_export.h"
#include "pistringlist.h"
namespace PIHTTP {
struct PIP_EXPORT ServerEndpoint {
struct PIP_EXPORT PathElement {
enum class Type {
Invalid = 0x01,
Fixed = 0x02,
Arguments = 0x04,
AnyOne = 0x08,
AnyPart = 0x10,
AnyMany = 0x20
};
Type type = Type::Fixed;
PIString source;
PIStringList parts;
PIMap<int, PIString> arguments;
PathElement(const PIString & reg = {});
bool match(const PIString & in, PIMap<PIString, PIString> & ext_args) const;
uint priority() const;
};
PIStringList path;
PIFlags<PathElement::Type> path_types;
PIVector<PathElement> prepared_path;
uint priority = 0;
bool create(const PIString & p);
bool match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const;
static PIStringList splitPath(const PIString & path);
};
}; // namespace PIHTTP
#endif
+1 -35
View File
@@ -102,43 +102,9 @@ public:
void clearReplyHeaders() { reply_headers.clear(); } void clearReplyHeaders() { reply_headers.clear(); }
private: private:
struct PathElement { PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT)
enum class Type {
Invalid = 0x01,
Fixed = 0x02,
Arguments = 0x04,
AnyOne = 0x08,
AnyPart = 0x10,
AnyMany = 0x20
};
Type type = Type::Fixed;
PIString source;
PIStringList parts;
PIMap<int, PIString> arguments;
PathElement(const PIString & reg = {});
bool match(const PIString & in, PIMap<PIString, PIString> & ext_args) const;
uint priority() const;
};
struct Endpoint {
PIStringList path;
PIHTTP::Method method = PIHTTP::Method::Unknown;
RequestFunction function;
PIFlags<PathElement::Type> path_types;
PIVector<PathElement> prepared_path;
uint priority = 0;
bool create(const PIString & p);
bool match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const;
};
static PIStringList splitPath(const PIString & path);
PIMap<PIString, PIString> reply_headers; PIMap<PIString, PIString> reply_headers;
PIMap<uint, PIVector<Endpoint>> endpoints;
RequestFunction unhandled; RequestFunction unhandled;
}; };
+18 -3
View File
@@ -24,6 +24,7 @@
# define PIP_CAN # define PIP_CAN
#endif #endif
#ifdef PIP_CAN #ifdef PIP_CAN
# include <fcntl.h>
# include <linux/can.h> # include <linux/can.h>
# include <linux/can/raw.h> # include <linux/can/raw.h>
# include <net/if.h> # include <net/if.h>
@@ -50,7 +51,7 @@ PICAN::PICAN(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(pat
setPath(path); setPath(path);
#ifdef PIP_CAN #ifdef PIP_CAN
can_id = 0; can_id = 0;
sock = 0; sock = -1;
PRIVATE->event.create(); PRIVATE->event.create();
#endif #endif
} }
@@ -71,19 +72,25 @@ bool PICAN::openDevice() {
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (sock < 0) { if (sock < 0) {
piCoutObj << "Error! while opening socket"; piCoutObj << "Error! while opening socket";
sock = -1;
return false; return false;
} }
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
ifreq ifr; ifreq ifr;
strcpy(ifr.ifr_name, path().dataAscii()); strcpy(ifr.ifr_name, path().dataAscii());
piCout << "PICAN try to get interface index..."; piCout << "PICAN try to get interface index...";
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) { if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
piCoutObj << "Error! while determin the interface ioctl"; piCoutObj << "Error! while determin the interface ioctl";
::close(sock);
sock = -1;
return false; return false;
} }
struct timeval tv; struct timeval tv;
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv); if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) < 0) {
piCoutObj << "Error! while setting socket receive timeout";
}
// bind socket to all CAN interface // bind socket to all CAN interface
sockaddr_can addr; sockaddr_can addr;
addr.can_family = AF_CAN; addr.can_family = AF_CAN;
@@ -91,6 +98,8 @@ bool PICAN::openDevice() {
piCout << "PICAN try to bind socket to interface" << ifr.ifr_ifindex; piCout << "PICAN try to bind socket to interface" << ifr.ifr_ifindex;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
piCoutObj << "Error! while binding socket"; piCoutObj << "Error! while binding socket";
::close(sock);
sock = -1;
return false; return false;
} }
piCout << "PICAN Open OK!"; piCout << "PICAN Open OK!";
@@ -105,7 +114,11 @@ bool PICAN::openDevice() {
bool PICAN::closeDevice() { bool PICAN::closeDevice() {
#ifdef PIP_CAN #ifdef PIP_CAN
interrupt(); interrupt();
if (sock > 0) ::close(sock); if (sock != -1) {
::shutdown(sock, SHUT_RDWR);
::close(sock);
sock = -1;
}
#endif #endif
return true; return true;
} }
@@ -113,6 +126,7 @@ bool PICAN::closeDevice() {
ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) { ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) {
#ifdef PIP_CAN #ifdef PIP_CAN
if (sock == -1) return -1;
// piCout << "PICAN read"; // piCout << "PICAN read";
can_frame frame; can_frame frame;
ssize_t ret = 0; ssize_t ret = 0;
@@ -131,6 +145,7 @@ ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) {
ssize_t PICAN::writeDevice(const void * data, ssize_t max_size) { ssize_t PICAN::writeDevice(const void * data, ssize_t max_size) {
#ifdef PIP_CAN #ifdef PIP_CAN
if (sock == -1) return -1;
// piCout << "PICAN write" << can_id << max_size; // piCout << "PICAN write" << can_id << max_size;
if (max_size > 8) { if (max_size > 8) {
piCoutObj << "Can't send CAN frame bigger than 8 bytes (requested " << max_size << ")!"; piCoutObj << "Can't send CAN frame bigger than 8 bytes (requested " << max_size << ")!";
+1 -1
View File
@@ -73,7 +73,7 @@ protected:
private: private:
PRIVATE_DECLARATION(PIP_EXPORT) PRIVATE_DECLARATION(PIP_EXPORT)
int sock; int sock = -1;
int can_id, readed_id; int can_id, readed_id;
}; };
+20 -6
View File
@@ -103,7 +103,11 @@
# ifndef WINDOWS # ifndef WINDOWS
PIString getSockAddr(sockaddr * s) { PIString getSockAddr(sockaddr * s) {
return s == 0 ? PIString() : PIStringAscii(inet_ntoa(((sockaddr_in *)s)->sin_addr)); if (!s) return PIString();
char buf[INET_ADDRSTRLEN];
piZeroMemory(buf, sizeof(buf));
const char * r = inet_ntop(AF_INET, &((sockaddr_in *)s)->sin_addr, buf, sizeof(buf));
return r ? PIStringAscii(r) : PIString();
} }
# endif # endif
@@ -862,6 +866,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
return -1; return -1;
} }
} }
ret += sr;
remain_data += sr; remain_data += sr;
remain_size -= sr; remain_size -= sr;
} }
@@ -1176,13 +1181,19 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
# else # else
# ifdef ANDROID # ifdef ANDROID
struct ifconf ifc; struct ifconf ifc;
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP); int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (s == -1) {
piCout << "[PIEthernet]"
<< "Can`t create socket: %1"_tr("PIEthernet").arg(errorString());
return il;
}
ifc.ifc_len = 256; ifc.ifc_len = 256;
ifc.ifc_buf = new char[ifc.ifc_len]; ifc.ifc_buf = new char[ifc.ifc_len];
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
piCout << "[PIEthernet]" piCout << "[PIEthernet]"
<< "Can`t get interfaces: %1"_tr("PIEthernet").arg(errorString()); << "Can`t get interfaces: %1"_tr("PIEthernet").arg(errorString());
delete[] ifc.ifc_buf; delete[] ifc.ifc_buf;
::close(s);
return il; return il;
} }
int icnt = ifc.ifc_len / sizeof(ifreq); int icnt = ifc.ifc_len / sizeof(ifreq);
@@ -1201,7 +1212,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
if (ci.address == "127.0.0.1") ci.flags |= PIEthernet::ifLoopback; if (ci.address == "127.0.0.1") ci.flags |= PIEthernet::ifLoopback;
il << ci; il << ci;
} }
delete ifc.ifc_buf; delete[] ifc.ifc_buf;
::close(s);
# else # else
struct ifaddrs *ret, *cif = 0; struct ifaddrs *ret, *cif = 0;
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP); int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
@@ -1223,7 +1235,7 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
# ifdef QNX # ifdef QNX
# ifndef BLACKBERRY # ifndef BLACKBERRY
int fd = ::open((PIString("/dev/io-net/") + ci.name).dataAscii(), O_RDONLY); int fd = ::open((PIString("/dev/io-net/") + ci.name).dataAscii(), O_RDONLY);
if (fd != 0) { if (fd >= 0) {
nic_config_t nic; nic_config_t nic;
devctl(fd, DCMD_IO_NET_GET_CONFIG, &nic, sizeof(nic), 0); devctl(fd, DCMD_IO_NET_GET_CONFIG, &nic, sizeof(nic), 0);
::close(fd); ::close(fd);
@@ -1292,8 +1304,10 @@ PINetworkAddress PIEthernet::interfaceAddress(const PIString & interface_) {
piZeroMemory(ifr); piZeroMemory(ifr);
strcpy(ifr.ifr_name, interface_.dataAscii()); strcpy(ifr.ifr_name, interface_.dataAscii());
int s = ::socket(AF_INET, SOCK_DGRAM, 0); int s = ::socket(AF_INET, SOCK_DGRAM, 0);
ioctl(s, SIOCGIFADDR, &ifr); if (s != -1) {
::close(s); ioctl(s, SIOCGIFADDR, &ifr);
::close(s);
}
struct sockaddr_in * sa = (struct sockaddr_in *)&ifr.ifr_addr; struct sockaddr_in * sa = (struct sockaddr_in *)&ifr.ifr_addr;
return PINetworkAddress(uint(sa->sin_addr.s_addr)); return PINetworkAddress(uint(sa->sin_addr.s_addr));
# endif # endif
+1 -2
View File
@@ -62,8 +62,7 @@ ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
if (ret <= 0) return -1; if (ret <= 0) return -1;
memcpy(read_to, data_->data(pos), ret); memcpy(read_to, data_->data(pos), ret);
// piCout << "readed" << ret; // piCout << "readed" << ret;
pos += size; pos += ret;
if (pos > data_->size_s()) pos = data_->size_s();
return ret; return ret;
} }
+4 -1
View File
@@ -623,7 +623,10 @@ bool PIPeer::dataRead(const uchar * readed, ssize_t size) {
return true; return true;
} }
cnt++; cnt++;
if (cnt > _PIPEER_MSG_TTL || from == dp->name) return true; if (cnt > _PIPEER_MSG_TTL || from == dp->name) {
eth_mutex.unlock();
return true;
}
sba << type << from << to << cnt << pba; sba << type << from << to << cnt << pba;
// piCout << "translate packet" << from << "->" << to << ", ttl =" << cnt; // piCout << "translate packet" << from << "->" << to << ", ttl =" << cnt;
sendToNeighbour(dp, sba); sendToNeighbour(dp, sba);
+4 -1
View File
@@ -512,7 +512,10 @@ bool PISerial::read(void * data, int size, double timeout_ms) {
all = readDevice(data, 1); all = readDevice(data, 1);
while (all < size) { while (all < size) {
ret = readDevice(&((uchar *)data)[all], size - all); ret = readDevice(&((uchar *)data)[all], size - all);
if (ret > 0) all += ret; if (ret > 0)
all += ret;
else
break;
} }
setOption(BlockingRead, br); setOption(BlockingRead, br);
received(data, all); received(data, all);
+6
View File
@@ -131,6 +131,12 @@ bool PIFileTransfer::sendFiles(const PIVector<PFTFileInfo> & files) {
void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) { void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) {
// piCout << "processFile" << id << files_.size(); // piCout << "processFile" << id << files_.size();
if (id <= 0 || id > files_.size_s()) {
cur_file_string = "Error: Invalid file id " + PIString::fromNumber(id);
piCoutObj << cur_file_string;
stopReceive();
return;
}
PFTFileInfo fi = files_[id - 1]; PFTFileInfo fi = files_[id - 1];
bytes_file_all = fi.size; bytes_file_all = fi.size;
bytes_file_cur = start; bytes_file_cur = start;
+13 -8
View File
@@ -308,10 +308,12 @@ inline PIVector<T> piAbs(const PIVector<T> & v) {
//! \~russian Нормализует угол к диапазону `[0; 360]` градусов на месте. //! \~russian Нормализует угол к диапазону `[0; 360]` градусов на месте.
template<typename T> template<typename T>
void normalizeAngleDeg360(T & a) { void normalizeAngleDeg360(T & a) {
while (a < 0.) if (std::isnan(a) || std::isinf(a)) {
a += 360.; a = 0.;
while (a > 360.) return;
a -= 360.; }
a -= std::floor(a / 360.) * 360.;
if (a < 0) a += 360;
} }
//! \~english Returns an angle normalized to the `[0; 360]` degree range. //! \~english Returns an angle normalized to the `[0; 360]` degree range.
@@ -327,10 +329,13 @@ double normalizedAngleDeg360(T a) {
//! \~russian Нормализует угол к диапазону `[-180; 180]` градусов на месте. //! \~russian Нормализует угол к диапазону `[-180; 180]` градусов на месте.
template<typename T> template<typename T>
void normalizeAngleDeg180(T & a) { void normalizeAngleDeg180(T & a) {
while (a < -180.) if (std::isnan(a) || std::isinf(a)) {
a += 360.; a = 0.;
while (a > 180.) return;
a -= 360.; }
a -= std::floor(a / 360.) * 360.;
if (a < -180) a += 360;
if (a >= 180) a -= 360;
} }
//! \~english Returns an angle normalized to the `[-180; 180]` degree range. //! \~english Returns an angle normalized to the `[-180; 180]` degree range.
+24
View File
@@ -167,6 +167,22 @@ public:
return *this; return *this;
} }
//! \~english Multiplies by-coordinates by `v`.
//! \~russian Умножает по-координатно на `v`.
PIPoint<Type> & operator*=(const PIPoint<Type> & v) {
x *= v.x;
y *= v.y;
return *this;
}
//! \~english Divides by-coordinates by `v`.
//! \~russian Делит по-координатно на `v`.
PIPoint<Type> & operator/=(const PIPoint<Type> & v) {
x /= v.x;
y /= v.y;
return *this;
}
//! \~english Returns sum of two points. //! \~english Returns sum of two points.
//! \~russian Возвращает сумму двух точек. //! \~russian Возвращает сумму двух точек.
PIPoint<Type> operator+(const PIPoint<Type> & p) const { return PIPoint<Type>(x + p.x, y + p.y); } PIPoint<Type> operator+(const PIPoint<Type> & p) const { return PIPoint<Type>(x + p.x, y + p.y); }
@@ -195,6 +211,14 @@ public:
//! \~russian Возвращает точку, деленную на `v`. //! \~russian Возвращает точку, деленную на `v`.
PIPoint<Type> operator/(Type v) const { return PIPoint<Type>(x / v, y / v); } PIPoint<Type> operator/(Type v) const { return PIPoint<Type>(x / v, y / v); }
//! \~english Returns point multiplied by `v`.
//! \~russian Возвращает точку, умноженную на `v`.
PIPoint<Type> operator*(const PIPoint<Type> & v) const { return PIPoint<Type>(x * v.x, y * v.y); }
//! \~english Returns point divided by `v`.
//! \~russian Возвращает точку, деленную на `v`.
PIPoint<Type> operator/(const PIPoint<Type> & v) const { return PIPoint<Type>(x / v.x, y / v.y); }
//! \~english Checks whether point coordinates are equal. //! \~english Checks whether point coordinates are equal.
//! \~russian Проверяет равенство координат точек. //! \~russian Проверяет равенство координат точек.
bool operator==(const PIPoint<Type> & p) const { return (x == p.x && y == p.y); } bool operator==(const PIPoint<Type> & p) const { return (x == p.x && y == p.y); }
+31 -5
View File
@@ -41,24 +41,39 @@ public:
Client(); Client();
virtual ~Client(); virtual ~Client();
//! \~english Request handler used by registered routes and fallback processing.
//! \~russian Обработчик запроса, используемый зарегистрированными маршрутами и fallback-обработкой.
using MessageFunction = std::function<void(const PIMQTT::MessageConst &)>;
void setConnectTimeout(PISystemTime time) { connect_timeout = time; } void setConnectTimeout(PISystemTime time) { connect_timeout = time; }
void connect(const PIString & address, const PIString & client, const PIString & username = {}, const PIString & password = {}); void connect(const PIString & address, const PIString & client, const PIString & username = {}, const PIString & password = {});
void disconnect(); void disconnect();
void subscribe(const PIString & topic, QoS qos = QoS::Level1); void subscribe(const PIString & topic, MessageFunction functor, QoS qos = QoS::Level1);
template<typename T>
void
subscribe(const PIString & topic, T * o, PIMQTT::MessageMutable (T::*function)(const PIMQTT::MessageConst &), QoS qos = QoS::Level1) {
subscribe(topic, [o, function](const PIMQTT::MessageConst & m) { return (o->*function)(m); }, qos);
}
void unsubscribe(const PIString & topic); void unsubscribe(const PIString & topic);
void unsubscribeAll();
void publish(const PIString & topic, const PIByteArray & msg, QoS qos = QoS::Level0); void publish(const PIString & topic, const PIByteArray & msg, QoS qos = QoS::Level0);
void publish(const MessageConst & msg); void publish(const MessageConst & msg);
void unsubscribeAll() { unsubscribe("#"); }
bool isConnecting() const { return m_status == Connecting; } bool isConnecting() const { return m_status == Connecting; }
bool isConnected() const { return m_status == Connected; } bool isConnected() const { return m_status == Connected; }
PIStringList usedTopics() const;
EVENT0(connected); EVENT0(connected);
EVENT1(disconnected, PIMQTT::Error, code); EVENT1(disconnected, PIMQTT::Error, code);
EVENT1(received, PIMQTT::MessageConst, message); EVENT1(receivedUnhandled, PIMQTT::MessageConst, message);
struct Endpoint;
private: private:
NO_COPY_CLASS(Client) NO_COPY_CLASS(Client)
@@ -79,23 +94,34 @@ private:
}; };
struct Subscribe { struct Subscribe {
PIString topic; PIString topic;
MessageFunction functor;
QoS qos; QoS qos;
}; };
void mqtt_connectionLost(); void mqtt_connectionLost();
void mqtt_deliveryComplete(int token); void mqtt_deliveryComplete(int token);
void mqtt_messageArrived(const MessageConst & msg); void mqtt_messageArrived(MessageMutable & msg);
PIString registerSubscribe(const Subscribe & sub);
PIString unregisterSubscribe(const PIString & mqtt_topic);
void unregisterAll();
void connectInternal(const ConnectInfo & ci); void connectInternal(const ConnectInfo & ci);
void disconnectInternal(); void disconnectInternal();
void publishInternal(const MessageConst & m); void publishInternal(const MessageConst & m);
void subscribeInternal(const Subscribe & sub); void subscribeInternal(const Subscribe & sub);
void unsubscribeInternal(const PIString & topic); void unsubscribeInternal(const PIString & mqtt_topic);
void destroy(); void destroy();
void changeStatus(Status s); void changeStatus(Status s);
void run(); void run();
// from HTTP format
static PIString convertTopic2MQTT(const PIString & topic);
// from MQTT format
static PIString convertTopic2HTTP(const PIString & topic);
std::atomic_int m_status = {Idle}; std::atomic_int m_status = {Idle};
std::atomic_bool is_destoying = {false}; std::atomic_bool is_destoying = {false};
PISystemTime connect_timeout = 10_s; PISystemTime connect_timeout = 10_s;
+28 -18
View File
@@ -56,17 +56,17 @@
#else #else
# define BINARY_STREAM_FRIEND(T) \ # define BINARY_STREAM_FRIEND(T) \
template<typename P> \ template<typename P> \
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v); \ friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v); \
template<typename P> \ template<typename P> \
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v); friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v);
# define BINARY_STREAM_WRITE(T) \ # define BINARY_STREAM_WRITE(T) \
template<typename P> \ template<typename P> \
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v) inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const T & v)
# define BINARY_STREAM_READ(T) \ # define BINARY_STREAM_READ(T) \
template<typename P> \ template<typename P> \
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v) inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, T & v)
#endif #endif
@@ -410,7 +410,7 @@ template<typename P,
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
// piCout << ">> vector trivial default"; // piCout << ">> vector trivial default";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -433,7 +433,7 @@ template<typename P,
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
// piCout << ">> vector trivial custom"; // piCout << ">> vector trivial custom";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -462,7 +462,7 @@ template<typename P,
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
// piCout << ">> deque trivial default"; // piCout << ">> deque trivial default";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -485,7 +485,7 @@ template<typename P,
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
// piCout << ">> deque trivial custom"; // piCout << ">> deque trivial custom";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -516,7 +516,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
int r, c; int r, c;
r = s.binaryStreamTakeInt(); r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt(); c = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || r < 0 || c < 0) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -542,6 +542,11 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
PIVector<T> tmp; PIVector<T> tmp;
r = s.binaryStreamTakeInt(); r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt(); c = s.binaryStreamTakeInt();
if (s.wasReadError() || r < 0 || c < 0) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
s >> tmp; s >> tmp;
if (s.wasReadError()) { if (s.wasReadError()) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
@@ -618,7 +623,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
//! \~russian Восстанавливает %PIVector из нетривиальных элементов по одному. //! \~russian Восстанавливает %PIVector из нетривиальных элементов по одному.
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -641,7 +646,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
//! \~russian Восстанавливает %PIDeque из нетривиальных элементов по одному. //! \~russian Восстанавливает %PIDeque из нетривиальных элементов по одному.
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -667,6 +672,11 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
PIVector<T> tmp; PIVector<T> tmp;
r = s.binaryStreamTakeInt(); r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt(); c = s.binaryStreamTakeInt();
if (s.wasReadError() || r < 0 || c < 0) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
s >> tmp; s >> tmp;
if (s.wasReadError()) { if (s.wasReadError()) {
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
@@ -700,7 +710,7 @@ template<typename P, typename Key, typename T>
//! \~russian Восстанавливает ключи и значения %PIMap. //! \~russian Восстанавливает ключи и значения %PIMap.
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
v.clear(); v.clear();
return s; return s;
@@ -749,7 +759,7 @@ template<typename P, typename Key>
//! \~russian Восстанавливает ключи %PISet. //! \~russian Восстанавливает ключи %PISet.
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<Key> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<Key> & v) {
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) { if (s.wasReadError() || sz < 0) {
fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key)); fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key));
v.clear(); v.clear();
return s; return s;
+1 -1
View File
@@ -547,7 +547,7 @@ void PIJSON::print(PIString & s, const PIJSON & v, PIString tab, bool spaces, bo
if (spaces) s += ' '; if (spaces) s += ' ';
} }
switch (v.c_type) { switch (v.c_type) {
case PIJSON::Invalid: break; case PIJSON::Invalid:
case PIJSON::Null: s += "null"; break; case PIJSON::Null: s += "null"; break;
case PIJSON::Boolean: s += PIString::fromBool(v.c_value.toBool()); break; case PIJSON::Boolean: s += PIString::fromBool(v.c_value.toBool()); break;
case PIJSON::Number: s += v.c_value.toString(); break; case PIJSON::Number: s += v.c_value.toString(); break;
@@ -291,6 +291,13 @@ inline PIJSON piSerializeJSON(const PIMathVectorT<Size, T> & v) {
return ret; return ret;
} }
template<>
//! \~english Serializes %PIStringList as JSON array.
//! \~russian Сериализует %PIStringList как JSON-массив.
inline PIJSON piSerializeJSON(const PIStringList & v) {
return piSerializeJSON((const PIDeque<PIString> &)v);
}
// --- // ---
// deserialize, piDeserializeJSON(T, PIJSON) // deserialize, piDeserializeJSON(T, PIJSON)
@@ -538,6 +545,13 @@ inline void piDeserializeJSON(PIMathVectorT<Size, T> & v, const PIJSON & js) {
piDeserializeJSON(v[i], js[i]); piDeserializeJSON(v[i], js[i]);
} }
template<>
//! \~english Deserializes %PIStringList from JSON array.
//! \~russian Десериализует %PIStringList из JSON-массива.
inline void piDeserializeJSON(PIStringList & v, const PIJSON & js) {
piDeserializeJSON((PIDeque<PIString> &)v, js);
}
// --- // ---
// PIJSON static wrapper // PIJSON static wrapper
+14 -7
View File
@@ -215,10 +215,10 @@ PRIVATE_DEFINITION_START(PIProcess)
PeekNamedPipe(pipes[pipe_type][PipeRead], nullptr, 0, nullptr, &available, nullptr); PeekNamedPipe(pipes[pipe_type][PipeRead], nullptr, 0, nullptr, &available, nullptr);
if (available > 0) { if (available > 0) {
BOOL ok = ReadFile(pipes[pipe_type][PipeRead], BOOL ok = ReadFile(pipes[pipe_type][PipeRead],
read_buffer.data(offset), read_buffer.data(offset),
piMini(available, read_buffer.size() - offset), piMini(available, read_buffer.size() - offset),
&bytes_read, &bytes_read,
nullptr); nullptr);
if (!ok) bytes_read = 0; if (!ok) bytes_read = 0;
} }
# else # else
@@ -293,10 +293,10 @@ void PIProcess::startProc(bool detached) {
si.dwFlags |= STARTF_USESTDHANDLES; si.dwFlags |= STARTF_USESTDHANDLES;
const auto cmd = convertWindowsCmd(args); const auto cmd = convertWindowsCmd(args);
if (CreateProcessA(0, // No module name (use command line) if (CreateProcessA(0, // No module name (use command line)
(LPSTR)cmd.data(), // Command line (LPSTR)cmd.data(), // Command line
0, // Process handle not inheritable 0, // Process handle not inheritable
0, // Thread handle not inheritable 0, // Thread handle not inheritable
true, // Set handle inheritance to FALSE true, // Set handle inheritance to FALSE
detached ? DETACHED_PROCESS /*CREATE_NEW_CONSOLE*/ : 0, // Creation flags detached ? DETACHED_PROCESS /*CREATE_NEW_CONSOLE*/ : 0, // Creation flags
0, // Use environment 0, // Use environment
wd.isEmpty() ? 0 : wd.data(), // Use working directory wd.isEmpty() ? 0 : wd.data(), // Use working directory
@@ -319,10 +319,17 @@ void PIProcess::startProc(bool detached) {
auto largs = convertToCharArrays(args); auto largs = convertToCharArrays(args);
auto lenv = convertToCharArrays(env); auto lenv = convertToCharArrays(env);
int pid_ = fork(); int pid_ = fork();
if (pid_ < 0) {
piCoutObj << "\"fork\" error: " << errorString();
PRIVATE->closeAllPipes();
delete[] largs;
delete[] lenv;
return;
}
if (!detached) PRIVATE->pid = pid_; if (!detached) PRIVATE->pid = pid_;
if (pid_ == 0) { if (pid_ == 0) {
if (!wd.isEmpty()) { if (!wd.isEmpty()) {
if (!chdir(wd.data())) piCoutObj << "Error while set working directory"; if (chdir(wd.data()) != 0) piCoutObj << "Error while set working directory";
} }
PRIVATE->closePipe(StdIn, PipeWrite); PRIVATE->closePipe(StdIn, PipeWrite);
PRIVATE->closePipe(StdOut, PipeRead); PRIVATE->closePipe(StdOut, PipeRead);
+2 -2
View File
@@ -671,7 +671,7 @@ PIString & PIString::operator+=(const PIConstChars & str) {
if (!str.isEmpty()) { if (!str.isEmpty()) {
size_t os = d.size(); size_t os = d.size();
d.enlarge(str.size()); d.enlarge(str.size());
for (size_t l = 0; l < d.size(); ++l) { for (size_t l = 0; l < str.size(); ++l) {
d[os + l] = str[l]; d[os + l] = str[l];
} }
} }
@@ -1763,7 +1763,7 @@ PIString PIString::toLowerCase() const {
char PIString::toChar() const { char PIString::toChar() const {
char v; char v = 0;
sscanf(dataAscii(), "%c", &v); sscanf(dataAscii(), "%c", &v);
return v; return v;
} }
+4 -2
View File
@@ -1107,9 +1107,11 @@ public:
PIByteArray & append(const PIByteArray & data_) { PIByteArray & append(const PIByteArray & data_) {
#ifdef CC_GCC #ifdef CC_GCC
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstringop-overflow"
# pragma GCC diagnostic ignored "-Warray-bounds" # pragma GCC diagnostic ignored "-Warray-bounds"
# pragma GCC diagnostic ignored "-Wrestrict" # ifndef ANDROID
# pragma GCC diagnostic ignored "-Wstringop-overflow"
# pragma GCC diagnostic ignored "-Wrestrict"
# endif
#endif #endif
const size_t ps = size(); const size_t ps = size();
enlarge(data_.size_s()); enlarge(data_.size_s());
+1 -1
View File
@@ -217,7 +217,7 @@ PIValueTree & PIValueTree::child(const PIStringList & path) {
if (_is_null || path.isEmpty()) return *this; if (_is_null || path.isEmpty()) return *this;
PIValueTree * ret = &child(path[0]); PIValueTree * ret = &child(path[0]);
for (int i = 1; i < path.size_s(); ++i) for (int i = 1; i < path.size_s(); ++i)
ret = &child(path[i]); ret = &(ret->child(path[i]));
return *ret; return *ret;
} }
+193 -11
View File
@@ -20,6 +20,36 @@
#include "pimqttclient.h" #include "pimqttclient.h"
#include "MQTTClient.h" #include "MQTTClient.h"
#include "piliterals_string.h"
#include "piserverendpoint_p.h"
struct PIMQTT::Client::Endpoint: public PIHTTP::ServerEndpoint {
PIMQTT::Client::MessageFunction function;
};
struct TopicUsage {
int counter = 0;
PIMQTT::QoS qos = PIMQTT::QoS::Level1;
};
struct EndpointsStorage {
PIMap<uint, PIMap<PIString, PIVector<PIMQTT::Client::Endpoint>>> prepared; // [priority][topic] -> endpoints
PIMap<PIString, TopicUsage> topics_binded; // [topic] -> TopicUsage
};
PIString topicFromEndpoint(const PIMQTT::Client::Endpoint & e) {
PIStringList ret;
for (const auto & i: e.prepared_path) {
switch (i.type) {
case PIHTTP::ServerEndpoint::PathElement::Type::Fixed: ret << i.source; break;
case PIHTTP::ServerEndpoint::PathElement::Type::AnyMany: ret << "#"_a; break;
default: ret << "+"_a; break;
}
}
return ret.join('/');
}
STATIC_INITIALIZER_BEGIN STATIC_INITIALIZER_BEGIN
@@ -30,7 +60,9 @@ STATIC_INITIALIZER_END
PRIVATE_DEFINITION_START(PIMQTT::Client) PRIVATE_DEFINITION_START(PIMQTT::Client)
MQTTClient client = nullptr; MQTTClient client = nullptr;
bool connected = false; std::atomic<bool> connected{false};
PIProtectedVariable<EndpointsStorage> endpoints;
static void connectionLost_callback(void * context, char *) { static void connectionLost_callback(void * context, char *) {
((PIMQTT::Client *)context)->mqtt_connectionLost(); ((PIMQTT::Client *)context)->mqtt_connectionLost();
@@ -88,15 +120,23 @@ void PIMQTT::Client::disconnect() {
} }
void PIMQTT::Client::subscribe(const PIString & topic, QoS qos) { void PIMQTT::Client::subscribe(const PIString & topic, MessageFunction functor, QoS qos) {
if (is_destoying) return; if (is_destoying) return;
worker->enqueueTask([this, topic, qos] { subscribeInternal({topic, qos}); }); Subscribe sub{topic, functor, qos};
// piCout << "subscribe" << topic;
PIString mqtt_topic = registerSubscribe(sub);
if (mqtt_topic.isEmpty()) return;
sub.topic = mqtt_topic;
worker->enqueueTask([this, sub] { subscribeInternal(sub); });
} }
void PIMQTT::Client::unsubscribe(const PIString & topic) { void PIMQTT::Client::unsubscribe(const PIString & topic) {
if (is_destoying) return; if (is_destoying) return;
worker->enqueueTask([this, topic] { unsubscribeInternal(topic); }); // piCout << "unsubscribe" << topic;
PIString mqtt_topic = unregisterSubscribe(topic);
if (mqtt_topic.isEmpty()) return;
worker->enqueueTask([this, mqtt_topic] { unsubscribeInternal(mqtt_topic); });
} }
@@ -115,8 +155,27 @@ void PIMQTT::Client::publish(const MessageConst & msg) {
} }
PIStringList PIMQTT::Client::usedTopics() const {
return PRIVATE->endpoints.getRef()->topics_binded.keys();
}
void PIMQTT::Client::unsubscribeAll() {
{
auto ref = PRIVATE->endpoints.getRef();
auto tit = ref->topics_binded.makeIterator();
while (tit.next()) {
if (tit.value().counter <= 0) continue;
PIString mqtt_topic = tit.key();
worker->enqueueTask([this, mqtt_topic] { unsubscribeInternal(mqtt_topic); });
}
}
unregisterAll();
}
void PIMQTT::Client::mqtt_connectionLost() { void PIMQTT::Client::mqtt_connectionLost() {
piCoutObj << "mqtt_connectionLost"; // piCoutObj << "mqtt_connectionLost";
PRIVATE->connected = false; PRIVATE->connected = false;
changeStatus(Idle); changeStatus(Idle);
disconnected(Error::ServerUnavailable); disconnected(Error::ServerUnavailable);
@@ -126,9 +185,114 @@ void PIMQTT::Client::mqtt_connectionLost() {
void PIMQTT::Client::mqtt_deliveryComplete(int token) {} void PIMQTT::Client::mqtt_deliveryComplete(int token) {}
void PIMQTT::Client::mqtt_messageArrived(const MessageConst & msg) { void PIMQTT::Client::mqtt_messageArrived(MessageMutable & msg) {
piCoutObj << "mqtt_messageArrived"; PIStringList in_path = msg.topicList();
received(msg); PIMQTT::Client::MessageFunction function;
// piCoutObj << "mqtt_messageArrived";
{
bool found = false;
auto ref = PRIVATE->endpoints.getRef();
auto pit = ref->prepared.makeReverseIterator();
while (pit.next()) { // by priority
auto tit = pit.value().makeIterator();
while (tit.next()) { // by MQTT topic
for (const auto & ep: tit.value()) {
PIMap<PIString, PIString> ext_args;
if (ep.match(in_path, ext_args)) {
msg.pathArguments() = ext_args;
function = ep.function;
found = true;
break;
}
}
if (found) break;
}
if (found) break;
}
}
if (function)
function(msg);
else
receivedUnhandled(msg);
}
PIString PIMQTT::Client::registerSubscribe(const Subscribe & sub) {
Endpoint ep;
ep.create(convertTopic2HTTP(sub.topic));
ep.function = sub.functor;
PIString topic = topicFromEndpoint(ep);
if (topic.isEmpty()) {
piCoutObj << "Warning: subscribe to empty topic, ignore";
return {};
}
// piCout << sub.topic << "->" << topic << ep.priority;
bool is_new_topic = false;
auto ref = PRIVATE->endpoints.getRef();
auto & eps_by_topic(ref->prepared[ep.priority][topic]);
for (const auto & i: eps_by_topic) {
if (i.path == ep.path) {
piCoutObj << "Warning: subscribe duplicate path, ignore";
return {};
}
}
eps_by_topic << ep;
auto & usage(ref->topics_binded[topic]);
is_new_topic = usage.counter == 0;
++usage.counter;
if (!is_new_topic) return {};
usage.qos = sub.qos;
return topic;
}
PIString PIMQTT::Client::unregisterSubscribe(const PIString & mqtt_topic) {
Endpoint ep;
ep.create(convertTopic2HTTP(mqtt_topic));
PIString topic = topicFromEndpoint(ep);
if (topic.isEmpty()) {
piCoutObj << "Warning: unsubscribe from empty topic, ignore";
return {};
}
// piCout << mqtt_topic << "->" << topic << ep.priority;
auto ref = PRIVATE->endpoints.getRef();
auto pit = ref->prepared.makeIterator();
while (pit.next()) { // by priority
auto tit = pit.value().makeIterator();
while (tit.next()) { // by MQTT topic
auto & eps(tit.value());
for (int i = 0; i < eps.size_s(); ++i) {
if (eps[i].path == ep.path) {
eps.remove(i);
auto & usage(ref->topics_binded[tit.key()]);
--usage.counter;
PIString ret;
if (usage.counter <= 0) {
ret = tit.key();
ref->topics_binded.remove(tit.key());
}
if (eps.isEmpty()) {
// piCout << "remove topics" << tit.key();
pit.value().remove(tit.key());
}
return ret;
}
}
}
}
piCoutObj << "Warning: unsubscribe from" << mqtt_topic << ", topic not found";
return {};
}
void PIMQTT::Client::unregisterAll() {
auto ref = PRIVATE->endpoints.getRef();
ref->prepared.clear();
ref->topics_binded.clear();
} }
@@ -160,6 +324,12 @@ void PIMQTT::Client::connectInternal(const ConnectInfo & ci) {
return; return;
} }
PRIVATE->connected = true; PRIVATE->connected = true;
PIMap<PIString, TopicUsage> topics_binded;
{ topics_binded = PRIVATE->endpoints.getRef()->topics_binded; }
auto it = topics_binded.makeIterator();
while (it.next()) {
if (it.value().counter > 0) subscribeInternal({it.key(), nullptr, it.value().qos});
}
changeStatus(Connected); changeStatus(Connected);
connected(); connected();
} }
@@ -189,18 +359,21 @@ void PIMQTT::Client::publishInternal(const MessageConst & m) {
void PIMQTT::Client::subscribeInternal(const Subscribe & sub) { void PIMQTT::Client::subscribeInternal(const Subscribe & sub) {
if (!PRIVATE->client) return; if (!PRIVATE->client) return;
// piCout << "subscribeInternal" << sub.topic;
int ret = MQTTClient_subscribe(PRIVATE->client, sub.topic.dataUTF8(), static_cast<int>(sub.qos)); int ret = MQTTClient_subscribe(PRIVATE->client, sub.topic.dataUTF8(), static_cast<int>(sub.qos));
if (ret != MQTTCLIENT_SUCCESS) { if (ret != MQTTCLIENT_SUCCESS) {
piCoutObj << "Failed to subscribe" << sub.topic << ", code" << ret; piCoutObj << "Failed to subscribe" << sub.topic << ", code" << ret;
return;
} }
} }
void PIMQTT::Client::unsubscribeInternal(const PIString & topic) { void PIMQTT::Client::unsubscribeInternal(const PIString & mqtt_topic) {
if (!PRIVATE->client) return; if (!PRIVATE->client) return;
int ret = MQTTClient_unsubscribe(PRIVATE->client, topic.dataUTF8()); // piCout << "unsubscribeInternal" << mqtt_topic;
int ret = MQTTClient_unsubscribe(PRIVATE->client, mqtt_topic.dataUTF8());
if (ret != MQTTCLIENT_SUCCESS) { if (ret != MQTTCLIENT_SUCCESS) {
piCoutObj << "Failed to unsubscribe" << topic << ", code" << ret; piCoutObj << "Failed to unsubscribe" << mqtt_topic << ", code" << ret;
} }
} }
@@ -217,3 +390,12 @@ void PIMQTT::Client::destroy() {
void PIMQTT::Client::changeStatus(Status s) { void PIMQTT::Client::changeStatus(Status s) {
m_status = s; m_status = s;
} }
PIString PIMQTT::Client::convertTopic2MQTT(const PIString & topic) {
return topic.replacedAll("**", '#').replacedAll('*', '+');
}
PIString PIMQTT::Client::convertTopic2HTTP(const PIString & topic) {
return topic.replacedAll('#', "**").replacedAll('+', '*');
}
+74 -135
View File
@@ -10,161 +10,100 @@
using namespace PICoutManipulators; using namespace PICoutManipulators;
using namespace PIHTTP; using namespace PIHTTP;
using namespace PIUnits::Class;
int rcnt = 0, scnt = 0;
inline PIByteArray SMBusTypeInfo_genHash(PIString n) {
PICrypt c;
return piSerialize(c.shorthash(n.removeAll(" "), PIString("SMBusDataHashKey").toByteArray()));
}
PIKbdListener kbd; PIKbdListener kbd;
MessageMutable createMessage(Code c, const char * path, const MessageConst & msg) {
piCout << "path" << path << "args" << msg.pathArguments();
return MessageMutable().setCode(c);
};
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
// piCout << "start ...";
// PIHTTPServer server;
// server.registerUnhandled([](const MessageConst & msg) { return createMessage(Code::BadRequest, "unhadled", msg); });
// server.registerPath("api/v1/status", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/status", msg);
// });
// server.registerPath("api/v1/plugins", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/plugins", msg);
// });
// server.registerPath("api/v1/task-status", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/task-status", msg);
// });
// server.registerPath("api/v1/task/{taskID}/status", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/task/{taskID}/status", msg);
// });
// server.registerPath("api/v1/bort/list", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/bort/list", msg);
// });
// server.registerPath("api/v1/all", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/all", msg);
// });
// server.registerPath("api/v1/all/bort{A}/f", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/all/*/f", msg);
// });
// server.registerPath("api/v1/all2/**", Method::Get, [](const MessageConst & msg) {
// return createMessage(Code::Accepted, "api/v1/all2/**", msg);
// });
// server.listenAll(12345);
// kbd.enableExitCapture('Q');
// WAIT_FOR_EXIT
// piCout << "exiting ...";
// server.stop();
// return 0;
// PISystemMonitor mon;
// mon.startOnSelf();
// PISystemMonitor::totalRAM();
// 2_s .sleep();
// return 0;
PIMQTT::Client cl; PIMQTT::Client cl;
cl.setConnectTimeout(2_s); cl.setConnectTimeout(2_s);
cl.subscribe("api/v1/all/bort{A}/f",
[](const PIMQTT::MessageConst & msg) { piCout << "1" << msg.topicList() << msg.pathArguments() << msg.body().size(); });
cl.subscribe("api/v1/all/task{T}/f",
[](const PIMQTT::MessageConst & msg) { piCout << "2" << msg.topicList() << msg.pathArguments() << msg.body().size(); });
cl.subscribe("api/v1/all/*/f",
[](const PIMQTT::MessageConst & msg) { piCout << "3" << msg.topicList() << msg.pathArguments() << msg.body().size(); });
cl.subscribe("api/v1/all2/**",
[](const PIMQTT::MessageConst & msg) { piCout << "4" << msg.topicList() << msg.pathArguments() << msg.body().size(); });
CONNECTL(&cl, connected, [&cl] { CONNECTL(&cl, connected, [&cl] {
piCout << "connected"; piCout << "connected";
cl.subscribe("/zigbee2mqtt"); // cl.subscribe("api/v1/plugins");
cl.subscribe("/zigbee2mqtt/+"); // cl.subscribe("api/v1/task-status");
cl.unsubscribe("/zigbee2mqtt"); // cl.subscribe("api/v1/*/{taskID}/status");
cl.publish("/zigbee2mqtt/abc", "hello from PIP"_a.toAscii()); // cl.subscribe("api/v1/bort/list");
// cl.subscribe("api/v1/all");
// cl.subscribe("/zigbee2mqtt");
// cl.subscribe("/zigbee2mqtt/+/status/");
// cl.subscribe("/zigbee2mqtt/*/status/");
// cl.subscribe("test/#");
// cl.subscribe("#");
// cl.unsubscribe("/zigbee2mqtt");
// cl.unsubscribe("api/v1/all/bort{A}/f");
// cl.unsubscribe("api/v1/all/*/f");
// cl.publish("/zigbee2mqtt/abc", "hello from PIP"_a.toAscii());
}); });
CONNECTL(&cl, disconnected, [&cl](PIMQTT::Error code) { CONNECTL(&cl, disconnected, [&cl](PIMQTT::Error code) {
piCout << "disconnected code" << (int)code; piCout << "disconnected code" << (int)code;
cl.connect("localhost", "PIP"); cl.connect("localhost", "PIP");
}); });
CONNECTL(&cl, received, [](const PIMQTT::MessageConst & message) { CONNECTL(&cl, receivedUnhandled, [](const PIMQTT::MessageConst & message) {
piCout << "received" << message.topic() << message.payload().size(); piCout << "receivedUnhandled" << message.topic() << message.pathArguments() << message.payload().size();
}); });
cl.connect("localhost", "PIP"); cl.connect("localhost", "PIP");
piSleep(6.);
cl.unsubscribeAll();
kbd.enableExitCapture('Q'); kbd.enableExitCapture('Q');
WAIT_FOR_EXIT WAIT_FOR_EXIT
piCout << "exiting ..."; piCout << "exiting ...";
return 0;
PICrypt _crypt;
// auto ba = PIFile::readAll("logo.png");
PIString str = "hello!"_a;
PIByteArray ba = str.toAscii();
PIByteArray key = PIString("SMBusDataHashKey").toByteArray();
const int times = 1000000;
PITimeMeasurer tm;
PISystemTime el;
tm.reset();
piForTimes(times) {
PIDigest::calculateWithKey(ba, key, PIDigest::Type::SipHash_2_4_128);
}
el = tm.elapsed();
piCout << "PIDigest" << el.toString();
tm.reset();
piForTimes(times) {
_crypt.shorthash(str, key);
}
el = tm.elapsed();
piCout << " sodium" << el.toString();
tm.reset();
piForTimes(times) {
PIDigest::calculateWithKey(ba, key, PIDigest::Type::BLAKE2b_128);
}
el = tm.elapsed();
piCout << " blake" << el.toString();
return 0;
PIEthernet *eth_r, *eth_s;
eth_r = PIIODevice::createFromFullPath("eth://udp: 192.168.1.25 :10000")->cast<PIEthernet>();
eth_s = PIIODevice::createFromFullPath("eth://udp: : : 192.168.1.25:10000")->cast<PIEthernet>();
eth_r->setReadBufferSize(1_MiB);
CONNECTL(eth_r, threadedReadEvent, [](const uchar * readed, ssize_t size) {
// piCout << "rec";
piMSleep(1);
++rcnt;
});
eth_r->startThreadedRead();
PIByteArray _ba(1400);
for (int i = 0; i < 100; ++i) {
eth_s->write(_ba);
++scnt;
}
0.2_s .sleep();
piCout << "snd" << scnt;
piCout << "rec" << rcnt;
piDeleteSafety(eth_r);
piDeleteSafety(eth_s);
return 0;
PITranslator::loadLang("ru");
/*auto ucl = PIUnits::allClasses();
for (auto c: ucl) {
piCout << (c->className() + ":");
for (auto t: c->allTypes()) {
piCout << " " << c->name(t) << "->" << c->unit(t);
}
}*/
// PIUnits::Value(1);
// piCout << PIUnits::name(PIUnits::Class::Information::Bit);
// piCout << PIUnits::name(PIUnits::Class::Information::Byte);
// piCout << PIUnits::name(PIUnits::Class::Information::_LastType);
// piCout << PIUnits::name((int)PIUnits::Class::Angle::Degree);
// piCout << PIUnits::unit(PIUnits::Class::Information::Bit);
// piCout << PIUnits::unit(PIUnits::Class::Information::Byte);
// piCout << PIUnits::unit(PIUnits::Class::Information::_LastType);
// piCout << PIUnits::unit((int)PIUnits::Class::Angle::Degree);
// for (int i = -10; i < 10; ++i)
// piCout << PIUnits::Value(pow10(i * 0.99), PIUnits::Class::Distance::Meter).toString();
auto v = PIUnits::Value(M_PI, Angle::Radian);
piCout << v << "=" << v.converted(Angle::Degree);
v = PIUnits::Value(45, Angle::Degree);
piCout << v << "=" << v.converted(Angle::Radian);
piCout << PIUnits::Value(5E-5, Time::Second);
piCout << PIUnits::Value(3E-3, Time::Second);
piCout << PIUnits::Value(0.8, Time::Second);
piCout << PIUnits::Value(1.2, Time::Second);
piCout << PIUnits::Value(1001, Time::Second);
piCout << PIUnits::Value(1000001, Time::Second);
piCout << PIUnits::Value(1_KB, Information::Byte);
piCout << PIUnits::Value(1_MB, Information::Byte);
piCout << PIUnits::Value(1_MiB, Information::Byte);
piCout << PIUnits::Value(1_MB, Information::Byte).converted(Information::Bit);
piCout << PIUnits::Value(1_MiB, Information::Byte).converted(Information::Bit);
piCout << PIUnits::Value(0., Temperature::Celsius).converted(Temperature::Kelvin);
piCout << PIUnits::Value(0., Temperature::Celsius).converted(Temperature::Fahrenheit);
piCout << PIUnits::Value(100., Temperature::Celsius).converted(Temperature::Fahrenheit);
piCout << PIUnits::Value(1., Pressure::Atmosphere).converted(Pressure::Pascal);
piCout << PIUnits::Value(1., Pressure::Atmosphere).converted(Pressure::MillimetreOfMercury);
piCout << PIUnits::Value(766., Pressure::MillimetreOfMercury).converted(Pressure::Atmosphere);
piCout << PIUnits::Value(5E-5, Time::Second).converted(Time::Hertz);
piCout << PIUnits::Value(3E-3, Time::Second).converted(Time::Hertz);
piCout << PIUnits::Value(0.8, Time::Second).converted(Time::Hertz);
piCout << PIUnits::Value(1.2, Time::Second).converted(Time::Hertz);
piCout << PIUnits::Value(1001, Time::Second).converted(Time::Hertz);
piCout << PIUnits::Value(1000001, Time::Second).converted(Time::Hertz);
// piCout << PIUnits::Value(0.2, Time::Second).converted(Time::Hertz);
// piCout << PIUnits::Value(5E-5, Time::Second).converted(Time::Hertz);
return 0;
} }
+16
View File
@@ -24,6 +24,10 @@
void writeGetterTypeMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) { void writeGetterTypeMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
writeGetterTypeMembers(rt, p, var_prefix);
}
PISet<int> used_id; PISet<int> used_id;
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
if (m.is_type_ptr || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue;
@@ -43,6 +47,10 @@ void writeGetterTypeMembers(Runtime & rt, const PICodeParser::Entity * e, PIStri
void writeGetterValueMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) { void writeGetterValueMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
writeGetterValueMembers(rt, p, var_prefix);
}
PISet<int> used_id; PISet<int> used_id;
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
if (m.is_type_ptr || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue;
@@ -65,6 +73,10 @@ void writeGetterValueMembers(Runtime & rt, const PICodeParser::Entity * e, PIStr
void writeGetterOffsetMembers(Runtime & rt, const PICodeParser::Entity * e, PIString entity_name, PIString var_prefix) { void writeGetterOffsetMembers(Runtime & rt, const PICodeParser::Entity * e, PIString entity_name, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
writeGetterOffsetMembers(rt, p, entity_name, var_prefix);
}
PISet<int> used_id; PISet<int> used_id;
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
if (m.is_type_ptr || !m.dims.isEmpty() || m.isBitfield() || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || !m.dims.isEmpty() || m.isBitfield() || (m.visibility != PICodeParser::Public)) continue;
@@ -117,5 +129,9 @@ bool needClassGetter(const PICodeParser::Entity * e) {
if (m.attributes[PICodeParser::Static]) continue; if (m.attributes[PICodeParser::Static]) continue;
return true; return true;
} }
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
if (needClassGetter(p)) return true;
}
return false; return false;
} }
+12 -8
View File
@@ -24,6 +24,10 @@
bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) { bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
writeClassJSONMembersOut(rt, p, var_prefix);
}
PIVector<PICodeParser::Member> ml; PIVector<PICodeParser::Member> ml;
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
@@ -57,16 +61,16 @@ bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e, PISt
if (is_union) break; if (is_union) break;
} }
if (is_union) return true; if (is_union) return true;
/*for (const PICodeParser::Entity * ce: e->children) {
if (!ce->is_anonymous) continue;
if (!writeClassJSONMembersOut(rt, ce)) return false;
}*/
return true; return true;
} }
bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) { bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
writeClassJSONMembersIn(rt, p, var_prefix);
}
PIVector<PICodeParser::Member> ml; PIVector<PICodeParser::Member> ml;
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
@@ -105,10 +109,6 @@ bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e, PIStr
if (is_union) break; if (is_union) break;
} }
if (is_union) return true; if (is_union) return true;
/*for (const PICodeParser::Entity * ce: e->children) {
if (!ce->is_anonymous) continue;
if (!writeClassJSONMembersIn(rt, ce)) return false;
}*/
return true; return true;
} }
@@ -121,6 +121,10 @@ bool needClassJSON(const PICodeParser::Entity * e) {
if (m.meta.value("id") == "-") continue; if (m.meta.value("id") == "-") continue;
return true; return true;
} }
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
if (needClassJSON(p)) return true;
}
return false; return false;
} }
+4
View File
@@ -22,6 +22,10 @@
void writeClassInfoMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) { void writeClassInfoMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
writeClassInfoMembers(rt, p, var_prefix);
}
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
auto type = findEntity(rt, m.type); auto type = findEntity(rt, m.type);
if (type) { if (type) {
+12
View File
@@ -24,6 +24,10 @@
bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix) { bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
if (!writeClassStreamMembersOut(rt, p, cnt, simple, var_prefix)) return false;
}
PIVector<PICodeParser::Member> ml; PIVector<PICodeParser::Member> ml;
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
@@ -83,6 +87,10 @@ bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, in
bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix) { bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix) {
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += "."; if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
if (!writeClassStreamMembersIn(rt, p, cnt, simple, var_prefix)) return false;
}
PIVector<PICodeParser::Member> ml; PIVector<PICodeParser::Member> ml;
for (const PICodeParser::Member & m: e->members) { for (const PICodeParser::Member & m: e->members) {
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
@@ -166,6 +174,10 @@ bool needClassStream(const PICodeParser::Entity * e) {
if (m.meta.value("id") == "-") continue; if (m.meta.value("id") == "-") continue;
return true; return true;
} }
for (const PICodeParser::Entity * p: e->parents) {
if (p->is_anonymous) continue;
if (needClassStream(p)) return true;
}
return false; return false;
} }