/*! \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