REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
mode.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 anabrid GmbH
2// Contact: https://www.anabrid.com/licensing/
3// SPDX-License-Identifier: MIT OR GPL-2.0-or-later
4
5#include "mode/mode.h"
6#include "mode/counters.h"
7
8#include <Arduino.h>
9
10#include "utils/factorize.h"
11#include "utils/logging.h"
12
14 digitalWriteFast(PIN_MODE_IC, HIGH);
15 digitalWriteFast(PIN_MODE_OP, HIGH);
16 pinMode(PIN_MODE_IC, OUTPUT);
17 pinMode(PIN_MODE_OP, OUTPUT);
18 digitalWriteFast(PIN_MODE_IC, HIGH);
19 digitalWriteFast(PIN_MODE_OP, HIGH);
20}
21
23 digitalWriteFast(PIN_MODE_OP, HIGH);
24 digitalWriteFast(PIN_MODE_IC, LOW);
26}
27
29 digitalWriteFast(PIN_MODE_IC, HIGH);
30 digitalWriteFast(PIN_MODE_OP, LOW);
32}
33
35 digitalWriteFast(PIN_MODE_IC, HIGH);
36 digitalWriteFast(PIN_MODE_OP, HIGH);
38}
39
47
52 } else {
53 // this should not happen.
54 }
55 }
56}
57
66
75
84
85// storage and default values for static class members
86bool mode::FlexIOControl::_is_initialized = false;
87bool mode::FlexIOControl::_is_enabled = false;
88
89bool mode::FlexIOControl::init(unsigned long long ic_time_ns, unsigned long long op_time_ns,
90 mode::OnOverload on_overload, mode::OnExtHalt on_ext_halt, mode::Sync sync) {
91 // Initialize and reset QTMR
92 _init_qtmr_op();
93 _reset_qtmr_op();
94
95 // Get FlexIO handler for initialization
96 auto flexio = FlexIOHandler::flexIOHandler_list[2];
97
98 // Set clock settings
99 // For (3, 0, 0) the clock frequency is 480'000'000
100 flexio->setClockSettings(CLK_SEL, 0, 0);
101 auto CLK_FREQ = flexio->computeClockRate();
102 auto CLK_FREQ_MHz = CLK_FREQ / 1'000'000;
103 // Enable fast access?
104 // flexio->port().CTRL |= FLEXIO_CTRL_FASTACC;
105
106 //
107 // Configure sync matcher
108 //
109
110 // Get internal FlexIO pins from external pins
111 uint8_t _sck_flex_pin = flexio->mapIOPinToFlexPin(PIN_SYNC_CLK);
112 if (_sck_flex_pin == 0xff)
113 return false;
114
115 // Configure a timer to track signal of PIN_SYNC_CLK
116 flexio->port().TIMCTL[t_sync_clk] = FLEXIO_TIMCTL_PINSEL(_sck_flex_pin) | FLEXIO_TIMCTL_TIMOD(1);
117 flexio->port().TIMCFG[t_sync_clk] = FLEXIO_TIMCFG_TIMOUT(1) | FLEXIO_TIMCFG_TIMDEC(2);
118 flexio->port().TIMCMP[t_sync_clk] = 0x0000'FF'00;
119
120 // Select a shifter for monitoring PIN_SYNC_ID
121 auto _flexio_pin_data_in = flexio->mapIOPinToFlexPin(PIN_SYNC_ID);
122 if (_flexio_pin_data_in == 0xff)
123 return false;
124 // Configure the shifter into continuous match mode, monitoring SYNC_CLK_ID
125 flexio->port().SHIFTCTL[z_sync_match] = FLEXIO_SHIFTCTL_TIMSEL(t_sync_clk) |
126 FLEXIO_SHIFTCTL_PINSEL(_flexio_pin_data_in) |
127 FLEXIO_SHIFTCTL_SMOD(0b101);
128 flexio->port().SHIFTCFG[z_sync_match] = 0;
129 // Set compare value in SHIFTBUF[31:16] and mask in SHIFTBUF[15:0] (1=mask, 0=no mask)
130 flexio->port().SHIFTBUF[z_sync_match] = 0b01010101'00001111'00000000'00000000;
131
132 // Get a timer which is enabled when there is a match
133 // Configure timer
134 flexio->port().TIMCTL[t_sync_trigger] =
135 FLEXIO_TIMCTL_TRGSEL(4 * z_sync_match + 1) | FLEXIO_TIMCTL_TRGSRC | FLEXIO_TIMCTL_TIMOD(1);
136 flexio->port().TIMCFG[t_sync_trigger] = FLEXIO_TIMCFG_TIMDIS(2) | FLEXIO_TIMCFG_TIMENA(6);
137 flexio->port().TIMCMP[t_sync_trigger] = 0x0000'01'00;
138
139 //
140 // Configure IDLE state
141 //
142
143 switch (sync) {
144 case Sync::NONE:
145 flexio->port().SHIFTCTL[s_idle] = FLEXIO_SHIFTCTL_PINCFG(3) | FLEXIO_SHIFTCTL_SMOD_STATE;
146 flexio->port().SHIFTBUF[s_idle] = FLEXIO_STATE_SHIFTBUF(0b11111111, s_idle);
147 case Sync::MASTER:
148 case Sync::SLAVE:
149 flexio->port().SHIFTCTL[s_idle] =
150 FLEXIO_SHIFTCTL_TIMSEL(t_sync_trigger) | FLEXIO_SHIFTCTL_PINCFG(3) | FLEXIO_SHIFTCTL_SMOD_STATE;
151 flexio->port().SHIFTBUF[s_idle] = FLEXIO_STATE_SHIFTBUF(0b11111111, s_ic);
152 }
153 flexio->port().SHIFTCFG[s_idle] = 0;
154
155 //
156 // Configure state check timer
157 //
158
159 // Some states are changed not by timer triggers, but by continuously checking of the inputs
160 // Configure state change check timer as fast as possible
161 flexio->port().TIMCTL[t_state_check] = FLEXIO_TIMCTL_TIMOD(3);
162 flexio->port().TIMCFG[t_state_check] = FLEXIO_TIMCFG_TIMDIS(0) | FLEXIO_TIMCFG_TIMENA(0);
163 flexio->port().TIMCMP[t_state_check] = 0x0000'0001;
164
165 //
166 // Configure IC state
167 //
168
169 // Sanity check ic_time_ns
170 if (ic_time_ns < 100 or ic_time_ns >= 9'000'000'000) {
171 LOG_ERROR("FlexIOControl: Requested ic_time_ns cannot be represented by 32bit.");
172 return false;
173 }
174
175 /*
176 if (ic_time_ns < 0xFFFFull * 1000ull / CLK_FREQ_MHz) {
177 // One 16bit timer is enough actually
178 flexio->port().TIMCTL[t_ic] = FLEXIO_TIMCTL_TRGSEL_STATE(s_ic) | FLEXIO_TIMCTL_TIMOD(3) |
179 FLEXIO_TIMCTL_PINCFG(3) | FLEXIO_TIMCTL_PINSEL(17);
180 flexio->port().TIMCFG[t_ic] =
181 FLEXIO_TIMCFG_TIMRST(6) | FLEXIO_TIMCFG_TIMDIS(0b110) | FLEXIO_TIMCFG_TIMENA(6) | FLEXIO_TIMCFG_TIMOUT(1);
182 flexio->port().TIMCMP[t_ic] = ic_time_ns * CLK_FREQ_MHz / 1000;
183
184 // Reset second timer used when going towards higher times
185 flexio->port().TIMCTL[t_ic_second] = 0;
186 flexio->port().TIMCFG[t_ic_second] = 0;
187 flexio->port().TIMCMP[t_ic_second] = 0;
188 } else {*/
189 // We split counting to two chained timers
190 auto factors = utils::factorize(ic_time_ns * CLK_FREQ_MHz / 1000);
191 if (factors.first >= 1 << 16 ||
192 factors.second >= 1 << 16) // Factror even is too big for two cascaded timers
193 return false;
194
195 // Configure state timer
196 flexio->port().TIMCTL[t_ic] = FLEXIO_TIMCTL_TRGSEL_STATE(s_ic) | FLEXIO_TIMCTL_TIMOD(3) |
197 FLEXIO_TIMCTL_PINPOL;
198 flexio->port().TIMCFG[t_ic] = FLEXIO_TIMCFG_TIMRST(6) | FLEXIO_TIMCFG_TIMDIS(6) | FLEXIO_TIMCFG_TIMENA(6);
199 flexio->port().TIMCMP[t_ic] = factors.first - 1;
200 // Configure second timer
201 flexio->port().TIMCTL[t_ic_second] = FLEXIO_TIMCTL_TRGSEL(4 * t_ic + 3) | FLEXIO_TIMCTL_TRGSRC |
202 FLEXIO_TIMCTL_TIMOD(3) | FLEXIO_TIMCTL_PINCFG(3) |
203 FLEXIO_TIMCTL_PINSEL(17);
204 flexio->port().TIMCFG[t_ic_second] = FLEXIO_TIMCFG_TIMDEC(1) | FLEXIO_TIMCFG_TIMRST(0) |
205 FLEXIO_TIMCFG_TIMDIS(1) | FLEXIO_TIMCFG_TIMENA(1) |
206 FLEXIO_TIMCFG_TIMOUT(1);
207 flexio->port().TIMCMP[t_ic_second] = factors.second;
208 //}
209
210 // Configure state shifter
211 flexio->port().SHIFTCTL[s_ic] =
212 FLEXIO_SHIFTCTL_TIMSEL(t_state_check) | FLEXIO_SHIFTCTL_PINCFG(3) | FLEXIO_SHIFTCTL_PINSEL(15) | FLEXIO_SHIFTCTL_SMOD_STATE;
213 flexio->port().SHIFTCFG[s_ic] = 0;
214 flexio->port().SHIFTBUF[s_ic] =
215 FLEXIO_STATE_SHIFTBUF(0b11101111, s_ic, s_ic, s_ic, s_ic, s_op, s_op, s_op, s_op);
216
217 //
218 // Configure OP state.
219 //
220 // State changes are triggered continuously as fast as possible,
221 // but we only leave OP when the correct input is set.
222 //
223
224 // Sanity check op_time_ns, which we will count with two 16bit timers (=32bit) at CLK_FREQ
225 // Also, we don't really want to do extremely short OP times (for now?)
226 if (op_time_ns < 100 or op_time_ns > 9'000'000'000) {
227 LOG_ERROR("FlexIOControl: Requested op_time_ns cannot be represented by 32bit.");
228 return false;
229 }
230
231 // Configure a timer to set an input pin high, signaling end of op_time
232 if (op_time_ns < 0xFFFFull * 1000ull / CLK_FREQ_MHz) {
233 // One 16bit timer is enough actually
234 flexio->port().TIMCTL[t_op] = FLEXIO_TIMCTL_TRGSEL_STATE(s_op) | FLEXIO_TIMCTL_TIMOD(3) |
235 FLEXIO_TIMCTL_PINCFG(3) | FLEXIO_TIMCTL_PINSEL(12);
236 flexio->port().TIMCFG[t_op] =
237 FLEXIO_TIMCFG_TIMRST(6) | FLEXIO_TIMCFG_TIMDIS(0b110) | FLEXIO_TIMCFG_TIMENA(6) | FLEXIO_TIMCFG_TIMOUT(1);
238 flexio->port().TIMCMP[t_op] = op_time_ns * CLK_FREQ_MHz / 1000;
239
240 // Reset second timer used when going towards higher op_times
241 flexio->port().TIMCTL[t_op_second] = 0;
242 flexio->port().TIMCFG[t_op_second] = 0;
243 flexio->port().TIMCMP[t_op_second] = 0;
244 } else {
245 // Configure first timer as pre-scaler
246 // But we want to pre-scale as much as possible, even though we then lose resolution
247 // But for op times in the range of seconds, we don't need microseconds resolution
248
249 auto factors = utils::factorize(op_time_ns * CLK_FREQ_MHz / 1000);
250 if (factors.first >= 1 << 16 ||
251 factors.second >= 1 << 16) // Factror even is too big for two cascaded timers
252 return false;
253
254 flexio->port().TIMCTL[t_op] =
255 FLEXIO_TIMCTL_TRGSEL_STATE(s_op) | FLEXIO_TIMCTL_TIMOD(3) | FLEXIO_TIMCTL_PINPOL;
256 flexio->port().TIMCFG[t_op] =
257 FLEXIO_TIMCFG_TIMRST(6) | FLEXIO_TIMCFG_TIMDIS(0b110) | FLEXIO_TIMCFG_TIMENA(6);
258 flexio->port().TIMCMP[t_op] = factors.first - 1;
259 // Configure second timer for 32bit total
260 flexio->port().TIMCTL[t_op_second] = FLEXIO_TIMCTL_TRGSEL(4 * t_op + 3) | FLEXIO_TIMCTL_TRGSRC |
261 FLEXIO_TIMCTL_TIMOD(3) | FLEXIO_TIMCTL_PINCFG(3) |
262 FLEXIO_TIMCTL_PINSEL(12);
263 flexio->port().TIMCFG[t_op_second] =
264 FLEXIO_TIMCFG_TIMDEC(1) | FLEXIO_TIMCFG_TIMRST(0) | FLEXIO_TIMCFG_TIMDIS(1) | FLEXIO_TIMCFG_TIMENA(1) | FLEXIO_TIMCFG_TIMOUT(1);
265 flexio->port().TIMCMP[t_op_second] = factors.second;
266 }
267
268 // Configure state shifter
269 flexio->port().SHIFTCTL[s_op] = FLEXIO_SHIFTCTL_TIMSEL(t_state_check) | FLEXIO_SHIFTCTL_PINCFG(3) |
270 FLEXIO_SHIFTCTL_PINSEL(10) | FLEXIO_SHIFTCTL_SMOD_STATE;
271 flexio->port().SHIFTCFG[s_op] = 0;
272 // Next state after OP depends on FlexIO inputs 10 (0 if overload), 11 (0 if exthalt), 12 (1 if op time over)
273 // Check with priority op-time-over > overload > ext halt
274 // Comments are t/T whether op-time-over, o/O whether overload active, e/E wether ext halt is true
275 uint8_t next_if_overload_and_exthalt = s_op, next_if_overload = s_op, next_if_exthalt = s_op;
276 switch (on_ext_halt) {
278 next_if_exthalt = s_op;
279 break;
281 next_if_exthalt = s_exthalt;
282 break;
283 }
284 switch (on_overload) {
286 next_if_overload = s_op;
287 next_if_overload_and_exthalt = next_if_exthalt;
288 break;
289 case OnOverload::HALT:
290 next_if_overload = s_overload;
291 next_if_overload_and_exthalt = s_overload;
292 break;
293 }
294 flexio->port().SHIFTBUF[s_op] = FLEXIO_STATE_SHIFTBUF(0b11011111, // Inputs [12-11-10]
295 next_if_overload_and_exthalt, // [0-0-0] = [t-E-O]
296 next_if_exthalt, // [0-0-1] = [t-E-o]
297 next_if_overload, // [0-1-0] = [t-e-O]
298 s_op, // [0-1-1] = [t-e-o]
299 s_end, // [1-0-0] = [T-E-O]
300 s_end, // [1-0-1] = [T-E-o]
301 s_end, // [1-1-0] = [T-e-O]
302 s_end // [1-1-1] = [T-e-o]
303 );
304
305 //
306 // Configure END state.
307 //
308
309 flexio->port().SHIFTCTL[s_end] = FLEXIO_SHIFTCTL_PINCFG(3) | FLEXIO_SHIFTCTL_SMOD_STATE;
310 flexio->port().SHIFTCFG[s_end] = 0;
311 flexio->port().SHIFTBUF[s_end] = FLEXIO_STATE_SHIFTBUF(0b11111111, s_end);
312
313 //
314 // Configure OVERLOAD state.
315 //
316
317 flexio->port().SHIFTCTL[s_overload] = FLEXIO_SHIFTCTL_PINCFG(3) | FLEXIO_SHIFTCTL_SMOD_STATE;
318 flexio->port().SHIFTCFG[s_overload] = 0;
319 flexio->port().SHIFTBUF[s_overload] = FLEXIO_STATE_SHIFTBUF(0b11111111, s_overload);
320
321 //
322 // Configure EXT HALT state.
323 //
324
325 // EXT HALT is a paused state which resumes as soon as the signal is no longer active.
326 // But "resuming" is only partially correct, since the full op time is restarted.
327 // Thus, the OP state after EXT HALT runs for the full OP time, not just the remainder.
328 // This can be solved similarly to the ADC by gating a timer with the OP signal,
329 // but that requires additional connections on the PCB.
330 // For all currently envisioned EXT HALT applications (e.g. control-systems), this is okay.
331 flexio->port().SHIFTCTL[s_exthalt] = FLEXIO_SHIFTCTL_TIMSEL(t_state_check) | FLEXIO_SHIFTCTL_PINCFG(3) |
332 FLEXIO_SHIFTCTL_PINSEL(10) | FLEXIO_SHIFTCTL_SMOD_STATE;
333 flexio->port().SHIFTCFG[s_exthalt] = 0;
334 // When selecting next state based on inputs [12-11-10], ignore anything but EXT HALT (11).
335 flexio->port().SHIFTBUF[s_exthalt] =
336 FLEXIO_STATE_SHIFTBUF(0b11111111, s_exthalt, s_exthalt, s_op, s_op, s_exthalt, s_exthalt, s_op, s_op);
337
338 //
339 // Configure miscellaneous flexio stuff
340 //
341
342 // Put relevant pins into FlexIO mode
344 if (flexio->mapIOPinToFlexPin(pin) == 0xff) {
345 return false;
346 }
347 flexio->setIOPinToFlexMode(pin);
348 }
349
350 enable();
351 _is_initialized = true;
352 return true;
353}
354
356 auto flexio = FlexIOHandler::flexIOHandler_list[2];
357 flexio->port().CTRL &= ~FLEXIO_CTRL_FLEXEN;
358 _is_enabled = false;
359}
360
362 auto flexio = FlexIOHandler::flexIOHandler_list[2];
363 flexio->port().CTRL |= FLEXIO_CTRL_FLEXEN;
364 _is_enabled = true;
365}
366
368
370 auto flexio = FlexIOHandler::flexIOHandler_list[2];
371 flexio->port().SHIFTSTATE = s_idle;
373}
374
376 auto flexio = FlexIOHandler::flexIOHandler_list[2];
377 flexio->port().SHIFTSTATE = s_ic;
379}
380
382 auto flexio = FlexIOHandler::flexIOHandler_list[2];
383 flexio->port().SHIFTSTATE = s_op;
385}
386
388 auto flexio = FlexIOHandler::flexIOHandler_list[2];
389 flexio->port().SHIFTSTATE = s_exthalt;
391}
392
394 auto flexio = FlexIOHandler::flexIOHandler_list[2];
395 flexio->port().SHIFTSTATE = s_end;
397}
398
400 disable();
401 delayMicroseconds(1);
402 auto flexio = FlexIOHandler::flexIOHandler_list[2];
403 flexio->port().CTRL |= FLEXIO_CTRL_SWRST;
404 delayMicroseconds(1);
405 flexio->port().CTRL &= ~FLEXIO_CTRL_SWRST;
406 delayMicroseconds(1);
407}
408
410 while (!is_done()) {
411 }
412}
413
415 TMR1_CNTR1 = 0;
416 TMR1_CNTR2 = 0;
417}
418
420 CCM_CCGR6 |= CCM_CCGR6_QTIMER1(CCM_CCGR_ON);
421
422 // Configure timer 1 of first QTMR module to do input-gated counting
423 TMR1_CTRL1 = 0; // stop
424 TMR1_CNTR1 = 0; // reset counter
425 TMR1_SCTRL1 = 0;
426 TMR1_LOAD1 = 0;
427 TMR1_CSCTRL1 = 0;
428 TMR1_LOAD1 = 0; // start val after compare
429 TMR1_COMP11 = 0xffff; // count up to this val, interrupt, and start again
430 TMR1_CMPLD11 = 0xffff;
431 // Set CM=0 for now, enable later, select fastest clock with PCS, select gating signal with SCS
432 TMR1_CTRL1 = TMR_CTRL_CM(0) | TMR_CTRL_PCS(8) | TMR_CTRL_SCS(1);
433 // Invert secondary signal (gating when HIGH, counting when LOW)
434 TMR1_SCTRL1 = TMR_SCTRL_IPS;
435
436 // Configure timer 2 of first QTMR module to cascade from timer 1
437 TMR1_CTRL2 = 0;
438 TMR1_CNTR2 = 0; // reset counter
439 TMR1_SCTRL2 = 0;
440 TMR1_LOAD2 = 0;
441 TMR1_CSCTRL2 = 0;
442 TMR1_LOAD2 = 0; // start val after compare
443 TMR1_COMP12 = 0xffff; // count up to this val and start again
444 TMR1_CMPLD12 = 0xffff;
445 // Set CM=0 for now, enable later, select first timer with PCS
446 TMR1_CTRL2 = TMR_CTRL_CM(0) | TMR_CTRL_PCS(4 + 1);
447
448 // Put PIN_QTMR_OP_GATE in QTimer mode
449 *(portConfigRegister(PIN_QTMR_OP_GATE)) = 1; // ALT 1
450 // Enable timers in reverse order
451 TMR1_CTRL2 |= TMR_CTRL_CM(7);
452 TMR1_CTRL1 |= TMR_CTRL_CM(3);
453}
454
456 // TODO: This is currently measured, but of course it can be calculated
457 return (TMR1_CNTR2 * 0xFFFF + TMR1_CNTR1) * 671 / 100;
458}
459
461 auto flexio = FlexIOHandler::flexIOHandler_list[2];
462 return flexio->port().SHIFTSTATE == s_idle;
463}
464
466 auto flexio = FlexIOHandler::flexIOHandler_list[2];
467 return flexio->port().SHIFTSTATE == s_op;
468}
469
471 auto flexio = FlexIOHandler::flexIOHandler_list[2];
472 auto state = flexio->port().SHIFTSTATE;
473 return state == s_end or state == s_overload;
474}
475
477 auto flexio = FlexIOHandler::flexIOHandler_list[2];
478 return flexio->port().SHIFTSTATE == s_overload;
479}
480
482 auto flexio = FlexIOHandler::flexIOHandler_list[2];
483 return flexio->port().SHIFTSTATE == s_exthalt;
484}
static void to_exthalt()
Definition mode.cpp:387
static void disable()
Definition mode.cpp:355
static void to_end()
Definition mode.cpp:393
static void _reset_qtmr_op()
Definition mode.cpp:414
static bool is_op()
Definition mode.cpp:465
static bool is_idle()
Definition mode.cpp:460
static bool is_initialized()
Definition mode.h:142
static unsigned long long get_actual_op_time()
Definition mode.cpp:455
static bool is_done()
Definition mode.cpp:470
static void reset()
Definition mode.cpp:399
static bool is_enabled()
Definition mode.h:146
static void to_ic()
Definition mode.cpp:375
static void to_op()
Definition mode.cpp:381
static void delay_till_done()
Definition mode.cpp:409
static void force_start()
Definition mode.cpp:367
static void to_idle()
Definition mode.cpp:369
static bool is_overloaded()
Definition mode.cpp:476
static void enable()
Definition mode.cpp:361
static void _init_qtmr_op()
Definition mode.cpp:419
static bool init(unsigned long long ic_time_ns, unsigned long long op_time_ns, mode::OnOverload on_overload=mode::OnOverload::HALT, mode::OnExtHalt on_ext_halt=mode::OnExtHalt::IGNORE, mode::Sync sync=mode::Sync::NONE)
Definition mode.cpp:89
static bool is_exthalt()
Definition mode.cpp:481
static void to_op()
Definition mode.cpp:28
static void init()
Definition mode.cpp:13
static void to_ic()
Definition mode.cpp:22
static void to_halt()
Definition mode.cpp:34
void to(mode::Mode new_mode)
Manual Mode tracking.
Definition counters.cpp:11
static void disable()
Definition mode.cpp:48
static void to_ic()
Definition mode.cpp:58
static void to_halt()
Definition mode.cpp:76
static void enable()
Definition mode.cpp:40
static void to_op()
Definition mode.cpp:67
static PerformanceCounter & get()
Definition singleton.h:48
#define LOG_ERROR(message)
Definition logging.h:37
OnOverload
Definition mode.h:26
constexpr uint8_t PIN_MODE_OP
Definition mode.h:16
constexpr uint8_t PIN_SYNC_CLK
Definition mode.h:19
constexpr uint8_t PIN_MODE_IC
Definition mode.h:15
Sync
Definition mode.h:38
OnExtHalt
Definition mode.h:32
constexpr uint8_t PIN_QTMR_OP_GATE
Definition mode.h:21
constexpr uint8_t PIN_MODE_EXTHALT
Definition mode.h:18
constexpr uint8_t PIN_MODE_OVERLOAD
Definition mode.h:17
constexpr uint8_t PIN_SYNC_ID
Definition mode.h:20
std::pair< unsigned long long, unsigned long long > factorize(unsigned long long input, unsigned int acceptable_delta=10)
Definition factorize.cpp:12