72#if defined(FL_IS_ARM_LPC)
76struct LowMemPinTogglePeriodStats {
84inline LowMemPinTogglePeriodStats computeLowMemPeriodStats(
86 LowMemPinTogglePeriodStats s{0, 0, 0, 0, 0};
89 fl::u32 min_ns = 0xFFFFFFFFu;
92 for (fl::size i = 0; i + 1 < edge_count; i += 2) {
93 const fl::u32 period_ns =
94 static_cast<fl::u32
>(edges[i].ns) +
95 static_cast<fl::u32
>(edges[i + 1].ns);
96 if (period_ns == 0)
continue;
98 sum_sq +=
static_cast<fl::u64>(period_ns) *
static_cast<fl::u64>(period_ns);
99 if (period_ns < min_ns) min_ns = period_ns;
100 if (period_ns > max_ns) max_ns = period_ns;
103 if (count == 0)
return s;
104 const fl::u32 mean =
static_cast<fl::u32
>(sum /
static_cast<fl::u64>(count));
106 const fl::u64 var = (sum_sq /
static_cast<fl::u64>(count)) - (mean64 * mean64);
108 while (
static_cast<fl::u64>(sig + 1) *
static_cast<fl::u64>(sig + 1) <= var) ++sig;
112 s.min_ns = (min_ns == 0xFFFFFFFFu) ? 0u : min_ns;
139 remote.bind(
"echo", [](
int v) ->
int {
144#if defined(FL_IS_ARM_LPC)
147 remote.bind(
"pinToggleRx",
148 [](
int tx_pin,
int rx_pin,
int freq_hz,
int duration_ms) ->
fl::string {
149 if (tx_pin < 0 || rx_pin < 0 || freq_hz <= 0 || duration_ms <= 0) {
152 const fl::u32 expected_edges =
153 2u *
static_cast<fl::u32
>(freq_hz) *
154 static_cast<fl::u32
>(duration_ms) / 1000u;
155 fl::u32 cap = expected_edges + (expected_edges / 2u);
156 if (cap < 256u) cap = 256u;
157 if (cap > 2048u) cap = 2048u;
159 auto rx = fl::LpcSctRxChannel::create(rx_pin);
165 if (!rx->begin(cfg))
return fl::string(
"0,0,0,0,0,0,0");
167 pinMode(tx_pin, OUTPUT);
168 digitalWrite(tx_pin, LOW);
170 const fl::u32 half_us = 500000u /
static_cast<fl::u32
>(freq_hz);
171 const fl::u32 cycles =
static_cast<fl::u32
>(freq_hz) *
172 static_cast<fl::u32
>(duration_ms) / 1000u;
174 for (fl::u32 i = 0; i < cycles; ++i) {
175 digitalWrite(tx_pin, HIGH);
176 delayMicroseconds(half_us);
178 digitalWrite(tx_pin, LOW);
179 delayMicroseconds(half_us);
181 if ((i & 0x7Fu) == 0u) {
188 const fl::size n_read = rx->getRawEdgeTimes(
191 LowMemPinTogglePeriodStats stats = computeLowMemPeriodStats(edges_buf, n_read);
194 const bool success = (stats.periods > 0);
195 s << (success ? 1 : 0) << ',' << static_cast<fl::u32>(n_read) <<
','
196 << stats.periods <<
',' << stats.mean_ns <<
',' << stats.sigma_ns <<
','
197 << stats.min_ns <<
',' << stats.max_ns;
201#if defined(FASTLED_LPC_RX_SCT_WS2812)
203 remote.bind(
"ws2812SctTest",
204 [](
int test_case,
int tx_pin,
int rx_pin,
int capture_ms) ->
fl::string {
205 if (test_case < 0 || test_case > 4 ||
206 tx_pin < 0 || rx_pin < 0 || capture_ms <= 0) {
211 case 1: num_leds = 3;
break;
212 case 4: num_leds = 100;
break;
213 default: num_leds = 1;
break;
215 static CRGB leds_buf[100];
216 for (
int i = 0; i < num_leds; ++i) {
218 case 0: leds_buf[i] =
CRGB(0xFF, 0x00, 0x00);
break;
220 if (i == 0) leds_buf[i] =
CRGB(0xFF, 0x00, 0x00);
221 else if (i == 1) leds_buf[i] =
CRGB(0x00, 0xFF, 0x00);
222 else leds_buf[i] =
CRGB(0x00, 0x00, 0xFF);
225 case 2: leds_buf[i] =
CRGB(0x00, 0x00, 0x00);
break;
226 case 3: leds_buf[i] =
CRGB(0xFF, 0xFF, 0xFF);
break;
228 const uint8_t r = (i % 3 == 0) ? 0xFFu : 0u;
229 const uint8_t g = (i % 3 == 1) ? 0xFFu : 0u;
230 const uint8_t b = (i % 3 == 2) ? 0xFFu : 0u;
231 leds_buf[i] =
CRGB(r, g, b);
236 const int expected_bytes = num_leds * 3;
237 static uint8_t expected_buf[300];
238 for (
int i = 0; i < num_leds; ++i) {
239 expected_buf[i * 3 + 0] = leds_buf[i].g;
240 expected_buf[i * 3 + 1] = leds_buf[i].r;
241 expected_buf[i * 3 + 2] = leds_buf[i].b;
243 auto rx = fl::LpcSctRxChannel::create(rx_pin);
244 if (!rx)
return fl::string(
"0,0,0,0,0,0,0,0");
246 const fl::u32 expected_edges = (fl::u32)num_leds * 24u * 2u;
247 fl::u32 cap = expected_edges + (expected_edges / 2u);
248 if (cap < 256u) cap = 256u;
249 if (cap > 2048u) cap = 2048u;
252 if (!rx->begin(cfg))
return fl::string(
"0,0,0,0,0,0,0,0");
254 constexpr int kFixedTxPin = 10;
255 if (tx_pin != kFixedTxPin) {
258 static bool fastled_inited =
false;
259 if (!fastled_inited) {
260 FastLED.addLeds<WS2812, kFixedTxPin,
GRB>(leds_buf, 100);
261 fastled_inited =
true;
264 rx->wait(capture_ms);
266 static uint8_t decoded_buf[300];
267 for (
int i = 0; i < expected_bytes; ++i) decoded_buf[i] = 0;
274 auto dec = rx->decode(timing,
fl::span<u8>(decoded_buf, expected_bytes));
275 const fl::u32 decoded_bytes = dec.ok() ? dec.value() : 0u;
278 fl::u32 mismatched = 0;
279 for (fl::u32 i = 0; i < decoded_bytes && i < (fl::u32)expected_bytes; ++i) {
280 if (decoded_buf[i] == expected_buf[i]) ++matched;
283 const fl::u32 missing = (fl::u32)expected_bytes - decoded_bytes;
284 mismatched += missing;
287 const fl::size edges_captured = rx->getRawEdgeTimes(
290 const bool success = (mismatched == 0 && decoded_bytes == (fl::u32)expected_bytes);
293 s << (success ? 1 : 0) <<
',' << test_case <<
',' << num_leds <<
','
294 << expected_bytes <<
',' << decoded_bytes <<
','
295 << matched <<
',' << mismatched <<
','
296 <<
static_cast<fl::u32
>(edges_captured);