src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
125 / 149
83.9%
Branches:
70 / 102
68.6%
Functions:
16 / 23
69.6%

Utils.cpp
Line Branch Exec Source
1 #include <Arduino.h>
2 #include <time.h>
3 #include "Utils.h"
4
5
6 /*********************************************************************
7 * Timestamp class members
8 ********************************************************************/
9 ✗ unsigned long Timestamp::epoch() {
10 struct tm tmNow;
11 time_t now;
12
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if(!getLocalTime(&tmNow,50)) return 0;
13 ✗ time(&now);
14 ✗ return now;
15 }
16 ✗ time_t Timestamp::now() {
17 struct tm tmNow;
18 ✗ getLocalTime(&tmNow,50);
19 ✗ return mktime(&tmNow);
20 }
21 ✗ time_t Timestamp::getUTC() {
22 time_t t;
23 ✗ time(&t);
24 ✗ return t;
25 }
26 2 time_t Timestamp::mkUTCTime(struct tm *dt) {
27 2 time_t tsBadLocal = mktime(dt);
28
29 struct tm tmUTC;
30 struct tm tmLocal;
31 2 gmtime_r(&tsBadLocal, &tmUTC);
32 2 localtime_r(&tsBadLocal, &tmLocal);
33 2 time_t tsBadUTC = mktime(&tmUTC);
34 2 time_t tsLocal = mktime(&tmLocal);
35 2 time_t tsLocalOffset = tsLocal - tsBadUTC;
36 2 return tsBadLocal + tsLocalOffset;
37 }
38 2 time_t Timestamp::parseUTCTime(const char *buff) {
39 struct tm dt;
40 2 dt.tm_hour = 0;
41 2 dt.tm_mday = 0;
42 2 dt.tm_mon = 0;
43 2 dt.tm_year = 0;
44 2 dt.tm_wday = 0;
45 2 dt.tm_yday = 0;
46 2 dt.tm_isdst = false;
47 char num[5];
48 2 uint8_t i = 0;
49 2 memset(num, 0x00, sizeof(num));
50
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 for(uint8_t j = 0; j < 5 && i < strlen(buff);) {
51 10 char ch = buff[i++];
52
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if(ch == '-') break;
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if(!isdigit(ch)) continue;
54 8 else num[j++] = ch;
55 }
56 2 dt.tm_year = atoi(num)-1900;
57 2 memset(num, 0x00, sizeof(num));
58
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 for(uint8_t j = 0; j < 5 && i < strlen(buff);) {
59 6 char ch = buff[i++];
60
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if(ch == '-') break;
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(!isdigit(ch)) continue;
62 4 else num[j++] = ch;
63 }
64 2 dt.tm_mon = atoi(num)-1;
65 2 memset(num, 0x00, sizeof(num));
66
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 for(uint8_t j = 0; j < 5 && i < strlen(buff);) {
67 6 char ch = buff[i++];
68
4/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
6 if(ch == '-' || ch == 'T' || ch == 't') break;
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(!isdigit(ch)) continue;
70 4 else num[j++] = ch;
71 }
72 2 dt.tm_mday = atoi(num);
73 2 memset(num, 0x00, sizeof(num));
74
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 for(uint8_t j = 0; j < 5 && i < strlen(buff);) {
75 6 char ch = buff[i++];
76
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
6 if(ch == '-' || ch == ':') break;
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(!isdigit(ch)) continue;
78 4 else num[j++] = ch;
79 }
80 2 dt.tm_hour = atoi(num);
81 2 memset(num, 0x00, sizeof(num));
82
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 for(uint8_t j = 0; j < 5 && i < strlen(buff);) {
83 6 char ch = buff[i++];
84
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
6 if(ch == '-' || ch == ':') break;
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(!isdigit(ch)) continue;
86 4 else num[j++] = ch;
87 }
88 2 dt.tm_min = atoi(num);
89
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 for(uint8_t j = 0; j < 5 && i < strlen(buff);) {
90 6 char ch = buff[i++];
91
4/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
6 if(ch == '-' || ch == ':' || ch == 'Z') break;
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(!isdigit(ch)) continue;
93 4 else num[j++] = ch;
94 }
95 2 dt.tm_sec = atoi(num);
96 //Serial.printf("Y:%d M:%d D:%d H:%d M:%d S:%d\n", dt.tm_year, dt.tm_mon, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
97 2 return Timestamp::mkUTCTime(&dt);
98 }
99 ✗ time_t Timestamp::getUTC(time_t t) {
100 tm tmUTC;
101 ✗ gmtime_r(&t, &tmUTC);
102 ✗ return mktime(&tmUTC);
103 }
104 ✗ char * Timestamp::getISOTime() { return this->getISOTime(this->getUTC()); }
105 ✗ char * Timestamp::getISOTime(time_t epoch) {
106 ✗ struct tm *dt = localtime((time_t *)&epoch);
107 ✗ return this->formatISO(dt, this->tzOffset());
108 }
109 3 char * Timestamp::formatISO(struct tm *dt, int tz) {
110 3 int tzHrs = floor(tz/100);
111 3 int tzMin = tz - (tzHrs * 100);
112 3 int ms = millis() % 1000;
113
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 snprintf(this->_timeBuffer, sizeof(this->_timeBuffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03d%s%02d%02d",
114 3 dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min, dt->tm_sec, ms, tzHrs < 0 ? "-" : "+", abs(tzHrs), abs(tzMin));
115 3 return this->_timeBuffer;
116 }
117 4 int Timestamp::calcTZOffset(time_t *dt) {
118 tm tmLocal, tmUTC;
119 4 gmtime_r(dt, &tmUTC);
120 4 localtime_r(dt, &tmLocal);
121 4 long diff = mktime(&tmLocal) - mktime(&tmUTC);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(tmLocal.tm_isdst) diff += 3600;
123 // Encoded as hhmm, e.g. +05:30 is 530 and -03:30 is -330.
124 4 int hrs = (int)((diff/3600) * 100);
125 4 int mins = (int)((diff % 3600) / 60);
126 4 return hrs + mins;
127 }
128 ✗ int Timestamp::tzOffset() {
129 time_t now;
130 ✗ time(&now);
131 ✗ return Timestamp::calcTZOffset(&now);
132 }
133 9 bool rssiNeedsEmit(int rssi, int lastRssi, int channel, int lastChannel, int minDelta) {
134
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if(channel != lastChannel) return true;
135
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 5 times.
6 int delta = rssi > lastRssi ? rssi - lastRssi : lastRssi - rssi;
136 6 return delta >= minDelta;
137 }
138 4 bool RssiBroadcast::due(int rssi, int channel, int minDelta) const {
139 4 return rssiNeedsEmit(rssi, this->rssi, channel, this->channel, minDelta);
140 }
141 3 void RssiBroadcast::sent(int rssi, int channel) {
142 3 this->rssi = rssi;
143 3 this->channel = channel;
144 3 }
145 3 bool emitAllowed(const void *current, const void *owner) {
146
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
3 return owner == nullptr || current == owner;
147 }
148 6 bool worthRoaming(bool connected, int currentRssi, int apRssi, int minGain) {
149
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 3 times.
6 return !connected || apRssi >= currentRssi + minGain;
150 }
151 4 bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs) {
152
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
4 return networkUp && uptimeMs >= minUptimeMs;
153 }
154 7 void releaseAssetName(char *buf, size_t size, const char *kind, const char *chipModel) {
155 7 snprintf(buf, size, "SomfyController.%s.esp32%s.bin", kind, chipModel);
156 7 }
157 3 void formatBacktrace(char *buf, size_t size, const uint32_t *bt, size_t maxFrames, uint32_t depth) {
158 // depth comes from flash. A half-written dump reads back as 0xa5a5a5a5,
159 // so never trust it past bt[] or the buffer.
160 3 buf[0] = '\0';
161 3 size_t pos = 0;
162 3 size_t frames = depth < maxFrames ? depth : maxFrames;
163
4/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 1 time.
25 for (size_t i = 0; i < frames && pos < size - 1; i++) {
164 22 int n = snprintf(buf + pos, size - pos, " 0x%08x", (unsigned int)bt[i]);
165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (n < 0) break;
166 22 pos += (size_t)n;
167 }
168 3 }
169 7 const char *wifiAuthModeName(uint8_t authMode) {
170
6/10
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 2 times.
7 switch(authMode) {
171 1 case 0: return "OPEN";
172 ✗ case 1: return "WEP";
173 ✗ case 2: return "WPA";
174 1 case 3: return "WPA2";
175 ✗ case 4: return "WPA/WPA2";
176 ✗ case 5: return "WPA2-ENT";
177 1 case 6: return "WPA3";
178 1 case 7: return "WPA2/WPA3";
179 1 case 8: return "WAPI";
180 2 default: return "UNKNOWN";
181 }
182 }
183 5882 void LoopStats::record(uint32_t passUs) {
184 5882 _passes++;
185
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5872 times.
5882 if(passUs > _maxUs) _maxUs = passUs;
186 5882 }
187 9 uint32_t LoopStats::rate(uint32_t nowMs) const {
188 // The unsigned subtraction keeps the window right across a millis() wrap.
189 9 const uint32_t elapsedMs = nowMs - _startMs;
190
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if(elapsedMs == 0) return 0;
191 7 return (uint32_t)((uint64_t)_passes * 1000 / elapsedMs);
192 }
193 2 void LoopStats::publish(uint32_t nowMs) {
194 2 _publishedRate.store(this->rate(nowMs), std::memory_order_relaxed);
195 2 _publishedMaxUs.store(_maxUs, std::memory_order_relaxed);
196 2 _passes = 0;
197 2 _maxUs = 0;
198 2 _startMs = nowMs;
199 2 }
200