FastLED 3.9.15
Loading...
Searching...
No Matches
connection.cpp.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "fl/stl/algorithm.h"
5namespace fl {
6
18
22
26
30
34
37 return; // Permanently closed, no connect allowed
38 }
39
40 // Track if we're coming from RECONNECTING state
43}
44
51
55
56void HttpConnection::onConnected(u32 currentTimeMs) {
58 // Reset attempts if we were in RECONNECTING state before entering CONNECTING
59 // This detects successful reconnection after disconnect
60 bool shouldResetAttempts = mWasReconnecting || (mState == ConnectionState::RECONNECTING);
61
63
64 if (shouldResetAttempts) {
65 resetReconnectAttempts(); // Successful reconnection, reset counter
66 } else {
67 resetReconnectState(); // Initial connection, just reset timing
68 }
69
70 mWasReconnecting = false;
71 }
72}
73
76 // Check if we should attempt reconnection
77 // Use <= to handle the exact limit correctly (0-indexed attempts vs 1-indexed limit)
78 if (mConfig.maxReconnectAttempts == 0 ||
79 mReconnectAttempts < mConfig.maxReconnectAttempts) {
81 } else {
83 }
84 }
85}
86
88 // Treat errors the same as disconnection
90}
91
92void HttpConnection::onEvent(const asio::error_code& ec, u32 currentTimeMs) {
93 if (ec.ok()) {
94 onConnected(currentTimeMs);
95 } else if (ec.code == asio::errc::eof || ec.code == asio::errc::connection_reset) {
97 } else {
98 onError();
99 }
100}
101
103 // Note: currentTimeMs should be passed, but for simplicity we don't update timestamp here
104 // The caller should update mLastHeartbeatSentMs via update()
105}
106
108 // Note: currentTimeMs should be passed, but for simplicity we don't update timestamp here
109 // The caller should update mLastDataReceivedMs via update()
110}
111
112bool HttpConnection::shouldSendHeartbeat(u32 currentTimeMs) const {
114 return false; // Only send heartbeats when connected
115 }
116
117 // Check if enough time has passed since last heartbeat
118 u32 timeSinceLastHeartbeat = currentTimeMs - mLastHeartbeatSentMs;
119 return timeSinceLastHeartbeat >= mConfig.heartbeatIntervalMs;
120}
121
122void HttpConnection::update(u32 currentTimeMs) {
123 // Check for timeout first (before updating timestamps)
124 if (isTimedOut(currentTimeMs)) {
126 return;
127 }
128
129 // Handle reconnection
131 if (currentTimeMs >= mNextReconnectTimeMs) {
132 // Time to attempt reconnection
133 connect(); // Transition to CONNECTING
134 }
135 }
136
137 // Update heartbeat sent timestamp if needed
138 if (shouldSendHeartbeat(currentTimeMs)) {
139 mLastHeartbeatSentMs = currentTimeMs;
140 }
141}
142
146
150
151bool HttpConnection::isTimedOut(u32 currentTimeMs) const {
153 return false; // Only check timeout when connected
154 }
155
156 // Check if enough time has passed since last data received
157 u32 timeSinceLastData = currentTimeMs - mLastDataReceivedMs;
158 return timeSinceLastData >= mConfig.connectionTimeoutMs;
159}
160
161void HttpConnection::transitionTo(ConnectionState newState, u32 currentTimeMs) {
162 mState = newState;
163
164 // Handle state-specific initialization
165 switch (newState) {
167 resetReconnectAttempts(); // Full reset on user disconnect
168 break;
169
171 // Starting connection attempt
172 break;
173
175 // Initialize data received timestamp (for timeout detection)
176 mLastDataReceivedMs = currentTimeMs;
177 // Initialize heartbeat timestamp to trigger immediate send on first check
178 // Subtract interval from currentTimeMs to ensure timeSince >= interval
179 if (mLastHeartbeatSentMs == 0) {
180 // Use wrapping arithmetic: currentTimeMs - interval
181 // Even if this underflows (currentTimeMs < interval), the unsigned
182 // subtraction in shouldSendHeartbeat will wrap correctly
183 mLastHeartbeatSentMs = currentTimeMs - mConfig.heartbeatIntervalMs;
184 }
185 break;
186
188 // Calculate backoff delay BEFORE incrementing attempts
190 mNextReconnectTimeMs = currentTimeMs + mReconnectDelayMs;
191 // Increment attempts for next reconnection
193 break;
194
196 resetReconnectAttempts(); // Full reset on close
197 break;
198 }
199}
200
202 // Reset reconnection timing state, but keep attempts counter
205}
206
208 // Fully reset all reconnection state including attempts counter
211}
212
214 // Exponential backoff: delay = initial * (multiplier ^ attempts)
215 u32 delay = mConfig.reconnectInitialDelayMs;
216 for (u32 i = 0; i < mReconnectAttempts; i++) {
217 delay *= mConfig.reconnectBackoffMultiplier;
218 if (delay > mConfig.reconnectMaxDelayMs) {
219 delay = mConfig.reconnectMaxDelayMs;
220 break;
221 }
222 }
223
224 return delay;
225}
226
227} // namespace fl
bool isConnected() const
void update(u32 currentTimeMs)
ConnectionState getState() const
u32 calculateBackoffDelay() const
bool shouldReconnect() const
bool isTimedOut(u32 currentTimeMs) const
HttpConnection(const ConnectionConfig &config=ConnectionConfig())
u32 getReconnectAttempts() const
ConnectionConfig mConfig
Definition connection.h:74
void onEvent(const asio::error_code &ec, u32 currentTimeMs=0)
void onConnected(u32 currentTimeMs=0)
bool shouldSendHeartbeat(u32 currentTimeMs) const
u32 getReconnectDelayMs() const
void transitionTo(ConnectionState newState, u32 currentTimeMs)
bool isDisconnected() const
ConnectionState mState
Definition connection.h:75
ConnectionState
Definition connection.h:9
void delay(u32 ms, bool run_async=true) FL_NOEXCEPT
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
bool ok() const
Convenience: true if no error.
Definition error_code.h:44
Asio-compatible error code: numeric code + optional human-readable message.
Definition error_code.h:31