From 0f1b528ac6da3bb45e1f2a772b9654b4450b2e9b Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 17 Oct 2013 16:12:10 +0400 Subject: [PATCH] 17.10.2013 - Adjusted for QNX, PIPeer release for Windows, Remote console --- CMakeLists.txt | 9 ++- main.cpp | 4 +- pibytearray.cpp | 68 +++++++++++++++++++ pibytearray.h | 142 +++++++++++++++++++++++++--------------- piconfig.cpp | 22 +++++++ piconfig.h | 22 ++++++- piconsole.cpp | 13 ++-- piconsole.h | 5 +- picontainers.h | 1 + picrc.h | 3 + pidiagnostics.h | 3 + piethernet.cpp | 30 ++++++++- piethernet.h | 9 +-- pievaluator.cpp | 12 ++-- pievaluator.h | 3 + pifile.h | 3 + piincludes.cpp | 32 ++++++++- piincludes.h | 8 ++- piiodevice.cpp | 10 +++ piiodevice.h | 6 +- pikbdlistener.h | 3 + pimath.cpp | 58 +++++++++------- pimath.h | 33 +++++----- pimutex.h | 3 + pipacketextractor.h | 3 + pipeer.cpp | 70 +++++++++++++------- pipeer.h | 6 +- piprocess.h | 3 + piprotocol.h | 3 + piserial.h | 3 + pisignals.h | 3 + pistring.cpp | 8 +-- pistring.h | 2 +- pithread.cpp | 4 +- pitimer.cpp | 29 +++++++- pitimer.h | 111 ++++++++++++++++++++++++++++--- piusb.h | 3 + remote_console/main.cpp | 4 +- serial.odg | Bin 10470 -> 0 bytes serial_.emf | Bin 120024 -> 0 bytes serial_.odg | Bin 11640 -> 0 bytes serial_.svg | 2 - 42 files changed, 585 insertions(+), 171 deletions(-) delete mode 100644 serial.odg delete mode 100644 serial_.emf delete mode 100644 serial_.odg delete mode 100644 serial_.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c20124c..ee50668e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ project(pip) cmake_minimum_required(VERSION 2.6) include_directories(${CMAKE_CURRENT_SOURCE_DIR} .) include(CheckFunctionExists) -set(VERSION "0.0305") +set(VERSION "0.0306") set(SOVERSION ${VERSION}) set(CMAKE_BUILD_TYPE "Release") set(LIBS) @@ -51,12 +51,12 @@ endif () if (${WIN32}) list(APPEND LIBS ws2_32 Iphlpapi) - include(GenerateExportHeader) execute_process(COMMAND "make_rc_win.bat" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) list(APPEND CPPS "pip_resource_win.o") add_library(pip SHARED ${CPPS}) - generate_export_header(pip) if (${CMAKE_C_COMPILER} STREQUAL "cl") + include(GenerateExportHeader) + generate_export_header(pip) add_definitions("/O2 /Ob2 /Ot") else () add_definitions("-O2") @@ -65,13 +65,12 @@ else () add_definitions("-O2") if (DEFINED ENV{QNX_HOST}) list(APPEND LIBS socket) + add_definitions("-ftemplate-depth-32") add_library(pip STATIC ${CPPS}) else () list(APPEND LIBS pthread rt) - include(GenerateExportHeader) add_definitions("-Wall -g3") add_library(pip SHARED ${CPPS}) - generate_export_header(pip) endif () endif () target_link_libraries(pip ${LIBS}) diff --git a/main.cpp b/main.cpp index 7e496bf8..d0f15a9e 100644 --- a/main.cpp +++ b/main.cpp @@ -245,8 +245,10 @@ int main (int argc, char * argv[]) { console.enableExitCapture(); PIProtocol p("/home/peri4/work/ISPUM/nosit_VM6/protocols.conf", "gas", 0, 0, &a__, 4, &b__, 4); p.start(); + console.addTab("ftab", 'f'); console.addVariable("service", &p); - console.start(); + console.addTab("stab", 's'); + //console.start(); console.startServer("cons"); console.waitForFinish(); return 0; diff --git a/pibytearray.cpp b/pibytearray.cpp index 127755e9..518cec11 100644 --- a/pibytearray.cpp +++ b/pibytearray.cpp @@ -19,6 +19,74 @@ #include "pibytearray.h" +/*! \class PIByteArray + * \brief Byte array + * \details This class based on PIVector and provide some handle function + * to manipulate it. + * + * \section PIByteArray_sec0 Usage + * PIByteArray can be used to store custom data and manipulate it. There are many + * stream operators to store/restore common types to byte array. Store operators + * places data at the end of arraym restore operators takes data from the beginning + * of array. + * In addition there are Base 64 convertions and checksums: + * * plain 8-bit + * * plain 32-bit + * * CRC 8-bit + * * CRC 16-bit + * * CRC 32-bit + * + */ + + +#pragma pack(push, 1) + +const char PIByteArray::base64Table[64] = { +0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, +0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, +0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, +0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, +0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, +0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, +0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f}; + +const char PIByteArray::base64InvTable[256] = { +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x3F, +0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, +0x3C, 0x3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, +0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, +0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, +0x17, 0x18, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, +0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, +0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, +0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + +#pragma pack(pop) + int PIHuffman::nodeCompare(const void * f, const void * s) { return (reinterpret_cast(const_cast(s))->freq - diff --git a/pibytearray.h b/pibytearray.h index 32389dde..d4298425 100644 --- a/pibytearray.h +++ b/pibytearray.h @@ -1,3 +1,6 @@ +/*! \file pibytearray.h + * \brief Byte array +*/ /* PIP - Platform Independent Primitives Byte array @@ -20,56 +23,13 @@ #ifndef PIBYTEARRAY_H #define PIBYTEARRAY_H +#ifdef DOXYGEN +//! This macro allow stream template operators for write and read any type from byte array. Use it with attention! +# define PIP_BYTEARRAY_STREAM_ANY_TYPE +#endif + #include "pibitarray.h" -#pragma pack(push, 1) - -static const char base64Table[64] = { -0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, -0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, -0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, -0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, -0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, -0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, -0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, -0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f}; - -static const char base64InvTable[256] = { -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x3F, -0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, -0x3C, 0x3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, -0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, -0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, -0x17, 0x18, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, -0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, -0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, -0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - -#pragma pack(pop) - class PIByteArray; class PIHuffman { @@ -90,17 +50,28 @@ private: PIVector nodes; }; -class PIP_EXPORT PIByteArray: public PIVector { +class PIP_EXPORT PIByteArray: public PIVector +{ public: + + //! Contructs an empty byte array PIByteArray() {;} + + //! Contructs 0-filled byte array size "size" PIByteArray(const uint size) {resize(size);} + + //! Contructs byte array from data "data" and size "size" PIByteArray(const void * data, const uint size) {for (uint i = 0; i < size; ++i) push_back(((uchar * )data)[i]);} - + + + //! Help struct to store/restore custom blocks of data to/from PIByteArray struct RawData { friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v); friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v); public: + //! Contructs data block RawData(void * data, int size) {d = data; s = size;} + //! Contructs data block RawData(const void * data, const int size) {d = const_cast(data); s = size;} RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;} private: @@ -108,11 +79,19 @@ public: int s; }; + //! Return resized byte array PIByteArray resized(int new_size) {PIByteArray tv(*this); tv.resize(new_size); return tv;} + //! Convert data to Base 64 and return this byte array PIByteArray & convertToBase64(); + + //! Convert data from Base 64 and return this byte array PIByteArray & convertFromBase64(); + + //! Return converted to Base 64 data PIByteArray toBase64() {PIByteArray ba(*this); ba.convertToBase64(); return ba;} + + //! Return converted from Base 64 data PIByteArray fromBase64() {PIByteArray ba(*this); ba.convertFromBase64(); return ba;} PIByteArray & compressRLE(uchar threshold = 192); @@ -122,7 +101,10 @@ public: PIByteArray & compressHuffman() {*this = huffman.compress(*this); return *this;} + //! Add to the end data "data" with size "size" PIByteArray & append(void * data, int size) {for (int i = 0; i < size; ++i) push_back(((uchar*)data)[i]); return *this;} + + //! Add to the end byte array "data" PIByteArray & append(const PIByteArray & data) {for (int i = 0; i < data.size_s(); ++i) push_back(data[i]); return *this;} /*PIByteArray & operator <<(short v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;} PIByteArray & operator <<(ushort v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;} @@ -132,10 +114,19 @@ public: PIByteArray & operator <<(ullong v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}*/ //PIByteArray & operator <<(const PIByteArray & v) {for (uint i = 0; i < v.size(); ++i) push_back(v[i]); return *this;} + //! Returns plain 8-bit checksum uchar checksumPlain8(); + + //! Returns plain 32-bit checksum uint checksumPlain32(); + + //! Returns CRC 8-bit checksum uchar checksumCRC8(); + + //! Returns CRC 16-bit checksum ushort checksumCRC16(); + + //! Returns CRC 32-bit checksum uint checksumCRC32(); void operator =(const PIVector & d) {resize(d.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = d[i];} @@ -156,65 +147,108 @@ private: } byte; }; + static const char base64Table[64]; + static const char base64InvTable[256]; static PIHuffman huffman; }; +//! \relatesalso PIByteArray \brief Output to std::ostream operator inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba) {s << "{"; for (uint i = 0; i < ba.size(); ++i) {s << ba[i]; if (i < ba.size() - 1) s << ", ";} s << "}"; return s;} + +//! \relatesalso PIByteArray \brief Output to PICout operator inline PICout operator <<(PICout s, const PIByteArray & ba) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < ba.size(); ++i) {s << ba[i]; if (i < ba.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;} #define PBA_OPERATOR_TO int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, uchar v) {s.push_back(v); return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const short v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const int v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const long & v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const llong & v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const ushort v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const uint v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const ulong & v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const ullong & v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const float v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const double & v) {PBA_OPERATOR_TO return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {s << v.size_s(); int os = s.size_s(); s.enlarge(v.size_s()); if (v.size_s() > 0) memcpy(s.data(os), v.data(), v.size()); return s;} +//! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {int os = s.size_s(); s.enlarge(v.s); if (v.s > 0) memcpy(s.data(os), v.d, v.s); return s;} +//! \relatesalso PIByteArray \brief Store operator template inline PIByteArray & operator <<(PIByteArray & s, const PIVector & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;} +//! \relatesalso PIByteArray \brief Store operator template inline PIByteArray & operator <<(PIByteArray & s, const PIList & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;} +//! \relatesalso PIByteArray \brief Store operator template inline PIByteArray & operator <<(PIByteArray & s, const PIDeque & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;} -//template -//inline PIByteArray & operator <<(PIByteArray & s, const T & v) {PBA_OPERATOR_TO return s;} +#ifdef PIP_BYTEARRAY_STREAM_ANY_TYPE +template +inline PIByteArray & operator <<(PIByteArray & s, const T & v) {PBA_OPERATOR_TO return s;} +#endif #undef PBA_OPERATOR_TO #define PBA_OPERATOR_FROM memcpy(&v, s.data(), sizeof(v)); s.remove(0, sizeof(v)); +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, short & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, int & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, long & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, llong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, ushort & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, uint & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, ulong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, ullong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, float & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, double & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); if (sz > 0) memcpy(v.data(), s.data(), v.size()); s.remove(0, v.size()); return s;} +//! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {assert(s.size_s() >= v.s); if (v.s > 0) memcpy(v.d, s.data(), v.s); s.remove(0, v.s); return s;} +//! \relatesalso PIByteArray \brief Restore operator template inline PIByteArray & operator >>(PIByteArray & s, PIVector & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;} +//! \relatesalso PIByteArray \brief Restore operator template inline PIByteArray & operator >>(PIByteArray & s, PIList & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;} +//! \relatesalso PIByteArray \brief Restore operator template inline PIByteArray & operator >>(PIByteArray & s, PIDeque & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;} -//template -//inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +#ifdef PIP_BYTEARRAY_STREAM_ANY_TYPE +template +inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +#endif #undef PBA_OPERATOR_FROM +//! \relatesalso PIByteArray \brief Byte arrays compare operator inline bool operator ==(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return false; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return false; return true;} +//! \relatesalso PIByteArray \brief Byte arrays compare operator inline bool operator !=(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return true; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return true; return false;} #endif // PIBYTEARRAY_H diff --git a/piconfig.cpp b/piconfig.cpp index 2bcdc4f2..9abb53b8 100644 --- a/piconfig.cpp +++ b/piconfig.cpp @@ -19,6 +19,28 @@ #include "piconfig.h" +/*! \class PIConfig + * \brief Configuration file + * \details This class provide handle access to configuration file. + * + * \section PIConfig_sec0 Synopsis + * PIConfig reads configuration file and create internal dendritic + * representation of all entries of this file. You can easily read + * some values and write new. + * \image html piconfig.png + * + * \section PIConfig_sec1 Concepts + * Each entry of internal tree has type PIConfig::Entry. This class + * has next properties: + * * name + * * value + * * type + * * comment + * Entry class has many implicit convertions to common types: bolean, + * integers, float, double, PIString, PIStringList. + * + */ + PIConfig::Entry PIConfig::Branch::_empty; PIConfig::Entry PIConfig::Entry::_empty; diff --git a/piconfig.h b/piconfig.h index d80ea41f..0852f278 100644 --- a/piconfig.h +++ b/piconfig.h @@ -1,3 +1,6 @@ +/*! \file piconfig.h + * \brief Configuration file +*/ /* PIP - Platform Independent Primitives Config parser @@ -54,7 +57,9 @@ class PIP_EXPORT PIConfig: public PIFile friend class Entry; friend class Branch; public: + //! Contructs and read configuration file at path "path" in mode "mode" PIConfig(const PIString & path, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); + ~PIConfig() {/*piForeach (Entry * i, root._children) deleteEntry(i); close();*/} class Entry; @@ -172,10 +177,13 @@ public: int _line; }; + //! Returns top-level entry with name "vname", if doesn`t exists return entry with value "def" and set *exist to false Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exist = 0); Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exist = 0) const {return const_cast(this)->getValue(vname, def, exist);} + PICONFIG_GET_VALUE + //! Returns top-level entries with names matches "vname" Branch getValues(const PIString & vname); void setValue(const PIString & name, const PIString & value, const PIString & type = "s", bool write = true); @@ -192,12 +200,21 @@ public: void setValue(const PIString & name, const float value, bool write = true) {setValue(name, ftos(value), "f", write);} void setValue(const PIString & name, const double value, bool write = true) {setValue(name, dtos(value), "f", write);} + //! Returns root entry Entry & rootEntry() {return root;} + + //! Returns top-level entries count int entriesCount() const {return childCount(&root);} + + //! Returns if top-level entry with name "name" exists bool isEntryExists(const PIString & name) const {return entryExists(&root, name);} + //! Returns all top-level entries Branch allTree() {Branch b; piForeach (Entry * i, root._children) b << i; return b;} + + //! Returns all entries without children Branch allLeaves() {Branch b; allLeaves(b, &root); b.sort(Entry::compare); return b;} + int entryIndex(const PIString & name); PIString getName(uint number) {return entryByIndex(number)._name;} @@ -216,8 +233,11 @@ public: void readAll(); void writeAll(); - + + //! Returns current tree delimiter const PIString & delimiter() const {return delim;} + + //! Set current tree delimiter void setDelimiter(const PIString & d) {delim = d; setEntryDelim(&root, d); readAll();} private: diff --git a/piconsole.cpp b/piconsole.cpp index cf8d94a4..02b4bc41 100644 --- a/piconsole.cpp +++ b/piconsole.cpp @@ -356,7 +356,10 @@ void PIConsole::run() { const void * ptr = 0; if (tv.remote) { if (tv.type == 0) { - rstr << PIByteArray(tv.rdata); + rstr.clear(); + PIByteArray tba(tv.rdata); + tba >> rstr; + rstr.trim(); ptr = &rstr; } else ptr = tv.rdata.data(); @@ -380,12 +383,13 @@ void PIConsole::run() { case 14: clen = printValue(bitsValue(ptr, tv.bitFrom, tv.bitCount), tv.format); break; } if (clen + tv.offset < (uint)col_wid) { + PIString ts = PIString( #if defined(QNX) || defined(FREE_BSD) - string ts = PIString(col_wid - clen - tv.offset - 1, ' ').stdString(); + col_wid - clen - tv.offset - 1, ' '); #else - string ts = PIString(col_wid - clen - tv.offset, ' ').stdString(); + col_wid - clen - tv.offset, ' '); #endif - printf("%s", ts.c_str()); + printf("%s", ts.data()); } newLine(); } @@ -878,6 +882,7 @@ void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) { void PIConsole::peerTimer(void * data, int delim) { if (peer == 0) return; + //piCout << "timer" << delim; if (server_mode) { if (delim == 20) serverSendInfo(); diff --git a/piconsole.h b/piconsole.h index 3162a9eb..a5a8901d 100644 --- a/piconsole.h +++ b/piconsole.h @@ -1,3 +1,6 @@ +/*! \file piconsole.h + * \brief Console output class +*/ /* PIP - Platform Independent Primitives Console output/input @@ -158,7 +161,7 @@ public: void moveRight(int n = 1) {SetConsoleCursorPosition(hOut, getWinCoord(n));} void moveLeft(int n = 1) {SetConsoleCursorPosition(hOut, getWinCoord(-n));} void moveTo(int x = 0, int y = 0) {ccoord.X = x; ccoord.Y = y; SetConsoleCursorPosition(hOut, ccoord);} - void clearScreen() {FillConsoleOutputAttribute(hOut, dattr, width * (height + 1), ulcoord, &written); + void clearScreen() {toUpperLeft(); FillConsoleOutputAttribute(hOut, dattr, width * (height + 1), ulcoord, &written); FillConsoleOutputCharacter(hOut, ' ', width * (height + 1), ulcoord, &written);} void clearScreenLower() {getWinCurCoord(); FillConsoleOutputAttribute(hOut, dattr, width * height - width * ccoord.Y + ccoord.X, ccoord, &written); FillConsoleOutputCharacter(hOut, ' ', width * height - width * ccoord.Y + ccoord.X, ccoord, &written);} diff --git a/picontainers.h b/picontainers.h index 6d8d47d0..ba357fd2 100644 --- a/picontainers.h +++ b/picontainers.h @@ -712,6 +712,7 @@ public: _CMap & insert(PIPair entry_) {_stlc::insert(_stlpair(entry_.first, entry_.second)); return *this;} Key key(Type value_) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++) if (i->second == value_) return i->first; return Key();} Type & value(const Key & key_) {typename _stlc::iterator it = _stlc::find(key_); if (it == _stlc::end()) it->second = Type(); return it->second;} + Type & at(const Key & key_) {return value(key_);} Type value(const Key & key_) const {return _stlc::find(key_)->second;} }; diff --git a/picrc.h b/picrc.h index 4b0c08c0..1ea8f0c1 100644 --- a/picrc.h +++ b/picrc.h @@ -1,3 +1,6 @@ +/*! \file picrc.h + * \brief CRC checksum calculator +*/ /* PIP - Platform Independent Primitives Abstract input/output device diff --git a/pidiagnostics.h b/pidiagnostics.h index 993bac9d..dce3003a 100644 --- a/pidiagnostics.h +++ b/pidiagnostics.h @@ -1,3 +1,6 @@ +/*! \file pidiagnostics.h + * \brief Connection quality diagnostics +*/ /* PIP - Platform Independent Primitives Speed and quality in/out diagnostics diff --git a/piethernet.cpp b/piethernet.cpp index cd4c260d..96024990 100644 --- a/piethernet.cpp +++ b/piethernet.cpp @@ -72,6 +72,7 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) { PIEthernet::~PIEthernet() { piMonitor.ethernets--; if (server_thread_.isRunning()) server_thread_.terminate(); + stop(); closeSocket(sock); //if (buffer_ != 0) delete buffer_; //buffer_ = 0; @@ -110,7 +111,6 @@ bool PIEthernet::init() { #else BOOL bv = TRUE; if (params[PIEthernet::ReuseAddress]) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char * )&bv, sizeof(bv)); - setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (const char * )&bv, sizeof(bv)); #endif //cout << "inited " << sock << ": bc = " << params << endl; //fcntl(sock, F_SETFL, 0/*O_NONBLOCK*/); @@ -170,6 +170,20 @@ bool PIEthernet::closeDevice() { } +void PIEthernet::closeSocket(int & sd) { + if (sd != -1) { +#ifdef WINDOWS + shutdown(sd, SD_BOTH); + closesocket(sd); +#else + shutdown(sock, SHUT_RDWR); + ::close(sd); +#endif + } + sd = -1; +} + + bool PIEthernet::joinMulticastGroup(const PIString & group) { if (sock == -1) init(); if (sock == -1) return false; @@ -195,7 +209,7 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) { piCoutObj << "[PIEthernet] Can`t join multicast group " << group << ", " << ethErrorString(); return false; } - leafs.insert(group, ret); + if (ret != sock) leafs.insert(group, ret); #else # ifndef QNX if (!params[Broadcast]) @@ -385,11 +399,13 @@ int PIEthernet::write(const void * data, int max_size) { /*if (params[PIEthernet::Broadcast]) saddr_.sin_addr.s_addr = INADDR_BROADCAST; else*/ saddr_.sin_addr.s_addr = inet_addr(ip_s.data()); saddr_.sin_family = AF_INET; + //piCout << "[PIEth] write to" << ip_s << ":" << port_s << max_size << "bytes ..."; #ifdef WINDOWS return sendto(sock, (const char * )data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_)); #else return sendto(sock, data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_)); #endif + //piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok"; case TCP_Client: return ::send(sock, (const char *)data, max_size, 0); default: break; @@ -519,12 +535,22 @@ PIEthernet::InterfaceList PIEthernet::interfaces() { ci.address = getSockAddr(ret->ifa_addr); ci.netmask = getSockAddr(ret->ifa_netmask); ci.mac.clear(); +#ifdef QNX + int fd = ::open((PIString("/dev/io-net/") + ci.name).data(), O_RDONLY); + if (fd != 0) { + nic_config_t nic; + devctl(fd, DCMD_IO_NET_GET_CONFIG, &nic, sizeof(nic), 0); + ::close(fd); + ci.mac = macFromBytes(PIByteArray(nic.permanent_address, 6)); + } +#else if (s != -1) { struct ifreq ir; strcpy(ir.ifr_name, ret->ifa_name); if (ioctl(s, SIOCGIFHWADDR, &ir) == 0) ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6)); } +#endif ci.flags = 0; if (ret->ifa_flags & IFF_UP) ci.flags |= PIEthernet::ifActive; if (ret->ifa_flags & IFF_RUNNING) ci.flags |= PIEthernet::ifRunning; diff --git a/piethernet.h b/piethernet.h index ab7757e0..2f921729 100644 --- a/piethernet.h +++ b/piethernet.h @@ -1,3 +1,6 @@ +/*! \file piethernet.h + * \brief Ethernet device +*/ /* PIP - Platform Independent Primitives Ethernet, UDP/TCP Broadcast/Multicast @@ -145,10 +148,8 @@ protected: bool init(); bool openDevice(); bool closeDevice(); -#ifdef WINDOWS - void closeSocket(int & sd) {if (sd != -1) {shutdown(sd, SD_BOTH); closesocket(sd);} sd = -1;} -#else - void closeSocket(int & sd) {if (sd != -1) {shutdown(sock, SHUT_RDWR); ::close(sd);} sd = -1;} + void closeSocket(int & sd); +#ifndef WINDOWS static PIString getSockAddr(sockaddr * s) {return s == 0 ? PIString() : PIString(inet_ntoa(((sockaddr_in*)s)->sin_addr));} #endif diff --git a/pievaluator.cpp b/pievaluator.cpp index 2818231d..ec041f15 100644 --- a/pievaluator.cpp +++ b/pievaluator.cpp @@ -970,22 +970,22 @@ inline void PIEvaluator::execFunction(const PIEvaluatorTypes::Instruction & ci) tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg, 0.); break; case PIEvaluatorTypes::bfJ0: - tmpvars[oi].value = j0(value(ci.operators[0]).real()); + tmpvars[oi].value = piJ0(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfJ1: - tmpvars[oi].value = j1(value(ci.operators[0]).real()); + tmpvars[oi].value = piJ1(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfJN: - tmpvars[oi].value = jn(round(value(ci.operators[1]).real()), value(ci.operators[0]).real()); + tmpvars[oi].value = piJn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfY0: - tmpvars[oi].value = y0(value(ci.operators[0]).real()); + tmpvars[oi].value = piY0(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfY1: - tmpvars[oi].value = y1(value(ci.operators[0]).real()); + tmpvars[oi].value = piY1(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfYN: - tmpvars[oi].value = yn(round(value(ci.operators[1]).real()), value(ci.operators[0]).real()); + tmpvars[oi].value = piYn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfRandom: tmp = static_cast(rand()) / RAND_MAX; diff --git a/pievaluator.h b/pievaluator.h index 40b5e07d..9a366fae 100644 --- a/pievaluator.h +++ b/pievaluator.h @@ -1,3 +1,6 @@ +/*! \file pievaluator.h + * \brief Mathematic expressions calculator +*/ /* PIP - Platform Independent Primitives Evaluator designed for stream computing diff --git a/pifile.h b/pifile.h index 77711f62..f8574a4b 100644 --- a/pifile.h +++ b/pifile.h @@ -1,3 +1,6 @@ +/*! \file pifile.h + * \brief Local file +*/ /* PIP - Platform Independent Primitives File diff --git a/piincludes.cpp b/piincludes.cpp index 1754eb60..1556681d 100644 --- a/piincludes.cpp +++ b/piincludes.cpp @@ -214,6 +214,34 @@ void PICout::applyFormat(PICoutFormat f) { } -/*! \mainpage Title - * This is main page +/*! \mainpage What is PIP + * PIP - Platform-Independent Primitives - is crossplatform library for C++ developers. + * It is wrap around STL and pure C++. This library can help developers write non-GUI + * projects much more quickly, efficiently and customizable than on pure C++. + * Library contains more classes, some of them are pure abstract, some classes + * can be used as they are, some classes should be inherited to new classes. + * PIP provide classes: + * * direct output to console (\a PICout) + * * containers (\a PIVector, \a PIList, \a PIMap, \a PIStack) + * * string (\a PIString, \a PIStringList) + * * base object (events and handlers) (\a PIObject) + * * thread (\a PIThread) + * * timer (\a PITimer) + * * console (information output) (\a PIConsole) + * * stand-alone + * * server + * * client + * * i/o devices + * * base class (\a PIIODevice) + * * file (\a PIFile) + * * serial port (\a PISerial) + * * ethernet (\a PIEthernet) + * * USB (\a PIUSB) + * * packets extractor (\a PIPacketExtractor) + * * command-line arguments parser (\a PICLI) + * * math evaluator (\a PIEvaluator) + * * peering net node (\a PIPeer) + * * process (\a PIProcess) + * * state machine (\a PIStateMachine) + * */ diff --git a/piincludes.h b/piincludes.h index 6e51a0f0..09737057 100644 --- a/piincludes.h +++ b/piincludes.h @@ -39,7 +39,7 @@ #define PIP_VERSION_REVISION PIP_VERSION & 0xFF //! Suffix of PIP version -#define PIP_VERSION_SUFFIX "" +#define PIP_VERSION_SUFFIX "_r1" #ifdef DOXYGEN @@ -207,6 +207,11 @@ # include # include # include +# ifdef QNX +# include +# include +# include +# endif #endif #ifdef MAC_OS # include @@ -813,6 +818,7 @@ public: case Quote: std::cout << '"'; break; }; return *this; + } //! Output operator for \a PIFlags values diff --git a/piiodevice.cpp b/piiodevice.cpp index 8db6bc67..74a5369b 100644 --- a/piiodevice.cpp +++ b/piiodevice.cpp @@ -100,6 +100,16 @@ PIIODevice::PIIODevice(const PIString & path, PIIODevice::DeviceMode type, bool } +PIIODevice::~PIIODevice() { + stop(); + if (opened_) { + closeDevice(); + if (!opened_) + closed(); + } +} + + void PIIODevice::check_start(void * data, int delim) { //cout << "check " << tread_started_ << endl; if (open()) { diff --git a/piiodevice.h b/piiodevice.h index 1119ed3f..b981616c 100644 --- a/piiodevice.h +++ b/piiodevice.h @@ -45,7 +45,7 @@ public: }; PIIODevice(const PIString & path, DeviceMode type = ReadWrite, bool initNow = true); - virtual ~PIIODevice() {stop(); if (opened_) {closeDevice(); if (!opened_) closed();}} + virtual ~PIIODevice(); //! Current open mode of device DeviceMode mode() const {return mode_;} @@ -122,7 +122,7 @@ public: void startThreadedRead(ReadRetFunc func) {ret_func_ = func; if (!isRunning()) PIThread::start();} //! Stop threaded read - void stopThreadedRead() {PIThread::stop();} + void stopThreadedRead() {PIThread::terminate();} //! Return \b true if threaded write is started @@ -132,7 +132,7 @@ public: void startThreadedWrite() {if (!write_thread.isRunning()) write_thread.startOnce();} //! Stop threaded write - void stopThreadedWrite() {write_thread.stop();} + void stopThreadedWrite() {write_thread.terminate();} //! Clear threaded write task queue void clearThreadedWriteQueue() {write_thread.lock(); write_queue.clear(); write_thread.unlock();} diff --git a/pikbdlistener.h b/pikbdlistener.h index 508439e3..8ff6414f 100644 --- a/pikbdlistener.h +++ b/pikbdlistener.h @@ -1,3 +1,6 @@ +/*! \file pikbdlistener.h + * \brief Keyboard console input listerner +*/ /* PIP - Platform Independent Primitives Keyboard grabber for console diff --git a/pimath.cpp b/pimath.cpp index 1d44b3f5..79a6ccb6 100644 --- a/pimath.cpp +++ b/pimath.cpp @@ -20,8 +20,8 @@ #include "pimath.h" +double piJ0(const double & v) { #ifndef PIP_MATH_J0 -double j0(const double & v) { double x = v; double xsq; double nn; @@ -92,12 +92,14 @@ double j0(const double & v) { q1 = 5428918384092285160.200195092 + xsq * q1; q1 = 493378725179413356211.3278438 + xsq * q1; return p1 / q1; -} +#else + return j0(v); #endif +} +double piJ1(const double & v) { #ifndef PIP_MATH_J1 -double j1(const double & v) { double x = v; double s; double xsq; @@ -172,12 +174,14 @@ double j1(const double & v) { q1 = 1162398708003212287858.529400 + xsq * q1; result = s * x * p1 / q1; return result; -} +#else + return j1(v); #endif +} +double piJn(int n, const double & v) { #ifndef PIP_MATH_JN -double jn(const int & n, const double & v) { double x = v; double pkm2; double pkm1; @@ -202,18 +206,18 @@ double jn(const int & n, const double & v) { x = -x; } if (n == 0) { - result = sg * j0(x); + result = sg * piJ0(x); return result; } if (n == 1) { - result = sg * j1(x); + result = sg * piJ1(x); return result; } if (n == 2) { if (x == 0) result = 0; else - result = sg * (2.0 * j1(x) / x - j0(x)); + result = sg * (2.0 * piJ1(x) / x - piJ0(x)); return result; } if (x < 1E-16) { @@ -242,17 +246,19 @@ double jn(const int & n, const double & v) { k = k - 1; } while (k != 0); if (fabs(pk) > fabs(pkm1)) - ans = j1(x) / pk; + ans = piJ1(x) / pk; else - ans = j0(x) / pkm1; + ans = piJ0(x) / pkm1; result = sg * ans; return result; -} +#else + return jn(n, v); #endif +} +double piY0(const double & v) { #ifndef PIP_MATH_Y0 -double y0(const double & v) { double x = v; double nn; double xsq; @@ -321,14 +327,16 @@ double y0(const double & v) { q4 = 23928830434997818.57439356652 + xsq * q4; q4 = 4192417043410839973.904769661 + xsq * q4; q4 = 372645883898616588198.9980 + xsq * q4; - result = p4 / q4 + 2 / M_PI * j0(x) * log(x); + result = p4 / q4 + 2 / M_PI * piJ0(x) * log(x); return result; -} +#else + return y0(v); #endif +} +double piY1(const double & v) { #ifndef PIP_MATH_Y1 -double y1(const double & v) { double x = v; double nn; double xsq; @@ -396,14 +404,16 @@ double y1(const double & v) { q4 = 29549879358971486742.90758119 + xsq * q4; q4 = 5435310377188854170800.653097 + xsq * q4; q4 = 508206736694124324531442.4152 + xsq * q4; - result = x * p4 / q4 + 2 / M_PI * (j1(x) * log(x) - 1 / x); + result = x * p4 / q4 + 2 / M_PI * (piJ1(x) * log(x) - 1 / x); return result; -} +#else + return y1(v); #endif +} +double piYn(int n, const double & v) { #ifndef PIP_MATH_YN -double yn(const int & n, const double & v) { int i; double x = v; double a; @@ -418,15 +428,15 @@ double yn(const int & n, const double & v) { s = -1; } if (n == 0) { - result = y0(x); + result = piY0(x); return result; } if (n == 1) { - result = s * y1(x); + result = s * piY1(x); return result; } - a = y0(x); - b = y1(x); + a = piY0(x); + b = piY1(x); for (i = 1; i <= n - 1; i++) { tmp = b; b = 2 * i / x * b - a; @@ -434,8 +444,10 @@ double yn(const int & n, const double & v) { } result = s * b; return result; -} +#else + return yn(n, v); #endif +} double randomn(double dv, double sv) { diff --git a/pimath.h b/pimath.h index 310546bf..620e2413 100644 --- a/pimath.h +++ b/pimath.h @@ -1,3 +1,6 @@ +/*! \file pimath.h + * \brief Many mathematical functions and classes +*/ /* PIP - Platform Independent Primitives Math @@ -27,6 +30,12 @@ #else # include # include +# undef PIP_MATH_J0 +# undef PIP_MATH_J1 +# undef PIP_MATH_JN +# undef PIP_MATH_Y0 +# undef PIP_MATH_Y1 +# undef PIP_MATH_YN #endif #ifndef M_LN2 @@ -110,24 +119,12 @@ inline complexd log2(const complexd & c) {return log(c) / M_LN2;} inline complexd log10(const complexd & c) {return log(c) / M_LN10;} # endif #endif -#ifndef PIP_MATH_J0 - __attribute__ ((unused)) static double j0(const double & v); -#endif -#ifndef PIP_MATH_J1 -__attribute__ ((unused)) static double j1(const double & v); -#endif -#ifndef PIP_MATH_JN -__attribute__ ((unused)) static double jn(const int & n, const double & v); -#endif -#ifndef PIP_MATH_Y0 -__attribute__ ((unused)) static double y0(const double & v); -#endif -#ifndef PIP_MATH_Y1 -__attribute__ ((unused)) static double y1(const double & v); -#endif -#ifndef PIP_MATH_YN -__attribute__ ((unused)) static double yn(const int & n, const double & v); -#endif +double piJ0(const double & v); +double piJ1(const double & v); +double piJn(int n, const double & v); +double piY0(const double & v); +double piY1(const double & v); +double piYn(int n, const double & v); inline double toDb(double val) {return 10. * log10(val);} inline double fromDb(double val) {return pow(10., val / 10.);} inline double toRad(double deg) {return deg * M_PI_180;} diff --git a/pimutex.h b/pimutex.h index b7c68bdd..265f7202 100644 --- a/pimutex.h +++ b/pimutex.h @@ -1,3 +1,6 @@ +/*! \file pimutex.h + * \brief Mutex +*/ /* PIP - Platform Independent Primitives Mutex diff --git a/pipacketextractor.h b/pipacketextractor.h index ade0ad30..18a00d72 100644 --- a/pipacketextractor.h +++ b/pipacketextractor.h @@ -1,3 +1,6 @@ +/*! \file pipacketextractor.h + * \brief Packets extractor +*/ /* PIP - Platform Independent Primitives Packets extractor diff --git a/pipeer.cpp b/pipeer.cpp index 23dfa7bb..db7b3106 100644 --- a/pipeer.cpp +++ b/pipeer.cpp @@ -21,7 +21,7 @@ #define _PIPEER_PORT_SYNC_START 13313 #define _PIPEER_PORT_SYNC_END 13353 -#define _PIPEER_IP_MULTICAST "239.13.3.12" +#define _PIPEER_IP_MULTICAST "230.13.3.12" #define _PIPEER_MSG_SIZE 8192 PIPeer::PIPeer(const PIString & name): PIObject() { @@ -29,6 +29,7 @@ PIPeer::PIPeer(const PIString & name): PIObject() { setName(name); self_info.name = name_; self_info.dist = 0; + eth_send = 0; //joinMulticastGroup("239.240.241.242"); srand(uint(PITimer::elapsed_system_m())); //id_ = name() + "_" + PIString::fromNumber(rand()); @@ -37,21 +38,24 @@ PIPeer::PIPeer(const PIString & name): PIObject() { sl.removeAll("127.0.0.1"); sl << "127.0.0.1"; initMulticasts(sl); initEths(sl); - //piCout << "Peer" << name_; + sendSelfInfo(); timer.addDelimiter(5); timer.start(1000); - sendSelfInfo(); } PIPeer::~PIPeer() { piForeach (PIEthernet * i, mc_eths) i->stopThreadedRead(); + if (eth_send != 0) + eth_send->stopThreadedRead(); sendSelfRemove(); destroyMulticasts(); piForeach (PIEthernet * i, eths) delete i; eths.clear(); + if (eth_send != 0) + delete eth_send; } @@ -88,6 +92,9 @@ void PIPeer::initEths(const PIStringList & al) { } } } + eth_send = new PIEthernet(); + eth_send->setParameters(0); + eth_send->setDebug(false); } @@ -116,6 +123,7 @@ void PIPeer::initMulticasts(const PIStringList & al) { if (!ce->open()) continue; if (is_main) if (!ce->joinMulticastGroup(_PIPEER_IP_MULTICAST)) continue; //piCout << "mc binded to" << ce->path(); + ce->setName(is_main ? "no_send" : ""); mc_eths << ce; if (is_main || is_bc) { if (is_main) rec_mc = true; @@ -175,14 +183,6 @@ PIPeer::PeerInfo * PIPeer::quickestPeer(const PIString & to) { } -bool PIPeer::sendToNeighbour(PIPeer::PeerInfo * peer, const PIByteArray & ba) { - if (peer->_neth == 0) return false; - //piCout << "send to" << peer->name << peer->_naddress << ba.size_s() << "bytes"; - diag_d.sended(ba.size_s()); - return peer->_neth->send(peer->_naddress, ba.data(), ba.size_s()); -} - - bool PIPeer::send(const PIString & to, const void * data, int size) { PeerInfo * dp = quickestPeer(to); if (dp == 0) { @@ -193,6 +193,7 @@ bool PIPeer::send(const PIString & to, const void * data, int size) { ba << int(4) << self_info.name << to << int(0) << size; PIByteArray fmsg(data, size), cmsg; int msg_count = (size - 1) / _PIPEER_MSG_SIZE + 1; + //piCout << "[PIPeer] send" << size << "bytes in" << msg_count << "packets ..."; for (int i = 0; i < msg_count; ++i) { int csize = (i == msg_count - 1) ? ((size - 1) % _PIPEER_MSG_SIZE + 1) : _PIPEER_MSG_SIZE; cmsg.clear(); @@ -201,17 +202,23 @@ bool PIPeer::send(const PIString & to, const void * data, int size) { cmsg.append(fmsg.data(i * _PIPEER_MSG_SIZE), csize); if (!sendToNeighbour(dp, cmsg)) return false; } + //piCout << "[PIPeer] send" << size << "bytes ok"; return true; } bool PIPeer::dataRead(uchar * readed, int size) { - diag_d.received(size); + if (size < 16) return true; PIByteArray ba(readed, size), sba; int type, cnt, rec_size; PIString from, to; - ba >> type >> from >> to >> cnt >> rec_size; - //piCout << "[PIPeer \"" + name_ + "\"] Received packet" << type << from << to << cnt << rec_size; + ba >> type; + //piCout << "[PIPeer \"" + name_ + "\"] Received packet" << type; + if (type != 4) return true; + PIMutexLocker locker(eth_mutex); + diag_d.received(size); + ba >> from >> to >> cnt >> rec_size; + //piCout << "[PIPeer \"" + name_ + "\"] Received packet" << /*type << from << to << cnt <<*/ rec_size; if (type == 4) { // data packet if (to == self_info.name) { // my packet int msg_count, cmsg; @@ -256,17 +263,20 @@ bool PIPeer::dataRead(uchar * readed, int size) { bool PIPeer::multicastRead(uchar * data, int size) { + if (size < 8) return true; + int type; + PIByteArray ba(data, size); + ba >> type; + if (type <= 0 || type >= 4) return true; + PeerInfo pi; + PIVector rpeers; + ba >> pi.name; + //piCout << "read type" << type << "from" << pi.name; + if (pi.name == name_) return true; PIMutexLocker locker(mc_mutex); diag_s.received(size); - int header; - PeerInfo pi; - PIByteArray ba(data, size); - PIVector rpeers; - ba >> header >> pi.name; - //piCout << "read type" << header << "from" << pi.name; - if (pi.name == name_) return true; //piCout << "analyz ..."; - switch (header) { + switch (type) { case 1: // new peer accepted //piCout << "new peer packet ..."; if (hasPeer(pi.name)) break; @@ -346,17 +356,31 @@ bool PIPeer::multicastRead(uchar * data, int size) { } +bool PIPeer::sendToNeighbour(PIPeer::PeerInfo * peer, const PIByteArray & ba) { + if (peer->_neth == 0) return false; + //piCout << "[PIPeer] sendToNeighbour" << (eth_send->readAddress()) << peer->_naddress << ba.size_s() << "bytes ..."; + //bool ok = peer->_neth->send(peer->_naddress, ba.data(), ba.size_s()); + bool ok = eth_send->send(peer->_naddress, ba.data(), ba.size_s()); + //piCout << "[PIPeer] sendToNeighbour" << (ok ? "ok" : "fail"); + if (ok) diag_d.sended(ba.size_s()); + return ok; +} + + void PIPeer::sendMulticast(const PIByteArray & ba) { + //piCout << "send muticast ..."; piForeach (PIEthernet * e, mc_eths) { + if (e->name() == "no_send") continue; for (int p = _PIPEER_PORT_SYNC_START; p < _PIPEER_PORT_SYNC_END; ++p) { e->setSendPort(p); //errorClear(); - //piCout << "send to" << e->sendAddress() << e->send(ba); + //piCout << "send to" << e->path() << e->sendAddress();// << e->send(ba); //piCout << PIEthernet::ethErrorString(); e->send(ba); diag_s.sended(ba.size_s()); } } + //piCout << "send muticast ok"; } diff --git a/pipeer.h b/pipeer.h index 2c971a51..3caff714 100644 --- a/pipeer.h +++ b/pipeer.h @@ -1,3 +1,6 @@ +/*! \file pipeer.h + * \brief Peering net node +*/ /* PIP - Platform Independent Primitives Peer - named I/O ethernet node, forming self-organized peering network @@ -145,8 +148,9 @@ private: PIVector eths; PIVector mc_eths; + PIEthernet * eth_send; PITimer timer; - PIMutex mc_mutex; + PIMutex mc_mutex, eth_mutex; bool rec_mc, rec_bc; PeerInfo self_info; diff --git a/piprocess.h b/piprocess.h index a3ddf923..8498862e 100644 --- a/piprocess.h +++ b/piprocess.h @@ -1,3 +1,6 @@ +/*! \file piprocess.h + * \brief Process +*/ /* PIP - Platform Independent Primitives Process diff --git a/piprotocol.h b/piprotocol.h index 61163499..0c87fad1 100644 --- a/piprotocol.h +++ b/piprotocol.h @@ -1,3 +1,6 @@ +/*! \file piprotocol.h + * \brief Highly configurable from file device +*/ /* PIP - Platform Independent Primitives Protocol, input/output channel (COM, UDP) diff --git a/piserial.h b/piserial.h index dd0e9a7e..b87d02f9 100644 --- a/piserial.h +++ b/piserial.h @@ -1,3 +1,6 @@ +/*! \file piserial.h + * \brief Serial device +*/ /* PIP - Platform Independent Primitives COM diff --git a/pisignals.h b/pisignals.h index 3cd8c872..e6fcd0b5 100644 --- a/pisignals.h +++ b/pisignals.h @@ -1,3 +1,6 @@ +/*! \file pisignals.h + * \brief System signals +*/ /* PIP - Platform Independent Primitives Signals diff --git a/pistring.cpp b/pistring.cpp index d530390d..af153f39 100644 --- a/pistring.cpp +++ b/pistring.cpp @@ -249,10 +249,10 @@ PIString & PIString::cutMid(const int start, const int len) { PIString & PIString::trim() { int st = 0, fn = 0; for (int i = 0; i < length(); ++i) - if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r') + if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12)) {st = i; break;} for (int i = length() - 1; i >= 0; --i) - if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r') + if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12)) {fn = i; break;} *this = mid(st, fn - st + 1); return *this; @@ -262,10 +262,10 @@ PIString & PIString::trim() { PIString PIString::trimmed() const { int st = 0, fn = 0; for (int i = 0; i < length(); ++i) - if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r') + if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12)) {st = i; break;} for (int i = length() - 1; i >= 0; --i) - if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r') + if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12)) {fn = i; break;} return mid(st, fn - st + 1); } diff --git a/pistring.h b/pistring.h index eca88141..ce76ed4b 100644 --- a/pistring.h +++ b/pistring.h @@ -676,7 +676,7 @@ inline PICout operator <<(PICout s, const PIString & v) {s.space(); s.quote(); s inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {int l = v.lengthAscii(); s << l; if (l <= 0) return s; int os = s.size_s(); s.enlarge(l); memcpy(s.data(os), v.data(), l); return s;} //! \relatesalso PIString \relatesalso PIByteArray \brief Input operator from PIByteArray -inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {int l; s >> l; if (l <= 0) return s; v = PIString((const char * )s.data(), l); s.remove(0, l); return s;} +inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {if (s.size() < 4) {v.clear(); return s;} int l; s >> l; if (l <= 0) return s; v = PIString((const char * )s.data(), l); s.remove(0, l); return s;} //! \relatesalso PIString \brief Return concatenated string diff --git a/pithread.cpp b/pithread.cpp index 9ff6b122..bd564e27 100644 --- a/pithread.cpp +++ b/pithread.cpp @@ -63,6 +63,7 @@ void piUSleep(int usecs) { PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int timer_delay): PIObject() { piMonitor.threads++; + thread = 0; data_ = data; ret_func = func; running = lockRun = false; @@ -74,6 +75,7 @@ PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int timer_delay) PIThread::PIThread(bool startNow, int timer_delay): PIObject() { piMonitor.threads++; + thread = 0; ret_func = 0; running = lockRun = false; priority_ = piNormal; @@ -84,7 +86,7 @@ PIThread::PIThread(bool startNow, int timer_delay): PIObject() { PIThread::~PIThread() { piMonitor.threads--; - if (!running) return; + if (!running || thread == 0) return; #ifndef WINDOWS pthread_cancel(thread); #else diff --git a/pitimer.cpp b/pitimer.cpp index 384e016d..aa391165 100644 --- a/pitimer.cpp +++ b/pitimer.cpp @@ -1,4 +1,4 @@ -/* +/*ccc PIP - Platform Independent Primitives Timer Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com @@ -20,6 +20,33 @@ #include "pitimer.h" #include "pisystemtests.h" + +/*! \class PITimer + * \brief Timer + * + * \section PITimer_sec0 Synopsis + * This class implements timer function. PIP timers supports 3 way to tick notify, + * frequency delimiters and time measurements. + * \section PITimer_sec1 Notify variants + * Notify variants: + * * "slot" - static function with format void func(void * data, int delimiter); + * * event - \a void timeout(void * data, int delimiter); + * * virtual function - \a void tick(void * data, int delimiter). + * All this variant are equivalent, use most applicable. + * \section PITimer_sec2 Frequency delimiters + * Frequency delimiter is an integer number and "slot" function. If "slot" function is null + * timer main "slot" will be used. Each delimiter numbers tick timer will be execute + * delimiters or timer main "slot" function with \b delimiter value = delimiter number. + * Example: \snippet pitimer.cpp delimiter + * \section PITimer_sec3 Time measurements + * PITimer can be used as time measurer. Function \a reset() set time mark to current + * system time, then functions double elapsed_*() returns time elapsed from this mark. + * These functions can returns nano-, micro-, milli- and seconds with suffixes "n", "u", "m" + * and "s"; + * Example: \snippet pitimer.cpp elapsed +*/ + + bool operator ==(const PITime & t0, const PITime & t1) { return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds); } diff --git a/pitimer.h b/pitimer.h index 5fed2921..0b70d59f 100644 --- a/pitimer.h +++ b/pitimer.h @@ -1,3 +1,6 @@ +/*! \file pitimer.h + * \brief Timer +*/ /* PIP - Platform Independent Primitives Timer @@ -153,31 +156,38 @@ class PIP_EXPORT PITimer { PIOBJECT(PITimer) public: + + //! \brief Constructs timer with execution function \b slot and common data \b data. PITimer(TimerEvent slot = 0, void * data = 0, bool threaded = true); PITimer(bool threaded); virtual ~PITimer(); + + //! \brief Set custom data. void setData(void * data_) {data = data_;} + + //! \brief Set timer execution function. void setSlot(TimerEvent slot) {ret_func = slot;} + + //! \brief Returns current loop delay. double interval() const {return interval_;} -#ifndef PIP_TIMER_RT + + EVENT_HANDLER0(void, reset) { # ifdef WINDOWS - EVENT_HANDLER0(void, reset) {t_st = GetCurrentTime();} + t_st = GetCurrentTime(); # elif defined(MAC_OS) - EVENT_HANDLER0(void, reset) {clock_get_time(__pi_mac_clock, &t_st);} + clock_get_time(__pi_mac_clock, &t_st); # else - EVENT_HANDLER0(void, reset) {clock_gettime(0, &t_st);} + clock_gettime(0, &t_st); # endif - EVENT_HANDLER1(bool, start, int, timer_delay) {start(double(timer_delay)); return true;} + } + EVENT_HANDLER1(void, start, int, msecs) {start(double(msecs));} EVENT_HANDLER1(void, start, double, msecs); - EVENT_HANDLER0(void, stop) {running_ = false;} EVENT_HANDLER2(void, deferredStart, double, interval_msecs, double, delay_msecs); EVENT_HANDLER2(void, deferredStart, double, interval_msecs, const PIDateTime &, start_datetime); +#ifndef PIP_TIMER_RT + EVENT_HANDLER0(void, stop) {running_ = false; PIThread::stop();} #else - EVENT_HANDLER0(void, reset) {clock_gettime(0, &t_st);} - EVENT_HANDLER1(void, start, double, msecs); - EVENT_HANDLER2(void, deferredStart, double, interval_msecs, double, delay_msecs); - EVENT_HANDLER2(void, deferredStart, double, interval_msecs, const PIDateTime &, start_datetime); EVENT_HANDLER0(void, stop); EVENT_HANDLER0(bool, waitForFinish) {return waitForFinish(-1);} EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs); @@ -186,9 +196,17 @@ public: EVENT_HANDLER0(void, lock) {mutex_.lock();} EVENT_HANDLER0(void, unlock) {mutex_.unlock();} #endif + + //! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot. void addDelimiter(int delim, TimerEvent slot = 0) {ret_funcs << TimerSlot(slot, delim);} + + //! \brief Remove all frequency delimiters \b delim. void removeDelimiter(int delim) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].delim == delim) {ret_funcs.remove(i); i--;}} + + //! \brief Remove all frequency delimiters with slot \b slot. void removeDelimiter(TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot) {ret_funcs.remove(i); i--;}} + + //! \brief Remove all frequency delimiters \b delim with slot \b slot. void removeDelimiter(int delim, TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot && ret_funcs[i].delim == delim) {ret_funcs.remove(i); i--;}} void setDelimiterValue(int delim, int value) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].delim == delim) ret_funcs[i].tick = value;} void setDelimiterValue(TimerEvent slot, int value) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot) ret_funcs[i].tick = value;} @@ -197,20 +215,40 @@ public: int delimiterValue(int delim, TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot && ret_funcs[i].delim == delim) return ret_funcs[i].tick; return -1;} EVENT_HANDLER0(void, clearDelimiters) {ret_funcs.clear();} + + //! \brief Returns nanoseconds elapsed from last \a reset() execution or from timer creation. double elapsed_n(); // nanoseconds + + //! \brief Returns microseconds elapsed from last \a reset() execution or from timer creation. double elapsed_u(); // microseconds + + //! \brief Returns milliseconds elapsed from last \a reset() execution or from timer creation. double elapsed_m(); // milliseconds + + //! \brief Returns seconds elapsed from last \a reset() execution or from timer creation. double elapsed_s(); // seconds + double reset_time_n(); // nanoseconds double reset_time_u(); // microseconds double reset_time_m(); // milliseconds double reset_time_s(); // seconds + + + //! \brief Returns time mark of last \a reset() execution or timer creation. PISystemTime reset_time(); + + //! \brief Returns nanoseconds representation of current system time. static double elapsed_system_n(); // nanoseconds + + //! \brief Returns microseconds representation of current system time. static double elapsed_system_u(); // microseconds + + //! \brief Returns milliseconds representation of current system time. static double elapsed_system_m(); // milliseconds + + //! \brief Returns seconds representation of current system time. static double elapsed_system_s(); // seconds @@ -244,7 +282,60 @@ public: EVENT2(timeout, void * , data, int, delimiter) +//! \handlers +//! \{ + + /** \fn void reset() + * \brief Set internal time mark to current system time + * \details This function used for set start time mark. Later + * you can find out elapsed time from this time mark to any + * moment of time with \a elapsed_s(), \a elapsed_m(), + * \a elapsed_u() or \a elapsed_n() function. + * \sa \a elapsed_s(), \a elapsed_m(), \a elapsed_u(), \a elapsed_n() */ + + /** \fn void start(int msecs) + * \brief Start timer with \b msecs loop delay + * \details Start execution of timer functions with frequency = 1 / msecs Hz. */ + + /** \fn void start(double msecs) + * \brief Start timer with \b msecs loop delay + * \details Start execution of timer functions with frequency = 1. / msecs Hz. + * Instead of \a start(int msecs) function this variant allow start timer + * with frequencies more than 1 kHz. */ + + //! \fn void stop() + //! \brief Stop timer + + /** \fn void deferredStart(double interval_msecs, double delay_msecs) + * \brief Start timer with \b interval_msecs loop delay after \b delay_msecs delay. + * \details Timer wait \b delay_msecs milliseconds and then normally starts with + * \b interval_msecs loop delay. + * \sa \a void start(double msecs), \a void deferredStart(double interval_msecs, const PIDateTime & start_datetime) */ + + /** \fn void deferredStart(double interval_msecs, const PIDateTime & start_datetime) + * \brief Start timer with \b interval_msecs loop delay after \b start_datetime date and time. + * \details Timer wait until \b start_datetime and then normally starts with + * \b interval_msecs loop delay. + * \sa \a void start(double msecs), \a void deferredStart(double interval_msecs, double delay_msecs) */ + + //! \fn void clearDelimiters() + //! \brief Remove all frequency delimiters. + +//! \} +//! \events +//! \{ + + /** \fn void timeout(void * data, int delimiter) + * \brief Raise on timer tick + * \details \b Data can be set with function \a setData(void * data) or from constructor. + * \b Delimiter if frequency delimiter, 1 for main loop. */ + + +//! \} + protected: + //! Virtual timer execution function, similar to "slot" or event \a void timeout(void * data, int delimiter). + //! By default is empty. virtual void tick(void * data, int delimiter) {;} private: diff --git a/piusb.h b/piusb.h index 5a61ace9..f04de800 100644 --- a/piusb.h +++ b/piusb.h @@ -1,3 +1,6 @@ +/*! \file piusb.h + * \brief USB device +*/ /* PIP - Platform Independent Primitives USB, based on libusb diff --git a/remote_console/main.cpp b/remote_console/main.cpp index faafff9b..39f97a2e 100644 --- a/remote_console/main.cpp +++ b/remote_console/main.cpp @@ -31,8 +31,6 @@ void key_event(char key, void * ) { if (ind < 0 || ind >= as.size_s()) return; selected = true; console.connectToServer(as[ind]); - console.clearScreen(); - piCout << "Connecting to" << console.selectedServer() << "..."; } int main(int argc, char * argv[]) { @@ -52,7 +50,7 @@ int main(int argc, char * argv[]) { } } if (!selected) return 0; - console.clearScreen(); + //console.clearScreen(); piCout << "Connecting to" << console.selectedServer() << "..."; while (!PIKbdListener::exiting) { msleep(20); diff --git a/serial.odg b/serial.odg deleted file mode 100644 index 97246b8a25a2ba9cb5ccec03956beae720663335..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10470 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 diff --git a/serial_.emf b/serial_.emf deleted file mode 100644 index 6ec3f2a60f890b558b476d887bc8eef834fd3b2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120024 zcmeI53B0Xi+5Z>LN#-F#LXP2>mEjnVSrksm>@DLPqBo@sg~|}3ghCWbi6Saw7L}w( z$W$S7C`4uGWcdHSYu(>{?pB`VoVVD|`~U3iJg)2hUDtg**ZsYpwf5R;ueJ76olfV2 zIsDpw>P}}=4!8(;%Q0OUKNg3BJmP*$AEzGAkufx3lF{*-MQ9J9|tX-I`*_!{G<)++qpT_&|LbQlJ%^f{F|y?>7Bi-HP=B*-E$9D-|Pdu zypWBbDHjkuW;oQJG4{b6t?R+IWj*f0Jz0-Evk&;SR<8@a4f|k^T+{Q-+1rO&qfcV+ zH-|X6SakE-u%6j-BRcSPoz9O}$?ZHgEe`p_(6FZ#YpxdExx>94uB*T0MryD0&UIC5 zbxeJ@``)7T`1NpJuCQhw><>$feK1Gsda&jX_j=riPggy&5A5@HdAzxmfq9E$g{!bg!p*a((=Xq4!U{6y`J&8)_ANwZw?-N ze?Q;9KbKx}ljw}A#y^Puh3Gt9J}>^~<6jVaOsuio+&bJRex=kvXMNl!qT%;j&$mW$ z=!5y#JhbTKq1?aJ8qRCEpOx#DmE()D))TT;SX~(Zi}A6?#Tu(w!4>_LSXqA%tGZU3 zSh;RlIld(8{&Hc3_NDk2$DSB#Ojcix4p;PV#MajpF*L6)>o>9Luhk}2u3J`)v8QB> zTvzyCDJ)JdmYA$gOdPJ{^|K;Yv$B2@tNvPTW5v2_R*YHGS7T+Rc4`%q)$z$SetP0w zS1=-m=5<9~a+_H7*J>LpnAEHoUz#3r#6)`ke!OlHsV%1-( zO{`=hE5}&YCM)i<(X_;5^@-?kC4NS%thkm%LdJu^<}3{ef)2gTNkK1K)Q5-lDv%bvLWq)4D&skS_Vj>O?^j*FX>aX!5PRp+Tie*vlWb&; zy&}5oFOQF=C04VchI8U}*^>*;y1vZSW$!*|*{`~O)85+eAok9s=eDt@rPYIr-OR&m0&Nv%bvLWnb@;Id%P}y>-6_v3D-LwT(SJ$wsc&E2GPvoc>tN zM)u6fzk%%KjO}M%$6l^}|K8fuAog`{ZDS8F+4K08am`+>-_~rn#*N4AvWFAbFfr?U zy{pTsVf04bsWaC&18~uJ;vzZe1a>n+vuVa%_-<}4suX}6Lb#Lz@ z>|g!g-}gVqIKsa7dWpqy`{wyzeh<_AdYRXJc$@j({_bUj{qX(XYlQvqvFCdmzjNGq zp5F6VUytSS2){$c=eaGlLrRQXa-4&19@g99aQ@D5!u-9Sj*N9ZX!yoHQ036Kx#;F$ z+pwM$7VNEO&sf)khHq@sDu?x$i*8<9)-!LQ(&ILqnp>3^<17`(9_FvvGmIQHGZxAw#3LK$2sWcVK>X%2~+ic z&iStw^CH>m>)7b!YoX0MJ9R$P*{d_Avw3Hi&PO}DcXl;4Vhe$}VtM@#k5@VH`SL!> z@3(tK+wM)-x9~q;OkOjYz$Da@V*GqLAxF~w-E()vW@jc70T znibDyZ*5{PW7#;~Dr=iRcObA?C;szU`$n-dM>8gyu_YIM-Na)$YvzA%jZX~C`Z8Ci z{+!8KCOOl^&KYZt^%*zqt^GE!cdos)iMsWKF&zS2#ei;t!t^GE!cdos)iMdf<-z$@geo|~q=ll8J0r82USzqSr)ITaY$0TR(*h6E@u|DIb zy|v#a_Rh7pHnEqZY#eV9DEoy2Y#z?q_lQ4V2K&Sslg+zJF8YOuC%v;-{1f97L$kij z)f4W_p8uVfoZn>PS+V9=pK;UP+HVtk=h|DF*vnBij;GIyQ9cn4Voy(Sm5t*oq8}6; zHg7LEpDxyzY%VFe=s(OH*jyI>Yw?Mp)%D@4PW^+EgSLJwdmtz4+mm|#-qL>)d*|9) zo7l@yHjcN8z;z3oXTya1;kQIPD%O~6HY&O3wb)ht1vbSBy^#Ev8#v=IYeHEJ4n7e(Zd)=2)LG*Ma=%y|v#a_Rh7p zu{mE`*vm1?>#}kDx-9(QaDdI!@z;-!wo|dhWb=zm?vBeG*gR4+W7e0sI`#2)OTC}P zZWe2f^%=7_@~ijOew)}k*Y%9e`P#zXp0d0y`_Y9T`YBm2Z16uDAA4LZImBYR&$qzt zq)La)!_mGHZ75di%UoUd$Clh9ik;lOwf`pep3n6RCwtb)d!$^u9P?0ONRyi}bBD9< z{^tPgDO=pVW*CppzVY5nt^?M2ef)jm|2lT75+lcJhFr#TM%Xl#Yv#FV8&q0`L)RoZ z+yVTVlOw@F#c*dd@dHAu-PX5`SCvz`>hfqC&Mlq zav6U$_BXMxIU)Y#m1cbykVCF}dqjNpcJJ6nV#y&E^NM?G|4r;&kLPO>d%4Mm@xfX5 zN;%*O`zxb;KK^sDhm{yPvLTo8YB_u^WR>_|t2FDwfE;q!1L{v5`{NwHOzao2+yVTVlOw@Fy?ukr*gm(HXkh-&ygC#%7$EZo=1WW8b3p0(X0;xeuhK; zVGinF5KGQJIf#)%%=-4IPJQ>*SQGntJ=AOyd%4Mm@qRhZ$o(!nVe^*af3R3$|KxNYZH69$%gUvSww+`7y&ExdWaIct(f5rGo5SL77hlc# zFdzq=J)r)<@p*pt1F`(x%{{cfJ*wAxYpjXA>+yVTVlOw@FrGi_KQ$J;^3$A5|LYg=xM&ud%MtPcZn(Afj(|1tiY z@qZt?OsxB5eS1`gy?bk{iM{Lbd~IScH`y@e^*TR^g)eNbjQ{JR@%kcSSlZR}wn8++vQ!oC+>_GbYi+BvbtkYNAwa3B}`>R8x37>(NqF*NJLg7c|U zAGVi8Bli7b$;rQ0+*|t{#GYFA)+Y9Hl#SzQ!x46{nI`@P@khm86l*MQm(A^AMlSl@ zv9Nz4+V$~?p;=$%>eRn6IkzR}`dEIpH7D*X?ydbcv8NW-g}t?jy&PrZc=m9-COyMu z`uJDIpE>p?vBu(d+3>xRT=c)i!v4i*cf}`$W__8fQ=j{f$C7hr>_f5U#C^rRwcjT8 z)Z)6Zw>Ghtqih^65{`U-h0WaYuZur_?5|>t#qF};_CPNB>+(1S_H)FCCoweZ%UqrM ze2?uUhwr5mGshh3Gj7^j`)y+HTzhL1dwPPKY#hJ0u!GGC@wtXKhnh0VCEef4Oo#~PE(*Gn!s zuY2pViN8~PVrbTvxjO7uP7cqD-j?(18EcO98FL-TuijhxZDQ|SdutPWIm*WIh54fh zu!GGzXYM_(cJQpZUx;Q*Hjc4hO&m7(Fjup_%+;xXVCtTd+>LS`p7S@y`i!{_yge7yatQVRLQ#GvX6N ztLw8r>eQb*Bl|?R!Sf4T1f&A*dwcjT8&b7BTv6rK494|6&?rXAM*!($6eiMI&X!pe$lg-Q}7k!b! zexCTRk53HE`Z8Ci{cJf5r5bGhtqih_X zp7m~-^}^=l`0K_$Ep|ezG1=@^a?yDWI&2P)zkPgSXx5jxI`z4B-k2bNVCm74d@wcMy6&*Hb#)k>o?!^+5%?C=Zb6~@5g&bqnm$^Fi z@p+97_J3l{u|8vZlwZBK_S?kXx%Sp3_Vy$jIKvG6kXYE@f4pd)j3tMdY+$y3rNick zXrGE^%=(Po6XwYNVEIY zXW!$~Us@ab`!x3Cp6*`lsn-k|*9w+v#~k<6vDX`W`k7Kk&H9e9UNiVyD_H6qvpziz zx+dwf>6)o~Bd<;D?M*g}xnJ5NmfHr`7#jDHFyKCu7&)?W{O#y|pZaWkzE7!HAFkw} zTOW-yB^QiCiZfZ4P)L5w#fWFp0GJ6+K-~$5X<|; zh>;^3$4f_lAUbRokAF>kHS5EG9CY@8`gcV8bF`yl`Md!4(E9eMUhl23HBu+#{^f5f zx*pHhCiZfZ4dc&c{cnGBk1uQvh{o?C?}|OH#K@5ixr{fC{dsJcP5iSf&H6APhg|l6 z`u9iUx$T2vd5+!vvc5g4*L!PhjRy9v$Mdy`z1(EO_`_NM){FFb!sdwudfLJZO^T5t z8*-g~ehu_pHQdN^O3*vm~e zj5kY4VY{+H2Z|vT&u=!|w z-UFj%eHf5~&K^*IO#B1m|0uB|V%;z6+oO8Dx5k>-yB^QiCiZfZ4dYp}{tcGy@r2Ef zqwzkL>7$J)F>+)>F5@j@*(2DzGyYpD&H6APhg|l6`g6zMHvTUY+dbC(vc5g4*L!QM ziM{Lbd~IScH`y@ez1PRb!V@;{i_dF9KN&k!EHQFqaVo=RLps#B#eLhnV&4QN7+Q`kLPO>d%4MmF|YH#E*8G9IV=93<6j>8hY}+v z|2mPnxr`snfc=8ao$;TkH0#5F9CFzM>i;hOyzze;yJ##q#H??R>h<0lYhv$uJYSpG z!x(O|VSHo8cNHBrH^=`?wA*8EEirQPugjiX#-sB&_s_?|=E-Qh2SCmGFdzrr+trKF zrU~n(W4V2~he>wR$jQGh z8*&-X6Q1yfeJB1cl_q-_kV7teK>a!5KOTRk*zWr~N-WYV?ydbdv3EV5uTAXbCL6{V zXVH%rp0If|KJQ=T?>JmuV&vpsmkqg$7Yj4q+X4IOOHPg*{scj(I)+Jqe4?`1>Lp7ZXQ z{8-qTFG(YN+Xv@W7*5IFZj;Au@6F!spC?+^>f2jm|H-`_^tXA|>Ha;QojMZ}olB07cdUy79lNtZ{c55u5#@p?ViOrqA&9lO&HAjul zv3!ozav$(w^v81?o8zGze=p;^i@iT~a&G5?u7#1m(-erW@bz-n0#jt~weam|yXCz% zr{!As`a=2M-ghk+n-jopIG)Zpw38xubYAc~9rSUY}!P zj%A`h5_>?7X-f{*jIqDQx95b1zURm9ES4j0QJM5T=T-Q-sdBnxhWzd%oSu$-C@0Nb zW7n^>+e?gGa-4&19<~kZIV~GXFL%ef9{gInvc$+G$2sWcwPig=yrI|AHLLgi`uhF0u1}BjQP-zGdu#f6g__K@ zx8c04kI!0b_HvYsV|#^7zhqGE zHum*(>H4q_rB~V0H=34M&4w}YKg7xgAD-Bny?oJS&wO&V_SSv}v3D-#Ya4sk zD;t?(d4IF)AC8a4dy$RRY{*4_ELQet@IY{NTbL#p{d&@bA4Px(H`e++_ z7|BMi*uO@X{S)!go-CGF&4w}Yzs1TPAC6e-%UoUdPnBHGV@_SaX>aX!5PRp+N88xL zO*S&ez8GEh&&EfaSS+!c4P)oX9u1CI>&skS_S8k=Jm%E(oA%az2eEf9eYA~z%|?FM zdFGtNesp}anTsV>vtjHU*`vV`TeEjh&}BbM$$ee1*J#>RV=ZZ4P)oX1`Uqbn!S61E_>>d%XzTm)b$zLoAqmL5PS1DU)$K% zY~+VMrLe)@JwEoZVu{skPOfy>purJav*vOlzFoQD`Wb$!P6X8l?l#NIr5ZX0`g zl8wxNWlvo+&SOqpziDsncMyB$(ns6a*KFj6 z{dIbk{nhc&t}m8Y&F1DxmpvLBu{C@51YP#jC71JH$*Jozwm0k7+93Ak(R16_)01pu zj{RM9+22;yen+vyYBr3WBO5e0Vy*99sLP(ZXq?BKx_;B%+V3Ft&ZUpGv9H<44|{KV zmHl1u(SBbnv6>BI=g1xnj@X*Ldx9=|>XOTOu;kSB8QYunYi$sF^EhAI*w<|2hrK_& z%KpBxb~Ix(n_8C*8XU1Td(NjWdviGtF>>nqjP1?(wKj;od7Ptd>}xi1#Xgu`W&c1~ zyOvnZhOu*Gg9b-z&0fyvvZpS&T5{_8jP1?(wKj;od7Q6p>}xji!}7Z~*^|>BtJ#q2 z9ND136I-*Vmb&cKYFpQ@&u{%&8^qo``e+;bnhn2$V=PD6qZ!lIZ0fjd&}3Y*uXWki znsfT=+f!X%Z4i5En>U>7S?d-#*2;Sn`CZy4V(E?7JK)#ab|pqGInF^h58HoWu7-}ss`3H53V^QpuCx6$TH4zZUKGspUl?Tz|>Ep^nI9`iZZ z-rB@ojt%}jD35oG1ePQG9Cu63 zA7eL-9m+}UmG;(to7hu}YslW(#9ofFalAvA?Vp}uvrhb-<8KnXXRI;VuUT@@zneJh z$vr+kF*NJTT%G!hC+D=}aJxDt)*S0I<~opHy|?z;#NN5~)+Y9Hl#Sz)vR?iM18nw; ze^~ra$MW|RjLGKEl8b(0;;=b7{`v8Vp;=$%>eT&sl7`rk~>Uz4*->|bKdu|8w21Nqf^YrjqGoojDxVlPM8I6h^? zd?sVo3!8=GUlM<(*h^!L$>zk8i~f(qVe^&vcgH7&W__8fQ-Ay9Jd>O;u}{aEV|~V4 z2lA`;)_$AVJJ;UY#9ofFalBrBzJncXej6rN$DcjgFJq0#=B*_ceeO5)*smIYVseS0 zSzqSr)So6f(YX2ZYOFcdXUugVzj|-&w~4)T?X6Ah z?MXII6=vvv%6egg|C{*O`(w!=CL7p2TaxG51Wd;_d)dPo?a9G(r9Ot7&%@u z= zD?L6OOV6;sF8&_z?}*)^#K@5ixs2ytInP(c!sexDn^l_iVNMRY>;d&>h`%@UVh@jX z53O&H>h<0lYhv$uJYSpG%S|?nr_1^m3--(?q*8Q@+J*wAxYpjXA>+yVTVlOw@Fuo=nZ;pj0Y&I?07pfRJvLV+wQ->XF z&>kpt(5w%GsWK+c9#H>_@yXe|#N03I+oO8Dx5k>-*X!YYZDKDs*)aZbm>s-ok0)$q zD*lGW5+g@8jt`5@&&{y;bbOx2R;%ligAQ-%Pl(Tc%v>~jAZC4gRPWzg_PvR{>+yVT zVlOw@F#dMdGUsYNzOcDC+7F}sF_z~+iIF24$BRe5KRRsQ93LiX)`tN(=swT&Tr{5Z z{&6hN8@gZCw@3AQZ;dsvcRil3P3+|+8^*_E{S#v03;QMFe_t^bQj2zjJ%lP!zFUG>=sQ3p~n)P8o4!P_B^^cE#M*Kr!FN!6HnDyzY zX>W}+u_tbC)NB)bxygp{`1JVs(lcxhjK6)f&&0l~#K@5ixs0zZaoC?7fBj0cKFp~> zE_*=ztK#n#|AN?hzpQVMFSobGn%KJ@&(|jQa+3|?XWp34y^Dn>Y>tb+SbVhEiX}%j z=!|bE7WNnRY1W5$R~{ zvbW=A>b=*0tC{nAu)e)D_MhC_k=H-}d)L6^?(Gpd&9Cx$P5x%!|Kt}0H{|c3)wf$? zxk)$PZg))VUq7pOOy`;CkL0*E2cJpH7<+HA561o>$K>3Pk6aG{^>2Jl?)AXuN4{ffjE7~1zSxdzrAwMst6e3M)SV>-*{YFIlX?jIKKye;<_Yvc;q zAQ_u@!MlF%^EtkF@kG(R-eK~%T<6}7< z%7M<|wRd&=eRJGhbYocbqjGGWdfaz0=dv7s$w8cJm%3cL#5fP5AAzw zY%G^g=)5j2 z0RE9TPn*QQB-aM} zfKQ)l^iPajt?MukJKXDWALx;u?}%j|?Avu1Qy=cW*#~<1O8VutO5f~5tr=r&=C}^5 zYbI~F*TX*0qxVB|WhZ+>hcDyEL&EV!s+Y zWA1OwbsenB{5GuT{`C6BrSn>otYOz>dh5ZT5RG3RpgonG39;lZAA3#W%(*po`7)RM zHmoOIcfXhI5IZ(KrNs{Z#o^9%hnA;6x;Cb37mg*qPO;_>_j>4;FMEDldguO%FEuSO z_2KTD+X;-PO;2}a1L%!?s5N8sZw_&C-5>LZdp+y}Jx-tA{#4e(KG-*wbr2&*eYpE( zAMPHV=lz!K^|p3;ON*Tw@;`iHi{>+c9*dnJ_8(QQ>tJ2xkImc}a}4L>!Y9)ETk|UFdDt2Yck2{zQ6WA8L(0iNW6-;^bn{&2Phc z_*;4O#NX80FP8P-*BXCEj~KaH;^^jK+pr$~Rvx`v6YF~LYmL97M~qx8adh*rZCDR~ zE013In|iJXzt;FWdc?@p5=S==JDlqopX(}jT|<9g@2ETn^!D^LI@-7#j*pH0&geYP z^7;51#y=)@<5**PnB0AA$=}kW20H8GJ_HTF-&()vH8K6Q+QiCr%gXT=v(`stom!UjTP&z zSuti!?}?R_+J99sS?!rz<2xkobp<10XkJ&;CAW!Hf33E$f=SJaF`pZ}Z7i(t)!tjh zWVL%0-!bu;6)`ke!OlHsV%1-(O{`=hE5}&YCM)i<(X_;5#b-RjmH1Avvf_Foh9)cP zH?iuk)izeFyJp3hHSH2BE3OT+|E^-N%8%Av9^^VFzwYR=L1XP$>&s4^`uOiFxzsnO zu5V9pw?2EpIf)Ho?_Bz58~d7#{IGkaSK04g*7@OLiPdaAQt7h!Xf!wytJ%9J=(69V zSOrLNB$d$WG64PtK|J-3ZLJ;_Gq*nOkRe($pOeTpSkvoVe?8*<@D%=+$yy6ouz zt=_M?e$(FC?;!ThrMI@RrzhFS9Q*O;vj13oG%c~34K~RI_Kyn)o?a_O)iLX5*ePNA}EtF){1QTwV6{KABV3Z`xb;dk}l) z(p%fu)01rEirqiD?8)hm)of(XoL6EmXKX+FI`(q)`}fwK2C=VuYa4rb$)3lzjBEC4 z{kCSqHEvw?aN-&!W__=Bb=lXq5p(MLH9zY!$3FirvX_@^9BW~t-*0O+Q^H=(*nakP zY;x+`(;)VBZ*98n?R|uO@AZ=TyvF9$vx{d(!8 zmxksL8=s?oK6ZqC@AcS=g$u7$9bw=59x-yCGje}lUV|`n|M9=Q&*6I;zsu(DZ}B`9 zf2WJbBmB-0zt;HMT*S!L5=S==TiquP-4AlxeJyUsu7|(BMKAn)F4u#GZ;ZdqWsa6O zx_Q_(tY?o@diHJ@R+DTn~P&@wd5%k*g(+ZXUJ` z`@`Siq8I)?m+Qf=HU2giF>w55Ojn5S!My{4Px_MZyx9O|L ztnB%D&&*b=fj)!v8F>>$C zfhCW8{QYyBkYj_?y*Cz}+EZstE$WbSUk>uG&v9=KYCMvIbD-11y~QVod~%49L#?OF zm|T6{3wv+I9Kk*EUeqvnHNPhJ_QB66e9q2Xd91W=?yx524L#Yap)X@-O}CGCCzfw_ zo%xb9vbRI%UNvV*_Lk4tnLm5WXYfq5+&}NFu_@i#Lj3 zdCh^^?IlJoInF^h59_r$9P8v$wXfhmmaT z@%LHVd!oyJ^RmvZV~xq?jFOAKN8+&gar~X*6GO8;EI6M!^+LDX@ zwZvg_XZ$1M6GOAU%+;xXWpYkR&Ly$O#+qY&##{&TtM}G^o7g+o-rB@oj?Im~6ORaNVL`fX$qzqJ23&F*NJTT%G!NBgXi^}^=Tuz4u{o1$?I8c_=R6C=nqz&&TnF-ly?blFP3)a(Z*5{PN7*<&E>9ZI77nmka*m$A zLw>kMGbS6y*mork8~kNUE}HdaZZ7q=OI>mn%XzToSf4T1f&9AHec4<4ZDQ|S&(|jQ z^aM}YIQ~{XfMJ>Fu=&NCdO0u6*R#fCb9%`||3K!z=8X6g;uAxw>%&)_`p>5>+Rt+y ztemWGPwM@9OaD#moojDxVlPM8IKD2gD|koN1e@98kBh%|>>9DgWOH@NML#rg*jyWb z*Z9QHtS@tQ>hF=9{gX3O>_=kFu|8w21Nqf^YrjqGoojDxVlPM8I6ikw-v5^M!e*iP zo5%l9?2fU&uc3!59lWWV@-j6DRc#ANe$^lonSpC%5Q=c0W(J~1@w%UqrM zw6_S?kXx%Sp3_HvYs;~m1` zNAL)nP2!&)f1B7#V~xpXrIL&Oc;c|%IR5SNiJ@6v=IYd6E;)}RXQ|i+W6iNXW3B`F z)q88dP3)a(Z*5{PN7*>uJL|n8>xIp3@vn{lq1YQ^jmc)+l8gTL#9{N^`0yl#W__8f zQ-7`GJe{2Ju}{UCV|~V42lA`;)_$AVJJ;UY#9ofFaeQ#r``i!{_7#JJDIa&GI}qk6r!#s;ycSNfo4o7l@u zHjMdx{GM2PhRwU<^VndESRN}7BS$ulkBUAqI&AhTbJVO419H&W1L}V^K93EKh~=?@ z`(=H5RHwdsYpjXA>+yVTVlOw@Fy?XShhu$gykmSG6Ym3-bm+{%L{yhHW`20MsW_=itgU%kn{`C0#EO=@xw=eh0`u3;}d-v8@6MNU= z`P#%@Zn9y_^A6X?!V@+p$3HFpd9gevLW~^QIKD4B&-K9O_W0k9uV#H1kb}-1P@nlX z#J@C_+lu>TeS1`=zI$t|iM{Lbd~IScH`y@e`R4@}D$o67oexIixxcBR?N?&t$c9|T z%f_-_Q)kW+@p=AL&H6AP2c12D{p|61?(ez8crMWWvc5g4Q{TNc*2LcRc)m8Vmz!)D zza#4(wQ!FoY<7&cW3+Q(c@CTyIkIs)L-a$V!)Ds}{N6#$`Y<2|-P_g0(Rj{#k64}q zcfYJ}kLuKSZ;dsvcRil3P3+|+8^+6I{fjQr<2y~(`JQO}uIGwae)mI+9N9QtGP=KS zTRi@RspJ*W>xx#9nT)VLV&bze-+f z3}4vXn1<0tEj}s6ST^K3hu>Ag294h{W6`V+1IFm=0rf|xF51mG57zy%zCEf_-@P@~ z#J*k+=gTRE?K9i^f3B6AY#2Y2->0vb$Jy|N&8|!L{Ntjd5hF)7j#rJoLgKJlIsP2+ z)$01>pu?H^UrH_f_vbuV_sjbBsNTP~^wh-O^?1HEv6q`{7~d5Zn=aSm3!77;{W;q6 zvAp(*7&)?WyiN2sh68N2h(9qoYSxDVIq2*G^{0uyaQts1wsfrfWqo^8ulLqi6MNU= z`P#%@Zn9x~VVEtke2*_|z8Q_z#yuW;O^J~s8*&-168lsvY?h6GOQl&K2IP>-9#DT` zv`+l*#?BP$ep%lh)$6@A*2LcRc)m8Vmz!)DpBgqFi-jj_Hi-Y-_&dh(8e3xI$j0$e z(Ql6qn?vGX7GKT!Fdzq=J)r*H@$Zelb?l?D?xFSVQN7+Q`kLPO>d%4Mm@u#!? zb7SEP8~Q#W{#Ro^Ut;9QhFr${z3Pi%VRL1C=BrtsTI8U!2h_hJ{!ikc8GA!4ImE1Q zkLvZ_8f#+jdOTm7*vm~ejQ7pDuZo2yY<>{`!1$NN?q6c$$c9|TkHnrH3!7WwA604A zhXFa{UKC6Hd*h!S|2MJUk9EJSZ;$Hr-WqFS?|M96o7l@uHjH=A`mc+HCv2{c&+GR2 z{D=>g7&)>bm+|wl@P^F;@eimp>%)K?a@hmwKO6t}_)o^366+pX-yYTLy*1Xv-t~CC zHnEqRY#8s5_1_c=PuTo2{;u)4?s%^fF>++%c)EP%2YUpY$CI;Ld^PLCfE;x8fcmeC z&pu5ZduXhCXnlKBulLqi6MNU=`P#%@Zn9y#Mb>|F;R_r5_ZDrNV#$#WamF);9TqlE z_G#9Kfw}Af^_j=}&}NFQ_sjbB=swnaYpjXA>){-nuTAXbCL4O4kRH`#zgf|Euc0|L zn>C})nDsFiHczC^`b8sVeR3GPPt=F`21R>k6|=s*IH%rQV}sb&=ac>Pc?(W{obLXN zOAnjnm@rlES{V777TqEn?1^e9PE4l z*Pam;$Y*Qt_uf|R_-&4n>n9Li<*&)Teojjtf6Dc-EUY#+W%{#kvKHAy6v#YTYTL`?|b#mHirwy^^etnB_ zjG3+XIVkJq&ZPfyP>g}U={k9LVtLweHwaA*1y}dK<-Q#xq!uetW?Z|9ZPMHnO*q$Nja)nv%W!$kM&r?QzTe>+ROq$lksd zyEb{}n3BESA+L?#KKWpN{^|P}$k>$bZSsenBV}%$VtLj7rieeY-!(d~q0bY3^W;h3 zBXdlfbK}?A#N-eoS4$k-JnY!aoiWF7uIH!I^?I5rPdvLGeEL(nKRLw6)e=WHuPy62 zC!ak^FOSB$9{gInuEfYC$2sWcwPiiW=lLOexjEML;MW?TtwW4lEpc@7u)}%1^}lxR zk~#A}p!AfRMEA2t9bX!qUb(&XYsRwF?%$gIM9D?}Oy=ZY=PSi0hGu=oTI%cf+qynI z(nnpN{_L&k_dC>NuD!L1y&PrZ*j{1NuNkY^zy$q>*!=q^_Gs3x`J&4npO}_?TYxeR*mp${z)sj=! zZ`xb?9mL+boUd){S+8tljy)#2>^~PD?eoPFtJyFner#<1b=jlA6V3YWg}Usii^h4( zsp~iGt^E#S?_Bz58+#bZM&{TPqs#t_@zIVimRQY(G4YdP^RLSuAC6e-%UoUdCzM>y zV@_SaX>aX!5PRp+N88xLO*S&eej~codpR;tuVt+93AMrH{6;ui3~C`}Kg4{cLg2wk(!d&4#gaWP=7rY|Y+1LC?Q# z4t2@pJXmt-`i$+(`n5KQy?LCkZR~3{^22^6z+i*F>ZqRmYq7*?HjJGk8#Fj#^RN4} zn|q;7eSGR-IgdGYeR{Mv>(|;K_U6&Y*qm>;o=55bxmI4Xag2Q;qU_I!k9K3R#A-H- zog*7GIAZf}h`oD)E_>>d%XzTm)b$zLoAqmL5PS1D-`JM1ui3~CyLJ{Y`#Y-;dAx2Kzq56#N&HA-Ah`o9AJho-*=_yO=vXMD< z`{=UYI6m5z#S+WEAvTPiBO5e0Vy!Q8b=gxFjq{ijcc^~T-rDaV_Rgh`wz03-$Pc@3 zdX@eAV#C-uvO$9**81*+y6mZo#(B(%J5;}EZ|!#wd*{+e+t}A^ zpy~_Te_-Ka|ODz9}*f4gE?9t$et=YRL=(49Sxts?}PW}zmXKZiQueCw!&EtG+ zV_&n8ANKI{D*MCA+R==~9b!}KvO$9*wr0=y)Malj=OIQ;{teYoUd){ zYc}%3^1C?MU0-bwdup3Eoa|XE?@`!!p5E_czaC3(yxswy z-><11Qexzi;~aGJux(h+g!y~VRUaAadhmG;Q|$vKMlLzdK{pTEhV`tlV6Ue=V_gqE z{i$tQV&szJ9CY*AvYvSZm1||2Sl5GJYpa$Rx#Tzp-MqG3Z__N%>uK#+*Mm=gY73Sa zx#Tzp-MqG}=a#&li(Y13Zqj=2YwfAzunuyy#L>;eX1j*%c{}glE+5zH>A6_<2cQ1b zep_PXlH(k7^V+f=K7ZkbIr3RwdGB&3_rKg<e3*f#7Be@A)UyuppX zv&{RpSr2}#@i&%p5+fUQhh}T-Sq7e`;5j7`fy)2i?53tmlX~^m@7` z*7e}ipW2xvMlLzdK{u~0>)CVeUQg%7x*mM`Q#-oE$R)=)=;jUgdisAaas0fU&N^Ac z=-hsCx7BfcLUelN{;*#&mb<*}&lTI0T=exaCwGyZeTz>F&H9eD)YtE~b$xoIkGekn z+1nba^ZFcoEER_Z8&f1<4bQ@MrYO>a+Hl@dxcHEW~^od6ZE&m_OnN` ze$5wM_V~oK)T`^m+4I)*?QIZy=Tf_E?Ca~&^jkd~&tq)b*S8)_w=EcP{5^8++C(8<}G_jxPJR$4A?+SYkCB#>6MY${r1#Xx4Wx z)MZayG|ppAUB78>?ROA+=h8>p*uzLRGRJNnUH0#akM{0jiPdZv6W=0M_V{qbT3_bs zvfs4iavpQ)`b~Rlzk}F2mp*!tIM9c zXq?BKx_;B%+V3Ft&ZUpGv9H<454&G_mHjU9(LPixv6>BI=g1xnj@X*Ldx9?e50~6s zizTP7&)D9qUu%Qdo5%Uu#=d4FKkUirRra4QYd^YJVl^Aa&XElo?6Ea_&ZjPW>Y{NT z_p7eY9DB2Vtqo#t9(}Zpea%LG*zJ~@#Quh|_SvEttJ#pNE*msBVr%y9iS@~$E|&9P z$*Jozwm0k7+93AkalW>(ui3~CyWTRB*gu`V(Y}}WyBe$6kgF~mG&o{w_MA`M>z=x3 zoCixzU7s=avDUA(LF~<=kG8R|*~kxjc6#+bXSeuhpDUJF&4#gaWP=7rY|Y+1L6<#s z$>ls)a_ahw?alhNHi*4>oUd){Yc}%3KA&D?|BJHrhl(Xuv-wA*%LWaO*qS}(QY{NTbL#p{duzXg*gKa#+QziUeSkF|cS4PtK|=W84LnvMLh>!w%PuT$2JW~^pY>#{+EBerJG`P9Ac&E-7A$f@fy zwm0k7+93AkagMgJui3~I`?mBd`}NA&wZv*RjGZGJG&o{w_Hss-J$1>|l2g}bY;V@D zwL$F7<9uynU$c=PmfyX}o}B(z&4yg($Oa9b*qS}H)Mc+$+q!;ze(TrTAok|bN88xf zZ1^1!wm&6u`kQ^#e4CgYlYt;@dFoYP<5p6dE)gVK@3xI8E1dhly)&JrV+9Os~$*Ou$;p7cjA^SyP_ zdhl!Qh2*dfa<#hBbOZKpqtm0^_;j`ucupMT@OC} zsa;rN9$rJYU3%v=b~~omX>)&#Uu(Rsju^RG;^^jKXU^Qb?5_L8>qhYZ EAC2%MZ~y=R diff --git a/serial_.odg b/serial_.odg deleted file mode 100644 index 9e2ecc0179fc27647a15ddad740bc2a7fada23f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11640 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 -Данные**ЗаголовокПолезные данныеДанные**Заголовок следующего пакетаПакет принят верно (функция возврата возвратила истину)**ДанныеПакет принят неверно (функция возврата возвратила ложь)**Поиск заголовка в текущем пакете********* \ No newline at end of file