Skip to content

Commit 72b2e36

Browse files
committed
Add TimedAttempt
1 parent 0d100c3 commit 72b2e36

File tree

5 files changed

+301
-0
lines changed

5 files changed

+301
-0
lines changed

extras/test/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ set(TEST_SRCS
2727
src/crc16/test_crc16.cpp
2828
src/sha256/test_sha256.cpp
2929
src/hex/test_hex.cpp
30+
src/time/test_TimedAttempt.cpp
3031
)
3132

3233
set(TEST_DUT_SRCS
3334
../../src/crc/crc32.cpp
3435
../../src/crc/crc16.cpp
3536
../../src/sha256/sha2.c
3637
../../src/hex/chex.h
38+
../../src/time/TimedAttempt.cpp
3739
)
3840

3941
##########################################################################
+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
This file is part of the Arduino_CloudUtils library.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#include <catch2/catch_test_macros.hpp>
12+
13+
#include <time/TimedAttempt.h>
14+
15+
using namespace arduino::time;
16+
17+
SCENARIO("Test broker connection retries") {
18+
TimedAttempt _connection_attempt(0,0);
19+
20+
_connection_attempt.begin(1000UL, 32000UL);
21+
22+
/* 100000 retries are more or less 37 days without connection */
23+
while(_connection_attempt.getRetryCount() < 100000) {
24+
_connection_attempt.retry();
25+
26+
switch(_connection_attempt.getRetryCount()) {
27+
case 1:
28+
REQUIRE(_connection_attempt.getWaitTime() == 2000);
29+
break;
30+
case 2:
31+
REQUIRE(_connection_attempt.getWaitTime() == 4000);
32+
break;
33+
case 3:
34+
REQUIRE(_connection_attempt.getWaitTime() == 8000);
35+
break;
36+
case 4:
37+
REQUIRE(_connection_attempt.getWaitTime() == 16000);
38+
break;
39+
default:
40+
REQUIRE(_connection_attempt.getWaitTime() == 32000);
41+
break;
42+
}
43+
}
44+
}
45+
46+
SCENARIO("Test thing id request with no answer from the cloud") {
47+
TimedAttempt _attachAttempt(0,0);
48+
49+
_attachAttempt.begin(2000UL, 32000UL);
50+
51+
/* 100000 retries are more or less 37 days of requests */
52+
while(_attachAttempt.getRetryCount() < 100000) {
53+
_attachAttempt.retry();
54+
55+
switch(_attachAttempt.getRetryCount()) {
56+
case 1:
57+
REQUIRE(_attachAttempt.getWaitTime() == 4000);
58+
break;
59+
case 2:
60+
REQUIRE(_attachAttempt.getWaitTime() == 8000);
61+
break;
62+
case 3:
63+
REQUIRE(_attachAttempt.getWaitTime() == 16000);
64+
break;
65+
default:
66+
REQUIRE(_attachAttempt.getWaitTime() == 32000);
67+
break;
68+
}
69+
}
70+
}
71+
72+
SCENARIO("Test thing id request of a detached device") {
73+
TimedAttempt _attachAttempt(0,0);
74+
75+
_attachAttempt.begin(2000UL, 32000UL);
76+
77+
while(_attachAttempt.getRetryCount() < 100000) {
78+
_attachAttempt.retry();
79+
80+
switch(_attachAttempt.getRetryCount()) {
81+
case 1:
82+
REQUIRE(_attachAttempt.getWaitTime() == 4000);
83+
_attachAttempt.reconfigure(2000UL * 10UL, 32000UL * 40UL);
84+
break;
85+
case 2:
86+
REQUIRE(_attachAttempt.getWaitTime() == 80000);
87+
break;
88+
case 3:
89+
REQUIRE(_attachAttempt.getWaitTime() == 160000);
90+
break;
91+
case 4:
92+
REQUIRE(_attachAttempt.getWaitTime() == 320000);
93+
break;
94+
case 5:
95+
REQUIRE(_attachAttempt.getWaitTime() == 640000);
96+
break;
97+
default:
98+
REQUIRE(_attachAttempt.getWaitTime() == 1280000);
99+
break;
100+
}
101+
}
102+
}
103+
104+
SCENARIO("Test last value request") {
105+
TimedAttempt _syncAttempt(0,0);
106+
107+
_syncAttempt.begin(30000UL);
108+
109+
/* 100000 retries are more or less 37 days of requests */
110+
while(_syncAttempt.getRetryCount() < 100000) {
111+
_syncAttempt.retry();
112+
113+
switch(_syncAttempt.getRetryCount()) {
114+
default:
115+
REQUIRE(_syncAttempt.getWaitTime() == 30000);
116+
break;
117+
}
118+
}
119+
}
120+
121+
SCENARIO("Test isExpired() and isRetry()") {
122+
TimedAttempt attempt(0,0);
123+
124+
attempt.begin(1000UL, 32000UL);
125+
126+
/* Initial condition */
127+
set_millis(0);
128+
REQUIRE(attempt.isExpired() == false);
129+
REQUIRE(attempt.isRetry() == false);
130+
131+
/* Normal retry 2000ms */
132+
attempt.retry();
133+
REQUIRE(attempt.isRetry() == true);
134+
set_millis(1000);
135+
REQUIRE(attempt.isExpired() == false);
136+
set_millis(1999);
137+
REQUIRE(attempt.isExpired() == false);
138+
set_millis(2000);
139+
REQUIRE(attempt.isExpired() == false);
140+
set_millis(2001);
141+
REQUIRE(attempt.isExpired() == true);
142+
143+
/* Retry with rollover 4000ms */
144+
set_millis(ULONG_MAX - 1999);
145+
attempt.retry();
146+
REQUIRE(attempt.isRetry() == true);
147+
set_millis(0);
148+
REQUIRE(attempt.isExpired() == false);
149+
set_millis(1999);
150+
REQUIRE(attempt.isExpired() == false);
151+
set_millis(2000);
152+
REQUIRE(attempt.isExpired() == false);
153+
set_millis(2001);
154+
REQUIRE(attempt.isExpired() == true);
155+
156+
/* Normal retry 8000ms */
157+
set_millis(4000);
158+
attempt.retry();
159+
REQUIRE(attempt.isRetry() == true);
160+
set_millis(4000);
161+
REQUIRE(attempt.isExpired() == false);
162+
set_millis(11999);
163+
REQUIRE(attempt.isExpired() == false);
164+
set_millis(12000);
165+
REQUIRE(attempt.isExpired() == false);
166+
set_millis(12001);
167+
REQUIRE(attempt.isExpired() == true);
168+
169+
attempt.reset();
170+
REQUIRE(attempt.isRetry() == false);
171+
}

src/Arduino_TimedAttempt.h

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
This file is part of the Arduino_CloudUtils library.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
#pragma once
11+
12+
#include "./TimedAttempt.h"

src/time/TimedAttempt.cpp

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
This file is part of the Arduino_CloudUtils library.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
12+
#include <Arduino.h>
13+
#include "TimedAttempt.h"
14+
15+
namespace arduino { namespace time {
16+
17+
TimedAttempt::TimedAttempt(unsigned long minDelay, unsigned long maxDelay)
18+
: _minDelay(minDelay)
19+
, _maxDelay(maxDelay) {
20+
}
21+
22+
void TimedAttempt::begin(unsigned long delay) {
23+
_retryCount = 0;
24+
_retryDelay = 0;
25+
_retryTick = 0;
26+
_minDelay = delay;
27+
_maxDelay = delay;
28+
}
29+
30+
void TimedAttempt::begin(unsigned long minDelay, unsigned long maxDelay) {
31+
_retryCount = 0;
32+
_retryDelay = 0;
33+
_retryTick = 0;
34+
_minDelay = minDelay;
35+
_maxDelay = maxDelay;
36+
}
37+
38+
unsigned long TimedAttempt::reconfigure(unsigned long minDelay, unsigned long maxDelay) {
39+
_minDelay = minDelay;
40+
_maxDelay = maxDelay;
41+
return reload();
42+
}
43+
44+
unsigned long TimedAttempt::retry() {
45+
_retryCount++;
46+
return reload();
47+
}
48+
49+
unsigned long TimedAttempt::reload() {
50+
unsigned long shift = _retryCount > 31 ? 31 : _retryCount;
51+
unsigned long delay = (1UL << shift) * _minDelay;
52+
_retryDelay = min(delay, _maxDelay);
53+
_retryTick = millis();
54+
return _retryDelay;
55+
}
56+
57+
void TimedAttempt::reset() {
58+
_retryCount = 0;
59+
}
60+
61+
bool TimedAttempt::isRetry() {
62+
return _retryCount > 0;
63+
}
64+
65+
bool TimedAttempt::isExpired() {
66+
return millis() - _retryTick > _retryDelay;
67+
}
68+
69+
unsigned int TimedAttempt::getRetryCount() {
70+
return _retryCount;
71+
}
72+
73+
unsigned int TimedAttempt::getWaitTime() {
74+
return _retryDelay;
75+
}
76+
77+
}} // arduino::time

src/time/TimedAttempt.h

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
This file is part of the Arduino_CloudUtils library.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#pragma once
12+
13+
namespace arduino { namespace time {
14+
15+
class TimedAttempt {
16+
17+
public:
18+
TimedAttempt(unsigned long minDelay, unsigned long maxDelay);
19+
20+
void begin(unsigned long delay);
21+
void begin(unsigned long minDelay, unsigned long maxDelay);
22+
unsigned long reconfigure(unsigned long minDelay, unsigned long maxDelay);
23+
unsigned long retry();
24+
unsigned long reload();
25+
void reset();
26+
bool isRetry();
27+
bool isExpired();
28+
unsigned int getRetryCount();
29+
unsigned int getWaitTime();
30+
31+
private:
32+
unsigned long _minDelay;
33+
unsigned long _maxDelay;
34+
unsigned long _retryTick;
35+
unsigned long _retryDelay;
36+
unsigned int _retryCount;
37+
};
38+
39+
}} // arduino::time

0 commit comments

Comments
 (0)