Skip to content

Commit c3a580e

Browse files
Add WiFiClientSecure and WifiServerSecure (TLS) support, NTP (#683)
* Add TLS (https) support * Add NTP server * Clean up include path, add BearSSL headers * Allow 2 NTP servers, add ESP8266 compat define * Add MFLN SSL example, free/used/total heap getters * Enable stack thunking * Add tested SSL examples * Add BSSL_validation demo * Add Client Certificate example * Add RP2040 helper docs * Clean up doc errors, missing doc version info * Add WiFiClientSecure documentation * Add NTP docs Fixes #679
1 parent 53cecae commit c3a580e

File tree

88 files changed

+21971
-37
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+21971
-37
lines changed

.github/workflows/pull-request.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Run codespell
2121
uses: codespell-project/actions-codespell@master
2222
with:
23-
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS
23+
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server
2424
ignore_words_list: ser,dout
2525

2626
# Consistent style
@@ -211,4 +211,4 @@ jobs:
211211
- name: Build Fade Example
212212
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
213213
- name: Build TinyUSB Example
214-
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
214+
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@
2525
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
2626
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
2727
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
28+
[submodule "tools/libbearssl/bearssl"]
29+
path = tools/libbearssl/bearssl
30+
url = https://github.com/earlephilhower/bearssl-esp8266.git

cores/rp2040/PolledTimeout.h

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
PolledTimeout.h - Encapsulation of a polled Timeout
3+
4+
Copyright (c) 2018 Daniel Salazar. All rights reserved.
5+
This file is part of the esp8266 core for Arduino environment.
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#pragma once
23+
24+
#include <limits> // std::numeric_limits
25+
#include <type_traits> // std::is_unsigned
26+
27+
#define IRAM_ATTR
28+
29+
namespace esp8266 {
30+
31+
32+
namespace polledTimeout {
33+
34+
namespace YieldPolicy {
35+
36+
struct DoNothing {
37+
static void execute() {}
38+
};
39+
40+
struct YieldOrSkip {
41+
static void execute() {} //{esp_yield();}
42+
};
43+
44+
template <unsigned long delayMs>
45+
struct YieldAndDelayMs {
46+
static void execute() {
47+
delay(delayMs);
48+
}
49+
};
50+
51+
} //YieldPolicy
52+
53+
namespace TimePolicy {
54+
55+
struct TimeSourceMillis {
56+
// time policy in milli-seconds based on millis()
57+
58+
using timeType = decltype(millis());
59+
static timeType time() {
60+
return millis();
61+
}
62+
static constexpr timeType ticksPerSecond = 1000;
63+
static constexpr timeType ticksPerSecondMax = 1000;
64+
};
65+
66+
struct TimeSourceCycles {
67+
// time policy based on esp_get_cycle_count()
68+
// this particular time measurement is intended to be called very often
69+
// (every loop, every yield)
70+
71+
using timeType = decltype(rp2040.getCycleCount());
72+
static timeType time() {
73+
return rp2040.getCycleCount();
74+
}
75+
static constexpr timeType ticksPerSecond = F_CPU;
76+
static constexpr timeType ticksPerSecondMax = F_CPU;
77+
};
78+
79+
template <typename TimeSourceType, unsigned long long second_th>
80+
// "second_th" units of timeType for one second
81+
struct TimeUnit {
82+
using timeType = typename TimeSourceType::timeType;
83+
84+
#if __GNUC__ < 5
85+
// gcc-4.8 cannot compile the constexpr-only version of this function
86+
// using #defines instead luckily works
87+
static constexpr timeType computeRangeCompensation() {
88+
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
89+
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
90+
91+
return ({
92+
fractional == 0 ?
93+
1 : // no need for compensation
94+
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
95+
});
96+
97+
#undef number_of_secondTh_in_one_tick
98+
#undef fractional
99+
}
100+
#else
101+
static constexpr timeType computeRangeCompensation() {
102+
return ({
103+
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
104+
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
105+
fractional == 0 ?
106+
1 : // no need for compensation
107+
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
108+
});
109+
}
110+
#endif
111+
112+
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
113+
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
114+
static constexpr timeType rangeCompensate = computeRangeCompensation();
115+
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
116+
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
117+
static constexpr timeType user2UnitDivider = rangeCompensate;
118+
// std::numeric_limits<timeType>::max() is reserved
119+
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
120+
121+
static timeType toTimeTypeUnit(const timeType userUnit) {
122+
return (userUnit * user2UnitMultiplier) / user2UnitDivider;
123+
}
124+
static timeType toUserUnit(const timeType internalUnit) {
125+
return (internalUnit * user2UnitDivider) / user2UnitMultiplier;
126+
}
127+
static timeType time() {
128+
return TimeSourceType::time();
129+
}
130+
};
131+
132+
using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >;
133+
using TimeFastMillis = TimeUnit< TimeSourceCycles, 1000 >;
134+
using TimeFastMicros = TimeUnit< TimeSourceCycles, 1000000 >;
135+
using TimeFastNanos = TimeUnit< TimeSourceCycles, 1000000000 >;
136+
137+
} //TimePolicy
138+
139+
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
140+
class timeoutTemplate {
141+
public:
142+
using timeType = typename TimePolicyT::timeType;
143+
static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
144+
145+
static constexpr timeType alwaysExpired = 0;
146+
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
147+
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
148+
149+
timeoutTemplate(const timeType userTimeout) {
150+
reset(userTimeout);
151+
}
152+
153+
IRAM_ATTR // fast
154+
bool expired() {
155+
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
156+
if (PeriodicT) { //in case of false: gets optimized away
157+
return expiredRetrigger();
158+
}
159+
return expiredOneShot();
160+
}
161+
162+
IRAM_ATTR // fast
163+
operator bool() {
164+
return expired();
165+
}
166+
167+
bool canExpire() const {
168+
return !_neverExpires;
169+
}
170+
171+
bool canWait() const {
172+
return _timeout != alwaysExpired;
173+
}
174+
175+
// Resets, will trigger after this new timeout.
176+
IRAM_ATTR // called from ISR
177+
void reset(const timeType newUserTimeout) {
178+
reset();
179+
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
180+
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
181+
}
182+
183+
// Resets, will trigger after the timeout previously set.
184+
IRAM_ATTR // called from ISR
185+
void reset() {
186+
_start = TimePolicyT::time();
187+
}
188+
189+
// Resets to just expired so that on next poll the check will immediately trigger for the user,
190+
// also change timeout (after next immediate trigger).
191+
IRAM_ATTR // called from ISR
192+
void resetAndSetExpired(const timeType newUserTimeout) {
193+
reset(newUserTimeout);
194+
_start -= _timeout;
195+
}
196+
197+
// Resets to just expired so that on next poll the check will immediately trigger for the user.
198+
IRAM_ATTR // called from ISR
199+
void resetAndSetExpired() {
200+
reset();
201+
_start -= _timeout;
202+
}
203+
204+
void resetToNeverExpires() {
205+
_timeout = alwaysExpired + 1; // because canWait() has precedence
206+
_neverExpires = true;
207+
}
208+
209+
timeType getTimeout() const {
210+
return TimePolicyT::toUserUnit(_timeout);
211+
}
212+
213+
static constexpr timeType timeMax() {
214+
return TimePolicyT::timeMax;
215+
}
216+
217+
private:
218+
219+
IRAM_ATTR // fast
220+
bool checkExpired(const timeType internalUnit) const {
221+
// canWait() is not checked here
222+
// returns "can expire" and "time expired"
223+
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
224+
}
225+
226+
protected:
227+
228+
IRAM_ATTR // fast
229+
bool expiredRetrigger() {
230+
if (!canWait()) {
231+
return true;
232+
}
233+
234+
timeType current = TimePolicyT::time();
235+
if (checkExpired(current)) {
236+
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
237+
_start += n * _timeout;
238+
return true;
239+
}
240+
return false;
241+
}
242+
243+
IRAM_ATTR // fast
244+
bool expiredOneShot() const {
245+
// returns "always expired" or "has expired"
246+
return !canWait() || checkExpired(TimePolicyT::time());
247+
}
248+
249+
timeType _timeout;
250+
timeType _start;
251+
bool _neverExpires;
252+
};
253+
254+
// legacy type names, deprecated (unit is milliseconds)
255+
256+
using oneShot = polledTimeout::timeoutTemplate<false> /*__attribute__((deprecated("use oneShotMs")))*/;
257+
using periodic = polledTimeout::timeoutTemplate<true> /*__attribute__((deprecated("use periodicMs")))*/;
258+
259+
// standard versions (based on millis())
260+
// timeMax() is 49.7 days ((2^32)-2 ms)
261+
262+
using oneShotMs = polledTimeout::timeoutTemplate<false>;
263+
using periodicMs = polledTimeout::timeoutTemplate<true>;
264+
265+
// Time policy based on esp_get_cycle_count(), and intended to be called very often:
266+
// "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%)
267+
// (cpu cycles for ::expired(): 372 (millis()) vs 52 (esp_get_cycle_count()))
268+
// timeMax() values:
269+
// Ms: max is 26843 ms (26.8 s)
270+
// Us: max is 26843545 us (26.8 s)
271+
// Ns: max is 1073741823 ns ( 1.07 s)
272+
// (time policy based on esp_get_cycle_count() is intended to be called very often)
273+
274+
using oneShotFastMs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
275+
using periodicFastMs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
276+
using oneShotFastUs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
277+
using periodicFastUs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
278+
using oneShotFastNs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
279+
using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
280+
281+
} //polledTimeout
282+
283+
284+
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
285+
using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
286+
287+
Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
288+
*/
289+
290+
}//esp8266

cores/rp2040/RP2040Support.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@
2222
#include <hardware/irq.h>
2323
#include <hardware/pio.h>
2424
#include <hardware/exception.h>
25+
#include <hardware/structs/rosc.h>
2526
#include <hardware/structs/systick.h>
2627
#include <pico/multicore.h>
2728
#include <pico/util/queue.h>
2829
#include "CoreMutex.h"
2930
#include "ccount.pio.h"
30-
31+
#include <malloc.h>
3132

3233
extern "C" volatile bool __otherCoreIdled;
3334

@@ -141,6 +142,9 @@ extern RP2040 rp2040;
141142
extern "C" void main1();
142143
class PIOProgram;
143144

145+
extern "C" char __StackLimit;
146+
extern "C" char __bss_end__;
147+
144148
// Wrapper class for PIO programs, abstracting common operations out
145149
// TODO - Add unload/destructor
146150
class PIOProgram {
@@ -257,6 +261,19 @@ class RP2040 {
257261
}
258262
}
259263

264+
inline int getFreeHeap() {
265+
return getTotalHeap() - getUsedHeap();
266+
}
267+
268+
inline int getUsedHeap() {
269+
struct mallinfo m = mallinfo();
270+
return m.uordblks;
271+
}
272+
273+
inline int getTotalHeap() {
274+
return &__StackLimit - &__bss_end__;
275+
}
276+
260277
void idleOtherCore() {
261278
fifo.idleOtherCore();
262279
}
@@ -274,6 +291,29 @@ class RP2040 {
274291
// Multicore comms FIFO
275292
_MFIFO fifo;
276293

294+
295+
// TODO - Not so great HW random generator. 32-bits wide. Cryptographers somewhere are crying
296+
uint32_t hwrand32() {
297+
// Try and whiten the HW ROSC bit
298+
uint32_t r = 0;
299+
for (int k = 0; k < 32; k++) {
300+
unsigned long int b;
301+
do {
302+
b = rosc_hw->randombit & 1;
303+
if (b != (rosc_hw->randombit & 1)) {
304+
break;
305+
}
306+
} while (true);
307+
r <<= 1;
308+
r |= b;
309+
}
310+
// Stir using the cycle count LSBs. In any WiFi use case this will be a random # since the connection time is not cycle-accurate
311+
uint64_t rr = (((uint64_t)~r) << 32LL) | r;
312+
rr >>= rp2040.getCycleCount() & 32LL;
313+
314+
return (uint32_t)rr;
315+
}
316+
277317
private:
278318
static void _SystickHandler() {
279319
rp2040._epoch += 1LL << 24;

0 commit comments

Comments
 (0)