FastLED 3.10.8
Loading...
Searching...
No Matches
connection.cpp.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "fl/stl/algorithm.h"
5#include "fl/stl/noexcept.h"
6namespace fl {
7
19
23
27
31
35
38 return; // Permanently closed, no connect allowed
39 }
40
41 // Track if we're coming from RECONNECTING state
44}
45
52
56
59 // Reset attempts if we were in RECONNECTING state before entering CONNECTING
60 // This detects successful reconnection after disconnect
61 bool shouldResetAttempts = mWasReconnecting || (mState == ConnectionState::RECONNECTING);
62
64
65 if (shouldResetAttempts) {
66 resetReconnectAttempts(); // Successful reconnection, reset counter
67 } else {
68 resetReconnectState(); // Initial connection, just reset timing
69 }
70
71 mWasReconnecting = false;
72 }
73}
74
77 // Check if we should attempt reconnection
78 // Use <= to handle the exact limit correctly (0-indexed attempts vs 1-indexed limit)
79 if (mConfig.maxReconnectAttempts == 0 ||
80 mReconnectAttempts < mConfig.maxReconnectAttempts) {
82 } else {
84 }
85 }
86}
87
89 // Treat errors the same as disconnection
91}
92
93void HttpConnection::onEvent(const asio::error_code& ec, u32 currentTimeMs) FL_NO_EXCEPT {
94 if (ec.ok()) {
95 onConnected(currentTimeMs);
96 } else if (ec.code == asio::errc::eof || ec.code == asio::errc::connection_reset) {
98 } else {
99 onError();
100 }
101}
102
104 // Note: currentTimeMs should be passed, but for simplicity we don't update timestamp here
105 // The caller should update mLastHeartbeatSentMs via update()
106}
107
109 // Note: currentTimeMs should be passed, but for simplicity we don't update timestamp here
110 // The caller should update mLastDataReceivedMs via update()
111}
112
115 return false; // Only send heartbeats when connected
116 }
117
118 // Check if enough time has passed since last heartbeat
119 u32 timeSinceLastHeartbeat = currentTimeMs - mLastHeartbeatSentMs;
120 return timeSinceLastHeartbeat >= mConfig.heartbeatIntervalMs;
121}
122
123void HttpConnection::update(u32 currentTimeMs) FL_NO_EXCEPT {
124 // Check for timeout first (before updating timestamps)
125 if (isTimedOut(currentTimeMs)) {
127 return;
128 }
129
130 // Handle reconnection
132 if (currentTimeMs >= mNextReconnectTimeMs) {
133 // Time to attempt reconnection
134 connect(); // Transition to CONNECTING
135 }
136 }
137
138 // Update heartbeat sent timestamp if needed
139 if (shouldSendHeartbeat(currentTimeMs)) {
140 mLastHeartbeatSentMs = currentTimeMs;
141 }
142}
143
147
151
152bool HttpConnection::isTimedOut(u32 currentTimeMs) const FL_NO_EXCEPT {
154 return false; // Only check timeout when connected
155 }
156
157 // Check if enough time has passed since last data received
158 u32 timeSinceLastData = currentTimeMs - mLastDataReceivedMs;
159 return timeSinceLastData >= mConfig.connectionTimeoutMs;
160}
161
163 mState = newState;
164
165 // Handle state-specific initialization
166 switch (newState) {
168 resetReconnectAttempts(); // Full reset on user disconnect
169 break;
170
172 // Starting connection attempt
173 break;
174
176 // Initialize data received timestamp (for timeout detection)
177 mLastDataReceivedMs = currentTimeMs;
178 // Initialize heartbeat timestamp to trigger immediate send on first check
179 // Subtract interval from currentTimeMs to ensure timeSince >= interval
180 if (mLastHeartbeatSentMs == 0) {
181 // Use wrapping arithmetic: currentTimeMs - interval
182 // Even if this underflows (currentTimeMs < interval), the unsigned
183 // subtraction in shouldSendHeartbeat will wrap correctly
184 mLastHeartbeatSentMs = currentTimeMs - mConfig.heartbeatIntervalMs;
185 }
186 break;
187
189 // Calculate backoff delay BEFORE incrementing attempts
191 mNextReconnectTimeMs = currentTimeMs + mReconnectDelayMs;
192 // Increment attempts for next reconnection
194 break;
195
197 resetReconnectAttempts(); // Full reset on close
198 break;
199 }
200}
201
203 // Reset reconnection timing state, but keep attempts counter
206}
207
209 // Fully reset all reconnection state including attempts counter
212}
213
215 // Exponential backoff: delay = initial * (multiplier ^ attempts)
216 u32 delay = mConfig.reconnectInitialDelayMs;
217 for (u32 i = 0; i < mReconnectAttempts; i++) {
218 delay *= mConfig.reconnectBackoffMultiplier;
219 if (delay > mConfig.reconnectMaxDelayMs) {
220 delay = mConfig.reconnectMaxDelayMs;
221 break;
222 }
223 }
224
225 return delay;
226}
227
228} // namespace fl
bool shouldReconnect() const FL_NO_EXCEPT
bool isTimedOut(u32 currentTimeMs) const FL_NO_EXCEPT
void onHeartbeatReceived() FL_NO_EXCEPT
void onHeartbeatSent() FL_NO_EXCEPT
void onEvent(const asio::error_code &ec, u32 currentTimeMs=0) FL_NO_EXCEPT
void update(u32 currentTimeMs) FL_NO_EXCEPT
void connect() FL_NO_EXCEPT
void onError() FL_NO_EXCEPT
void resetReconnectAttempts() FL_NO_EXCEPT
HttpConnection(const ConnectionConfig &config=ConnectionConfig()) FL_NO_EXCEPT
void disconnect() FL_NO_EXCEPT
ConnectionConfig mConfig
Definition connection.h:75
void transitionTo(ConnectionState newState, u32 currentTimeMs) FL_NO_EXCEPT
void onConnected(u32 currentTimeMs=0) FL_NO_EXCEPT
u32 getReconnectAttempts() const FL_NO_EXCEPT
u32 calculateBackoffDelay() const FL_NO_EXCEPT
void close() FL_NO_EXCEPT
void resetReconnectState() FL_NO_EXCEPT
void onDisconnected() FL_NO_EXCEPT
bool isConnected() const FL_NO_EXCEPT
bool shouldSendHeartbeat(u32 currentTimeMs) const FL_NO_EXCEPT
bool isDisconnected() const FL_NO_EXCEPT
ConnectionState mState
Definition connection.h:76
u32 getReconnectDelayMs() const FL_NO_EXCEPT
ConnectionState getState() const FL_NO_EXCEPT
ConnectionState
Definition connection.h:10
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
void delay(u32 ms, bool run_async=true) FL_NO_EXCEPT
Public delay wrapper that keeps bare Arduino delay() preferred after using fl::delay; while still all...
Definition delay.h:98
Base definition for an LED controller.
Definition crgb.hpp:179
Asio-compatible error code: numeric code + optional human-readable message.
Definition error_code.h:31