diff --git a/CMakeLists.txt b/CMakeLists.txt
index 61a32303..b05912a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -480,7 +480,7 @@ if (NOT CROSSTOOLS)
#target_link_libraries(pip_plugin pip)
add_executable(pip_test "main.cpp")
- target_link_libraries(pip_test pip)
+ target_link_libraries(pip_test pip pip_io_utils)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
diff --git a/libs/io_utils/pipackedtcp.cpp b/libs/io_utils/pipackedtcp.cpp
new file mode 100644
index 00000000..d9efac7b
--- /dev/null
+++ b/libs/io_utils/pipackedtcp.cpp
@@ -0,0 +1,199 @@
+/*
+ PIP - Platform Independent Primitives
+ PIPackedTCP
+ Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 .
+*/
+
+#include "pipackedtcp.h"
+
+#include "piethernet.h"
+#include "piliterals.h"
+
+
+/** \class PIPackedTCP pipackedtcp.h
+ * \brief
+ * TCP packed channel
+ *
+ * \details
+ * \section PITCP_sec0 Synopsis
+ * %PIEthernet designed to work with IPv4 network via two protocols:
+ * UDP and TCP. This class allow you send and receive packets to/from
+ * another computer through network. Also it supports broadcast and
+ * multicast extensions.
+ *
+ * */
+
+
+PIPackedTCP::PIPackedTCP(Role role, const PINetworkAddress & addr): m_role(role) {
+ setMode(PIIODevice::ReadWrite);
+ packer.setCryptEnabled(false);
+ CONNECTL(&packer, packetReceiveEvent, [this](PIByteArray & data) {
+ PIMutexLocker ml(rec_mutex);
+ rec_queue.enqueue(data);
+ });
+ init();
+ setAddress(addr);
+}
+
+
+PIPackedTCP::~PIPackedTCP() {
+ stopAndWait();
+ if (client) client->stopAndWait();
+ if (eth) eth->stopAndWait();
+ piDeleteSafety(eth);
+}
+
+
+void PIPackedTCP::setAddress(const PINetworkAddress & addr) {
+ m_addr = addr;
+ setPath(m_addr.toString());
+}
+
+
+bool PIPackedTCP::isConnected() const {
+ if (m_role == Client) {
+ return eth->isConnected();
+ } else {
+ if (client) return client->isConnected();
+ }
+ return false;
+}
+
+
+bool PIPackedTCP::isConnecting() const {
+ if (m_role == Client) {
+ return eth->isConnecting();
+ } else {
+ if (client) return client->isConnecting();
+ }
+ return false;
+}
+
+
+void PIPackedTCP::init() {
+ if (client) client->stopAndWait();
+ if (eth) eth->stopAndWait();
+ piDeleteSafety(eth);
+ eth = new PIEthernet(m_role == Client ? PIEthernet::TCP_Client : PIEthernet::TCP_Server);
+ if (m_role == Client) {
+ eth->setReopenTimeout(100_ms);
+ packer.assignDevice(eth);
+ CONNECTL(eth, connected, [this]() {
+ packer.clear();
+ connected();
+ });
+ CONNECTL(eth, disconnected, [this](bool) {
+ packer.clear();
+ eth->connect(path(), true);
+ disconnected();
+ });
+ } else {
+ CONNECTL(eth, newConnection, [this](PIEthernet * c) {
+ if (client) client->stopAndWait();
+ piDeleteSafety(client);
+ client = c;
+ // piCout << "Server connected" << client;
+ packer.assignDevice(client);
+ CONNECTL(client, disconnected, [this](bool) {
+ packer.assignDevice(nullptr);
+ packer.clear();
+ disconnected();
+ });
+ client->startThreadedRead();
+ connected();
+ });
+ }
+}
+
+
+PIIODevice::DeviceInfoFlags PIPackedTCP::deviceInfoFlags() const {
+ return PIIODevice::Reliable;
+}
+
+
+PIString PIPackedTCP::constructFullPathDevice() const {
+ return PIString(m_role == Client ? "client" : "server") + ":" + path();
+}
+
+
+void PIPackedTCP::configureFromFullPathDevice(const PIString & full_path) {
+ PIStringList pl = full_path.split(":");
+ if (pl.size() >= 1) {
+ PIString p = pl[0].toLowerCase().left(1);
+ if (p == "c") m_role = Client;
+ if (p == "s") m_role = Server;
+ init();
+ }
+ PINetworkAddress addr("0.0.0.0", 13362);
+ if (pl.size() >= 2) {
+ if (pl[1].isNotEmpty()) addr.setIP(pl[1]);
+ }
+ if (pl.size() >= 3) {
+ if (pl[2].isNotEmpty()) addr.setPort(pl[2].toInt());
+ }
+ setAddress(addr);
+}
+
+
+ssize_t PIPackedTCP::readDevice(void * read_to, ssize_t max_size) {
+ PIMutexLocker ml(rec_mutex);
+ if (rec_queue.isNotEmpty()) {
+ auto d = rec_queue.dequeue();
+ auto sz = piMin(max_size, d.size_s());
+ if (read_to) memcpy(read_to, d.data(), sz);
+ return sz;
+ }
+ return 0;
+}
+
+
+ssize_t PIPackedTCP::writeDevice(const void * data, ssize_t max_size) {
+ if (!isConnected()) return 0;
+ packer.send(PIByteArray(data, max_size));
+ // piCout << m_role << "write" << eth;
+ return max_size;
+ /*if (m_role == Client) {
+ return eth->write(data, max_size);
+ } else {
+ if (client) return client->write(data, max_size);
+ }*/
+}
+
+
+bool PIPackedTCP::openDevice() {
+ if (m_role == Client) {
+ if (eth->isConnected()) return true;
+ if (eth->isConnecting()) return false;
+ packer.clear();
+ bool ret = eth->connect(path(), false);
+ eth->startThreadedRead();
+ return ret;
+ } else {
+ return eth->listen(path(), false);
+ }
+ return false;
+}
+
+
+bool PIPackedTCP::closeDevice() {
+ if (client) {
+ client->close();
+ client->stopAndWait();
+ piDeleteSafety(client);
+ packer.assignDevice(nullptr);
+ }
+ return eth->close();
+}
diff --git a/libs/main/io_devices/piiodevice.cpp b/libs/main/io_devices/piiodevice.cpp
index 7c06b4a6..654b1a10 100644
--- a/libs/main/io_devices/piiodevice.cpp
+++ b/libs/main/io_devices/piiodevice.cpp
@@ -569,15 +569,14 @@ PIStringList PIIODevice::availableClasses() {
void PIIODevice::registerDevice(PIConstChars prefix, PIConstChars classname, PIIODevice * (*fabric)()) {
+ // printf("registerDevice %s %s %d\n", prefix.data(), classname.data(), fabrics().size());
if (prefix.isEmpty()) return;
- // printf("registerDevice %s %d %d\n", prefix, p.isEmpty(), fabrics().size());
- if (!fabrics().contains(prefix)) {
- FabricInfo fi;
- fi.prefix = prefix;
- fi.classname = classname;
- fi.fabricator = fabric;
- fabrics()[prefix] = fi;
- }
+ if (fabrics().contains(prefix)) return;
+ FabricInfo fi;
+ fi.prefix = prefix;
+ fi.classname = classname;
+ fi.fabricator = fabric;
+ fabrics()[prefix] = fi;
}
diff --git a/libs/main/io_utils/piioutilsmodule.h b/libs/main/io_utils/piioutilsmodule.h
index 7baee2d3..462e09e8 100644
--- a/libs/main/io_utils/piioutilsmodule.h
+++ b/libs/main/io_utils/piioutilsmodule.h
@@ -57,6 +57,7 @@
#include "pidatatransfer.h"
#include "pidiagnostics.h"
#include "pifiletransfer.h"
+#include "pipackedtcp.h"
#include "pipacketextractor.h"
#include "piparsehelper.h"
diff --git a/libs/main/io_utils/pipackedtcp.h b/libs/main/io_utils/pipackedtcp.h
new file mode 100644
index 00000000..d5d66d3a
--- /dev/null
+++ b/libs/main/io_utils/pipackedtcp.h
@@ -0,0 +1,90 @@
+/*! \file pipackedtcp.h
+ * \ingroup IO-Utils
+ * \~\brief
+ * \~english Ethernet device
+ * \~russian Устройство Ethernet
+ */
+/*
+ PIP - Platform Independent Primitives
+ Ethernet, UDP/TCP Broadcast/Multicast
+ Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 .
+*/
+
+#ifndef pipackedtcp_H
+#define pipackedtcp_H
+
+#include "piiodevice.h"
+#include "pinetworkaddress.h"
+#include "pip_io_utils_export.h"
+#include "pistreampacker.h"
+
+class PIEthernet;
+
+
+class PIP_IO_UTILS_EXPORT PIPackedTCP: public PIIODevice {
+ PIIODEVICE(PIPackedTCP, "ptcp");
+
+public:
+ //! \brief Role of %PIPackedTCP
+ enum Role {
+ Client /** TCP client */,
+ Server /** TCP server for one client */
+ };
+
+ //! Contructs %PIPackedTCP with "role" and "addr" address
+ explicit PIPackedTCP(Role role = Client, const PINetworkAddress & addr = {});
+
+ virtual ~PIPackedTCP();
+
+ //! Set server address for Server role or connect address for Client
+ void setAddress(const PINetworkAddress & addr);
+
+ bool isConnected() const;
+ bool isConnecting() const;
+
+ //! Returns read address in format "i.i.i.i:p"
+ PINetworkAddress address() const { return m_addr; }
+
+ //! Returns %PIEthernet type
+ Role role() const { return m_role; }
+
+ EVENT0(connected);
+ EVENT0(disconnected);
+
+protected:
+ void init();
+
+ DeviceInfoFlags deviceInfoFlags() const override;
+ PIString constructFullPathDevice() const override;
+ void configureFromFullPathDevice(const PIString & full_path) override;
+ ssize_t readDevice(void * read_to, ssize_t max_size) override;
+ ssize_t writeDevice(const void * data, ssize_t max_size) override;
+ bool openDevice() override;
+ bool closeDevice() override;
+
+ mutable PINetworkAddress m_addr;
+ Role m_role = Client;
+ PIEthernet *eth = nullptr, *client = nullptr;
+ PIStreamPacker packer;
+ PIMutex rec_mutex;
+ PIQueue rec_queue;
+
+private:
+};
+
+REGISTER_DEVICE(PIPackedTCP)
+
+#endif
diff --git a/main.cpp b/main.cpp
index 8c575fc2..9c5d61ba 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,7 +2,6 @@
#include "picodeparser.h"
#include "piiostream.h"
#include "pijson.h"
-#include "piliterals_time.h"
#include "pimathbase.h"
#include "pip.h"
#include "pivaluetree_conversions.h"
@@ -17,7 +16,83 @@ enum MyEvent {
meIntString,
};
+PITimeMeasurer tm;
+std::atomic_int cnt = {0};
+void tfunc(int delim) {
+ // piCout << "tick with delimiter" << delim;
+ ++cnt;
+};
+void tfunc4(int delim) {
+ piCout << "tick4 with delimiter" << delim;
+};
+
+
int main(int argc, char * argv[]) {
+ PIPackedTCP * tcp_s =
+ PIIODevice::createFromFullPath("ptcp://s::8000")->cast(); // new PIPackedTCP(PIPackedTCP::Server, {"0.0.0.0:8000"});
+ PIPackedTCP * tcp_c = PIIODevice::createFromFullPath("ptcp://c:127.0.0.1:8000")
+ ->cast(); // new PIPackedTCP(PIPackedTCP::Client, {"127.0.0.1:8000"});
+ piCout << tcp_s << tcp_c;
+ // CONNECTL(&tcp_s, opened, []() { piCout << "Srv opened"; });
+ // CONNECTL(&tcp_c, opened, []() { piCout << "Cli opened"; });
+ // CONNECTL(&tcp_s, closed, []() { piCout << "Srv closed"; });
+ // CONNECTL(&tcp_c, closed, []() { piCout << "Cli closed"; });
+ CONNECTL(tcp_s, connected, []() { piCout << "Srv conn"; });
+ CONNECTL(tcp_c, connected, []() { piCout << "Cli conn"; });
+ CONNECTL(tcp_s, disconnected, []() { piCout << "Srv disconn"; });
+ CONNECTL(tcp_c, disconnected, []() { piCout << "Cli disconn"; });
+ CONNECTL(tcp_s, threadedReadEvent, [](const uchar * readed, ssize_t size) {
+ PIByteArray d(readed, size);
+ piCout << "Srv readed" << d;
+ });
+ CONNECTL(tcp_c, threadedReadEvent, [](const uchar * readed, ssize_t size) {
+ PIByteArray d(readed, size);
+ piCout << "Cli readed" << d;
+ });
+ // tcp_s->open();
+ // tcp_c->open();
+ tcp_s->startThreadedRead();
+ tcp_c->startThreadedRead();
+ piForTimes(5) {
+ piCout << "\n1";
+ piMSleep(200);
+ piCout << "2";
+ // tcp_c->close();
+ piCout << "2+";
+ // tcp_s->close();
+ piCout << "3";
+ // tcp_c->open();
+ piCout << "3+";
+ // tcp_s->open();
+ piCout << "4";
+ piMSleep(500);
+ // piCout << "5";
+ tcp_c->write("1234567890"_a.toByteArray());
+ // piCout << "6";
+ tcp_s->write("1234567890"_a.toByteArray());
+ // piCout << "7";
+ piMSleep(200);
+ }
+ // piCout << &tcp_s;
+ // piCout << tcp_s->path();
+ // piCout << tcp_s->constructFullPath();
+ delete tcp_s;
+ delete tcp_c;
+ return 0;
+ /*PITimer timer(tfunc);
+ // timer.addDelimiter(2);
+ timer.addDelimiter(40, tfunc4);
+
+ tm.reset();
+ timer.start(0.5_Hz);
+ piMSleep(2200);
+ piCout << tm.elapsed_m() << cnt;
+
+ timer.stop();
+ timer.waitForFinish();
+ return 0;*/
+
+
bool posted;
PIStateMachine * root = new PIStateMachine("Machine");
root->addOnFinish([] { piCout << "finish"; });
@@ -49,9 +124,10 @@ int main(int argc, char * argv[]) {
s2->setInitialState(s21);
s21->setInitialState(s213);
- s213->addTransition(s13, meVoid)->addAction([] { piCout << "action transition s21 -> s22"; });
- s3->addTransition(s212, meVoid)->addAction([] { piCout << "action transition s1 -> s213"; });
- // s2->addTransition(s3, meInt)->addGuard([](int i) { return i == 1; });
+ // s213->addTransition(s13, meVoid)->addAction([] { piCout << "action transition s21 -> s22"; });
+ // s3->addTransition(s212, meVoid)->addAction([] { piCout << "action transition s1 -> s213"; });
+ s2->addTransition(s3, meVoid);
+ s2->addTimeoutTransition(s3, .5_s);
// s3->addTransition(s1, meIntString)->addGuard([](int i, PIString str) { return i == 2 && str == "hello"; });
root->start();
@@ -59,10 +135,11 @@ int main(int argc, char * argv[]) {
piCout << "active atomics" << root->activeAtomics();
root->print();
- piCout << "\npost event";
- posted = root->postEvent(meVoid);
- piCout << "posted" << posted << "\n";
- piCout << "active atomics" << root->activeAtomics();
+ // piCout << "\npost event";
+ // posted = root->postEvent(meVoid);
+ // piCout << "posted" << posted << "\n";
+ // piCout << "active atomics" << root->activeAtomics();
+ piSleep(1.);
root->print();
// piCout << "\npost event";
diff --git a/utils/crypt_tool/main.cpp b/utils/crypt_tool/main.cpp
index 8d4ec3b7..57fdb8b0 100644
--- a/utils/crypt_tool/main.cpp
+++ b/utils/crypt_tool/main.cpp
@@ -17,8 +17,9 @@
along with this program. If not, see .
*/
+#include "picli.h"
#include "picrypt.h"
-#include "pip.h"
+#include "pifile.h"
#include
diff --git a/utils/system_test/main.cpp b/utils/system_test/main.cpp
index e62ec337..59ab539a 100755
--- a/utils/system_test/main.cpp
+++ b/utils/system_test/main.cpp
@@ -17,8 +17,9 @@
along with this program. If not, see .
*/
-#include "pip.h"
+#include "piconfig.h"
#include "pisystemtests.h"
+#include "pisystemtime.h"
#ifdef CC_GCC
# include
#endif