DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
dshot.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file dshot.cpp
6 * @brief DShot ESC throttle protocol codec (see dshot.h).
7 */
8
10
11#if DETWS_ENABLE_DSHOT
12
13namespace
14{
15// The DShot CRC: xor of the three 4-bit nibbles of the 12-bit (value<<1 | telemetry) word.
16uint8_t dshot_crc(uint16_t v12, bool bidirectional)
17{
18 uint8_t crc = (uint8_t)((v12 ^ (v12 >> 4) ^ (v12 >> 8)) & 0x0F);
19 if (bidirectional)
20 crc = (uint8_t)((~crc) & 0x0F); // bidirectional/extended DShot inverts the CRC
21 return crc;
22}
23} // namespace
24
25uint16_t detws_dshot_encode(uint16_t value11, bool telemetry, bool bidirectional)
26{
27 value11 &= 0x07FF; // 11-bit value field
28 uint16_t v12 = (uint16_t)((value11 << 1) | (telemetry ? 1 : 0));
29 uint8_t crc = dshot_crc(v12, bidirectional);
30 return (uint16_t)((v12 << 4) | crc);
31}
32
33bool detws_dshot_decode(uint16_t frame, uint16_t *value11, bool *telemetry, bool bidirectional)
34{
35 uint16_t v12 = (uint16_t)(frame >> 4);
36 uint8_t got = (uint8_t)(frame & 0x0F);
37 if (got != dshot_crc(v12, bidirectional))
38 return false;
39 if (value11)
40 *value11 = (uint16_t)(v12 >> 1);
41 if (telemetry)
42 *telemetry = (v12 & 1) != 0;
43 return true;
44}
45
46uint32_t detws_dshot_bit_ns(uint16_t rate_kbit, bool bit)
47{
48 uint32_t period_ns; // one bit-period, in ns, at rate_kbit kbit/s
49 switch (rate_kbit)
50 {
51 case 150:
52 period_ns = 6667;
53 break;
54 case 300:
55 period_ns = 3333;
56 break;
57 case 600:
58 period_ns = 1667;
59 break;
60 case 1200:
61 period_ns = 833;
62 break;
63 default:
64 return 0;
65 }
66 // A "1" holds high ~3/4 of the period, a "0" ~3/8 (T1H = 2 * T0H); the ESC samples the pulse width.
67 return bit ? (period_ns * 3 / 4) : (period_ns * 3 / 8);
68}
69
70uint32_t detws_esc_pwm_ns(uint16_t throttle_1000, DetwsEscPwm mode)
71{
72 uint32_t lo;
73 uint32_t hi; // pulse width range in ns
74 switch (mode)
75 {
76 case DetwsEscPwm::DETWS_ESC_ONESHOT125:
77 lo = 125000;
78 hi = 250000;
79 break;
80 case DetwsEscPwm::DETWS_ESC_ONESHOT42:
81 lo = 42000;
82 hi = 84000;
83 break;
84 case DetwsEscPwm::DETWS_ESC_MULTISHOT:
85 lo = 5000;
86 hi = 25000;
87 break;
88 case DetwsEscPwm::DETWS_ESC_PWM:
89 default:
90 lo = 1000000;
91 hi = 2000000;
92 break;
93 }
94 if (throttle_1000 > 1000)
95 throttle_1000 = 1000;
96 // Linear map, computed in 64-bit to avoid overflow (hi-lo up to 1e6, * 1000).
97 return lo + (uint32_t)(((uint64_t)(hi - lo) * throttle_1000) / 1000);
98}
99
100#endif // DETWS_ENABLE_DSHOT
DShot ESC digital throttle protocol codec (DETWS_ENABLE_DSHOT).