/*! \file pidiagnostics.h * \ingroup IO * \~\brief * \~english Connection quality diagnostics * \~russian Диагностика качества связи */ /* PIP - Platform Independent Primitives Speed and quality in/out diagnostics Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIDIAGNOSTICS_H #define PIDIAGNOSTICS_H #include "piqueue.h" #include "pitimer.h" class PIP_EXPORT PIDiagnostics: public PITimer { PIOBJECT_SUBCLASS(PIDiagnostics, PITimer); friend class PIConnection; public: NO_COPY_CLASS(PIDiagnostics); //! Constructs an empty diagnostics and if "start_" start it PIDiagnostics(bool start_ = true); virtual ~PIDiagnostics(); //! Connection quality enum Quality { Unknown /** Unknown, no one packet received yet */ = 1, Failure /** No connection, no one correct packet received for last period */ = 2, Bad /** Bad connection, correct packets received <= 20% */ = 3, Average /** Average connection, correct packets received > 20% and <= 80% */ = 4, Good /** Good connection, correct packets received > 80% */ = 5 }; //! Information about current diagnostics state struct PIP_EXPORT State { State(); float immediate_freq = 0.f; float integral_freq = 0.f; ullong received_packets_per_sec = 0ull; ullong received_packets = 0ull; ullong received_packets_wrong = 0ull; ullong received_bytes_per_sec = 0ull; ullong received_bytes = 0ull; ullong received_bytes_wrong = 0ull; ullong sended_packets_per_sec = 0ull; ullong sended_packets = 0ull; ullong sended_bytes_per_sec = 0ull; ullong sended_bytes = 0ull; PIString receive_speed; PIString send_speed; PIDiagnostics::Quality quality = PIDiagnostics::Unknown; }; //! Returns current state PIDiagnostics::State state() const; //! Returns period of full disconnect in seconds and period of averaging frequency PISystemTime disconnectTimeout() const { return disconn_; } //! Returns period of full disconnect in seconds and period of averaging frequency void setDisconnectTimeout(float s) DEPRECATEDM("use setDisconnectTimeout(PISystemTime)") { setDisconnectTimeout(PISystemTime::fromSeconds(s)); } //! Returns period of full disconnect and period of averaging frequency void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm); } //! Returns connection quality PIDiagnostics::Quality quality() const; //! Returns receive speed in format "n {B|kB|MB|GB|TB}/s" PIString receiveSpeed() const; //! Returns send speed in format "n {B|kB|MB|GB|TB}/s" PIString sendSpeed() const; EVENT_HANDLER0(void, start); EVENT_HANDLER1(void, start, PISystemTime, interval); EVENT_HANDLER0(void, reset); EVENT_HANDLER1(void, received, int, size) { received(size, true); } EVENT_HANDLER2(void, received, int, size, bool, correct); EVENT_HANDLER1(void, sended, int, size); EVENT2(qualityChanged, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality); //! \handlers //! \{ //! \fn void start(double msecs = 1000.) //! \brief Start diagnostics evaluations with period "msecs" milliseconds //! \fn void reset() //! \brief Reset diagnostics counters //! \fn void received(int size, bool correct = true) //! \brief Notify diagnostics about "correct" corected received packet //! \fn void sended(int size) //! \brief Notify diagnostics about sended packet //! \} //! \events //! \{ //! \fn void qualityChanged(PIDiagnostics::Quality new_quality, PIDiagnostics::Quality old_quality) //! \brief Raise on change receive quality from "old_quality" to "new_quality" //! \} private: struct PIP_EXPORT Entry { ullong bytes_ok = 0; ullong bytes_fail = 0; uint cnt_ok = 0; uint cnt_fail = 0; bool empty = true; }; friend bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); friend bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); friend bool operator<(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); void tick(int) override; Entry calcHistory(PIQueue & hist, int & cnt); void propertyChanged(const char *) override; void changeDisconnectTimeout(PISystemTime disct); PIQueue history_rec, history_send; PISystemTime disconn_; State cur_state; mutable PIMutex mutex_state; }; inline bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) { return f.bytes_ok == s.bytes_ok && f.bytes_fail == s.bytes_fail && f.cnt_ok == s.cnt_ok && f.cnt_fail == s.cnt_fail && f.empty == s.empty; } inline bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) { return !(f == s); } inline bool operator<(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) { return f.bytes_ok < s.bytes_ok; } #endif // PIDIAGNOSTICS_H