[Timing Stats] Add duty cycle column + LoRa TTN on air timings

This commit is contained in:
TD-er
2020-10-13 02:08:23 +02:00
parent 29abb5dbba
commit 0100d26080
9 changed files with 188 additions and 26 deletions
@@ -242,6 +242,11 @@ String rn2xx3::peekLastError() const
return _rn2xx3_handler.peekLastError();
}
float rn2xx3::getLoRaAirTime(uint8_t pl) const
{
return _rn2xx3_handler.getLoRaAirTime(pl);
}
String rn2xx3::getLastError()
{
return _rn2xx3_handler.getLastError();
+41
View File
@@ -221,6 +221,42 @@ public:
* This can be overwritten by the network when using OTAA.
* So to force a datarate, call this function after initOTAA().
*/
/*
EU / CN
Frequencies:
EU 863-870 MHz (LoRaWAN Specification (2015), Page 35, Table 14)
CN 779-787 MHz (LoRaWAN Specification (2015), Page 44, Table 25)
EU 433 MHz (LoRaWAN Specification (2015), Page 48, Table 31)
DataRate Modulation SF BW bit/s
0 LoRa 12 125 250
1 LoRa 11 125 440
2 LoRa 10 125 980
3 LoRa 9 125 1'760
4 LoRa 8 125 3'125
5 LoRa 7 125 5'470
6 LoRa 7 250 11'000
7 FSK 50 kbps 50'000
Data rates 8-15 are reserved.
US
Frequencies:
US 902-928 MHz (LoRaWAN Specification (2015), Page 40, Table 18)
DataRate Modulation SF BW bit/s
0 LoRa 10 125 980
1 LoRa 9 125 1'760
2 LoRa 8 125 3'125
3 LoRa 7 125 5'470
4 LoRa 8 500 12'500
8 LoRa 12 500 980
9 LoRa 11 500 1'760
10 LoRa 10 500 3'900
11 LoRa 9 500 7'000
12 LoRa 8 500 12'500
13 LoRa 7 500 21'900
Data rates 5-7 and 14-15 are reserved.
*/
bool setDR(int dr);
/*
@@ -287,6 +323,11 @@ public:
String peekLastError() const;
// Compute the air time for a packet in msec.
// Formula used from https://www.loratools.nl/#/airtime
// @param pl Payload length in bytes
float getLoRaAirTime(uint8_t pl) const;
bool hasJoined() const {
return _rn2xx3_handler.Status.Joined;
}
@@ -441,6 +441,7 @@ bool rn2xx3_handler::setSF(uint8_t sf)
if (dr >= 0)
{
_sf = sf;
_dr = dr;
return setDR(dr);
}
}
@@ -590,10 +591,10 @@ bool rn2xx3_handler::setFrequencyPlan(RN2xx3_datatypes::Freq_plan fp)
default:
{
// set default channels 868.1, 868.3 and 868.5?
returnValue = false; // well we didn't do anything, so yes, false
break;
return false; // well we didn't do anything, so yes, false
}
}
_fp = fp;
return returnValue;
}
@@ -697,6 +698,56 @@ bool rn2xx3_handler::getRxDelayValues(uint32_t& rxdelay1,
return _rxdelay1 != 0 && _rxdelay2 != 0;
}
float rn2xx3_handler::getLoRaAirTime(uint8_t pl) const
{
uint8_t sf = _sf; // Spreading factor 7 - 12
uint16_t bw = 125; // Bandwidth 125 kHz default for LoRaWAN. 250 kHz also supported.
uint8_t cr = 1; // Code Rate 4 / (CR + 4) = 4/5. 4/5 default for LoRaWAN
uint8_t n_preamble = 8; // Preamble length Default for frame = 8, beacon = 10
bool header = true; // Explicit header Default on for LoRaWAN
bool crc = true; // CRC Default on for LoRaWAN
if (sf > 12) {
sf = 12;
} else if (sf < 7) {
sf = 7;
}
if (cr > 4) {
cr = 4;
} else if (cr < 1) {
cr = 1;
}
// Symbols in frame
int payload_length = 8;
{
int beta_offset = 28;
if (crc) { beta_offset += 16; }
if (!header) { beta_offset -= 20; }
float beta_f = 8.0f * pl - 4.0f * sf + beta_offset;
bool lowDataRateOptimization = (bw == 125 && sf >= 11);
if (lowDataRateOptimization) {
beta_f = beta_f / (4.0f * (sf - 2));
} else {
beta_f = beta_f / (4.0f * sf);
}
int beta = static_cast<int>(beta_f + 1.0f); // ceil
if (beta > 0) {
payload_length += (beta * (cr + 4));
}
}
// t_symbol and t_air in msec
float t_symbol = static_cast<float>(1 << sf) / bw;
float t_air = ((n_preamble + 4.25f) + payload_length) * t_symbol;
return t_air;
}
void rn2xx3_handler::set_state(rn2xx3_handler::RN_state state) {
const bool was_processing_cmd = _processing_cmd != Active_cmd::none;
@@ -189,6 +189,12 @@ public:
bool getRxDelayValues(uint32_t& rxdelay1,
uint32_t& rxdelay2);
// Compute the air time for a packet in msec.
// Formula used from https://www.loratools.nl/#/airtime
// @param pl Payload length in bytes
float getLoRaAirTime(uint8_t pl) const;
private:
RN2xx3_datatypes::Model configureModuleType();
@@ -259,6 +265,7 @@ private:
RN2xx3_datatypes::Model _moduleType = RN2xx3_datatypes::Model::RN_NA;
RN2xx3_datatypes::Freq_plan _fp = RN2xx3_datatypes::Freq_plan::TTN_EU;
uint8_t _sf = 7;
uint8_t _dr = 5;
bool _otaa = true; // Switch between OTAA or ABP activation (default OTAA)
bool _asyncMode = false; // When set, the user must call async_loop() frequently
+23 -3
View File
@@ -18,6 +18,7 @@ void handle_timingstats() {
html_table_header(F("Function"));
html_table_header(F("#calls"));
html_table_header(F("call/sec"));
html_table_header(F("duty (%)"));
html_table_header(F("min (ms)"));
html_table_header(F("Avg (ms)"));
html_table_header(F("max (ms)"));
@@ -35,6 +36,8 @@ void handle_timingstats() {
addRowLabel(F("Time span"));
addHtml(String(timespan));
addHtml(F(" sec"));
addRowLabel(F("*"));
addHtml(F("Duty cycle based on average < 1 msec is highly unreliable"));
html_end_table();
sendHeadandTail_stdtemplate(_TAIL);
@@ -56,17 +59,34 @@ void format_using_threshhold(unsigned long value) {
void stream_html_timing_stats(const TimingStats& stats, long timeSinceLastReset) {
unsigned long minVal, maxVal;
unsigned int c = stats.getMinMax(minVal, maxVal);
const unsigned int c = stats.getMinMax(minVal, maxVal);
html_TD();
addHtml(String(c));
html_TD();
float call_per_sec = static_cast<float>(c) / static_cast<float>(timeSinceLastReset) * 1000.0f;
const float call_per_sec = static_cast<float>(c) / static_cast<float>(timeSinceLastReset) * 1000.0f;
const float avg = stats.getAvg();
addHtml(String(call_per_sec, 2));
html_TD();
{
const float duty = (call_per_sec * avg / 10000.0f);
String duty_str = String(duty, 2);
if (avg < 1000) {
// Unreliable as average is below 1 msec
duty_str += '*';
html_I(duty_str);
} else if (duty > 10.0f) {
// Over 10% of the time
html_B(duty_str);
} else {
addHtml(duty_str);
}
}
html_TD();
format_using_threshhold(minVal);
html_TD();
format_using_threshhold(stats.getAvg());
format_using_threshhold(avg);
html_TD();
format_using_threshhold(maxVal);
}
+22
View File
@@ -268,6 +268,13 @@ struct C018_data_struct {
return sampleSetCounter;
}
float getLoRaAirTime(uint8_t pl) const {
if (isInitialized()) {
return myLora->getLoRaAirTime(pl);
}
return -1.0;
}
void async_loop() {
if (isInitialized()) {
rn2xx3_handler::RN_state state = myLora->async_loop();
@@ -809,6 +816,21 @@ bool do_process_c018_delay_queue(int controller_number, const C018_queue_element
bool do_process_c018_delay_queue(int controller_number, const C018_queue_element& element, ControllerSettingsStruct& ControllerSettings) {
bool success = C018_data.txHexBytes(element.packed, ControllerSettings.Port);
if (success) {
uint8_t pl = (element.packed.length() / 2) + 13; // We have a LoRaWAN header of 13 bytes.
float airtime_ms = C018_data.getLoRaAirTime(pl);
if (airtime_ms > 0.0) {
ADD_TIMER_STAT(C018_AIR_TIME, static_cast<unsigned long>(airtime_ms * 1000));
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("LoRaWAN : Payload Length: ");
log += pl;
log += F(" Air Time: ");
log += String(airtime_ms, 3);
log += F(" ms");
addLog(LOG_LEVEL_INFO, log);
}
}
}
String error = C018_data.getLastError(); // Clear the error string.
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
+1
View File
@@ -228,6 +228,7 @@ String getMiscStatsName(int stat) {
case PARSE_SYSVAR: return F("parseSystemVariables()");
case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change");
case HANDLE_SERVING_WEBPAGE: return F("handle webpage");
case C018_AIR_TIME: return F("C018 LoRa TTN - Air Time");
case C001_DELAY_QUEUE:
case C002_DELAY_QUEUE:
case C003_DELAY_QUEUE:
+32 -21
View File
@@ -54,26 +54,33 @@
# define C018_DELAY_QUEUE 33
# define C019_DELAY_QUEUE 34
# define C020_DELAY_QUEUE 35
# define TRY_CONNECT_HOST_TCP 36
# define TRY_CONNECT_HOST_UDP 37
# define HOST_BY_NAME_STATS 38
# define CONNECT_CLIENT_STATS 39
# define LOAD_CUSTOM_TASK_STATS 40
# define WIFI_ISCONNECTED_STATS 41
# define WIFI_NOTCONNECTED_STATS 42
# define LOAD_TASK_SETTINGS 43
# define TRY_OPEN_FILE 44
# define FS_GC_SUCCESS 45
# define FS_GC_FAIL 46
# define PARSE_SYSVAR 47
# define PARSE_SYSVAR_NOCHANGE 48
# define PARSE_TEMPLATE_PADDED 49
# define RULES_PROCESSING 50
# define GRAT_ARP_STATS 51
# define BACKGROUND_TASKS 52
# define HANDLE_SCHEDULER_IDLE 53
# define HANDLE_SCHEDULER_TASK 54
# define HANDLE_SERVING_WEBPAGE 55
# define C021_DELAY_QUEUE 36
# define C022_DELAY_QUEUE 37
# define C023_DELAY_QUEUE 38
# define C024_DELAY_QUEUE 39
# define C025_DELAY_QUEUE 40
# define C018_AIR_TIME 41
# define TRY_CONNECT_HOST_TCP 42
# define TRY_CONNECT_HOST_UDP 43
# define HOST_BY_NAME_STATS 44
# define CONNECT_CLIENT_STATS 45
# define LOAD_CUSTOM_TASK_STATS 46
# define WIFI_ISCONNECTED_STATS 47
# define WIFI_NOTCONNECTED_STATS 48
# define LOAD_TASK_SETTINGS 49
# define TRY_OPEN_FILE 50
# define FS_GC_SUCCESS 51
# define FS_GC_FAIL 52
# define PARSE_SYSVAR 53
# define PARSE_SYSVAR_NOCHANGE 54
# define PARSE_TEMPLATE_PADDED 55
# define RULES_PROCESSING 56
# define GRAT_ARP_STATS 57
# define BACKGROUND_TASKS 58
# define HANDLE_SCHEDULER_IDLE 59
# define HANDLE_SCHEDULER_TASK 60
# define HANDLE_SERVING_WEBPAGE 61
class TimingStats {
public:
@@ -109,7 +116,7 @@ extern std::map<int, TimingStats> controllerStats;
extern std::map<int, TimingStats> miscStats;
extern unsigned long timingstats_last_reset;
# define START_TIMER const unsigned statisticsTimerStart(micros());
# define START_TIMER const unsigned long statisticsTimerStart(micros());
# define STOP_TIMER_TASK(T, F) \
if (mustLogFunction(F)) pluginStats[(T) * 256 + (F)].add(usecPassedSince(statisticsTimerStart));
# define STOP_TIMER_CONTROLLER(T, F) \
@@ -118,12 +125,16 @@ extern unsigned long timingstats_last_reset;
// #define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince(statisticsTimerStart));
# define STOP_TIMER(L) miscStats[L].add(usecPassedSince(statisticsTimerStart));
// Add a timer statistic value in usec.
# define ADD_TIMER_STAT(L, T) miscStats[L].add(T);
#else // ifdef USES_TIMING_STATS
# define START_TIMER
# define STOP_TIMER_TASK(T, F) ;
# define STOP_TIMER_CONTROLLER(T, F) ;
# define STOP_TIMER(L) ;
# define ADD_TIMER_STAT(L, T) ;
// FIXME TD-er: This class is used as a parameter in functions defined in .ino files.
+4
View File
@@ -10,6 +10,10 @@ public:
LongTermTimer() {}
explicit LongTermTimer(bool usenow) : _timer_usec(0ull) {
if (usenow) setNow();
}
//explicit LongTermTimer(uint64_t start_time) : _timer_usec(start_time) {}
inline bool operator<(const LongTermTimer& rhs) const