├── .clang-format
├── .devcontainer
└── devcontainer.json
├── .gitattributes
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug-report.yml
│ ├── config.yml
│ ├── devboard-request.yml
│ └── feature-request.yml
└── workflows
│ ├── codeql.yml
│ └── quality_control.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── examples
├── flight_modes
│ └── flight_modes.ino
├── link_stats
│ └── link_stats.ino
├── platformio
│ └── main.cpp
├── rc_channels
│ └── rc_channels.ino
└── telemetry
│ └── telemetry.ino
├── keywords.txt
├── library.json
├── library.properties
└── src
├── CFA_Config.hpp
├── CRSFforArduino.cpp
├── CRSFforArduino.hpp
├── SerialReceiver
├── CRC
│ ├── CRC.cpp
│ └── CRC.hpp
├── CRSF
│ ├── CRSF.cpp
│ ├── CRSF.hpp
│ └── CRSFProtocol.hpp
├── SerialBuffer
│ ├── SerialBuffer.cpp
│ └── SerialBuffer.hpp
├── SerialReceiver.cpp
├── SerialReceiver.hpp
└── Telemetry
│ ├── Telemetry.cpp
│ └── Telemetry.hpp
├── build
├── scripts
│ ├── build.py
│ └── platformio.ini
└── targets
│ ├── common.ini
│ ├── quality_control.ini
│ ├── unified_esp32.ini
│ ├── unified_rp2040.ini
│ ├── unified_samd21.ini
│ ├── unified_samd51.ini
│ ├── unified_stm32.ini
│ ├── unified_teensy3x.ini
│ └── unified_teensy4x.ini
└── hal
└── CompatibilityTable
├── CompatibilityTable.cpp
└── CompatibilityTable.hpp
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | BasedOnStyle: GNU
4 | AccessModifierOffset: -2
5 | AlignAfterOpenBracket: Align
6 | AlignConsecutiveMacros: true
7 | AlignConsecutiveAssignments: false
8 | AlignConsecutiveBitFields: true
9 | AlignConsecutiveDeclarations: false
10 | AlignEscapedNewlines: Right
11 | AlignOperands: Align
12 | AlignTrailingComments: true
13 | AllowAllArgumentsOnNextLine: true
14 | AllowAllConstructorInitializersOnNextLine: true
15 | AllowAllParametersOfDeclarationOnNextLine: true
16 | AllowShortEnumsOnASingleLine: false
17 | AllowShortBlocksOnASingleLine: Never
18 | AllowShortCaseLabelsOnASingleLine: false
19 | AllowShortFunctionsOnASingleLine: false
20 | AllowShortLambdasOnASingleLine: Empty
21 | AllowShortIfStatementsOnASingleLine: Never
22 | AllowShortLoopsOnASingleLine: false
23 | AlwaysBreakAfterDefinitionReturnType: None
24 | AlwaysBreakAfterReturnType: None
25 | AlwaysBreakBeforeMultilineStrings: false
26 | AlwaysBreakTemplateDeclarations: MultiLine
27 | BinPackArguments: true
28 | BinPackParameters: true
29 | BraceWrapping:
30 | AfterCaseLabel: true
31 | AfterClass: true
32 | AfterControlStatement: Always
33 | AfterEnum: true
34 | AfterFunction: true
35 | AfterNamespace: true
36 | AfterObjCDeclaration: false
37 | AfterStruct: true
38 | AfterUnion: true
39 | AfterExternBlock: true
40 | BeforeCatch: true
41 | BeforeElse: true
42 | BeforeLambdaBody: false
43 | BeforeWhile: false
44 | IndentBraces: false
45 | SplitEmptyFunction: false
46 | SplitEmptyRecord: false
47 | SplitEmptyNamespace: false
48 | BreakBeforeBinaryOperators: None
49 | BreakBeforeBraces: Custom
50 | BreakBeforeInheritanceComma: false
51 | BreakInheritanceList: AfterColon
52 | BreakBeforeTernaryOperators: true
53 | # BreakConstructorInitializersBeforeComma: false
54 | BreakConstructorInitializers: AfterColon
55 | BreakAfterJavaFieldAnnotations: false
56 | BreakStringLiterals: true
57 | ColumnLimit: 0
58 | CommentPragmas: '^ IWYU pragma:'
59 | CompactNamespaces: false
60 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
61 | ConstructorInitializerIndentWidth: 4
62 | ContinuationIndentWidth: 4
63 | Cpp11BracedListStyle: true
64 | DeriveLineEnding: true
65 | DerivePointerAlignment: false
66 | DisableFormat: false
67 | ExperimentalAutoDetectBinPacking: false
68 | FixNamespaceComments: true
69 | ForEachMacros:
70 | - foreach
71 | - Q_FOREACH
72 | - BOOST_FOREACH
73 | IncludeBlocks: Preserve
74 | IncludeCategories:
75 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
76 | Priority: 2
77 | SortPriority: 0
78 | - Regex: '^(<|"(gtest|gmock|isl|json)/)'
79 | Priority: 3
80 | SortPriority: 0
81 | - Regex: '.*'
82 | Priority: 1
83 | SortPriority: 0
84 | IncludeIsMainRegex: '(Test)?$'
85 | IncludeIsMainSourceRegex: ''
86 | IndentCaseLabels: true
87 | IndentCaseBlocks: true
88 | IndentGotoLabels: true
89 | IndentPPDirectives: None
90 | IndentExternBlock: AfterExternBlock
91 | IndentWidth: 4
92 | IndentWrappedFunctionNames: false
93 | InsertTrailingCommas: None
94 | JavaScriptQuotes: Leave
95 | JavaScriptWrapImports: true
96 | KeepEmptyLinesAtTheStartOfBlocks: true
97 | MacroBlockBegin: ''
98 | MacroBlockEnd: ''
99 | MaxEmptyLinesToKeep: 1
100 | NamespaceIndentation: All
101 | ObjCBinPackProtocolList: Auto
102 | ObjCBlockIndentWidth: 2
103 | ObjCBreakBeforeNestedBlockParam: true
104 | ObjCSpaceAfterProperty: false
105 | ObjCSpaceBeforeProtocolList: true
106 | PenaltyBreakAssignment: 2
107 | PenaltyBreakBeforeFirstCallParameter: 19
108 | PenaltyBreakComment: 300
109 | PenaltyBreakFirstLessLess: 120
110 | PenaltyBreakString: 1000
111 | PenaltyBreakTemplateDeclaration: 10
112 | PenaltyExcessCharacter: 1000000
113 | PenaltyReturnTypeOnItsOwnLine: 60
114 | PointerAlignment: Right
115 | ReflowComments: false
116 | SortIncludes: true
117 | SortUsingDeclarations: true
118 | SpaceAfterCStyleCast: false
119 | SpaceAfterLogicalNot: false
120 | SpaceAfterTemplateKeyword: true
121 | SpaceBeforeAssignmentOperators: true
122 | SpaceBeforeCpp11BracedList: false
123 | SpaceBeforeCtorInitializerColon: true
124 | SpaceBeforeInheritanceColon: true
125 | SpaceBeforeParens: ControlStatements
126 | SpaceBeforeRangeBasedForLoopColon: true
127 | SpaceInEmptyBlock: false
128 | SpaceInEmptyParentheses: false
129 | SpacesBeforeTrailingComments: 1
130 | SpacesInAngles: false
131 | SpacesInConditionalStatement: false
132 | SpacesInContainerLiterals: false
133 | SpacesInCStyleCastParentheses: false
134 | SpacesInParentheses: false
135 | SpacesInSquareBrackets: false
136 | SpaceBeforeSquareBrackets: false
137 | BitFieldColonSpacing: Both
138 | Standard: Latest
139 | StatementMacros:
140 | - Q_UNUSED
141 | - QT_REQUIRE_VERSION
142 | TabWidth: 8
143 | UseCRLF: false
144 | UseTab: Never
145 | WhitespaceSensitiveMacros:
146 | - STRINGIZE
147 | - PP_STRINGIZE
148 | - BOOST_PP_STRINGIZE
149 | ...
150 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CRSFforArduino development container",
3 | "image": "mcr.microsoft.com/devcontainers/python:3.11",
4 | "postCreateCommand": "pip install platformio",
5 | "postStartCommand": "sudo groupadd -g 986 uucp || true && sudo usermod -aG uucp vscode",
6 | "customizations": {
7 | "vscode": {
8 | "extensions": [
9 | "donjayamanne.githistory",
10 | "eamodio.gitlens",
11 | "github.vscode-github-actions",
12 | "GitHub.vscode-pull-request-github",
13 | "ms-vscode.cpptools",
14 | "ms-vscode.cpptools-extension-pack",
15 | "ms-vscode.cpptools-themes",
16 | "platformio.platformio-ide",
17 | "streetsidesoftware.code-spell-checker",
18 | "streetsidesoftware.code-spell-checker-australian-english",
19 | "vivaxy.vscode-conventional-commits",
20 | "xaver.clang-format"
21 | ]
22 | }
23 | },
24 | "runArgs": [
25 | "--device=/dev/ttyACM0",
26 | "--group-add=986"
27 | ],
28 | "mounts": [
29 | "source=/dev/bus/usb,target=/dev/bus/usb,type=bind"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.c text eol=lf
2 | *.cpp text eol=lf
3 | *.h text eol=lf
4 | *.hpp text eol=lf
5 | *.ini text eol=lf
6 | *.ino text eol=lf
7 | *.json text eol=lf
8 | *.md text eol=lf
9 | *.properties text eol=lf
10 | *.txt text eol=lf
11 | *.yml text eol=lf
12 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to CRSF for Arduino
2 |
3 | Thank you for helping to make CRSF for Arduino better.
4 | Before you can go Gung Ho on coding, there are a few house rules I need you to familiarise yourself with.
5 |
6 | ## Do's and don'ts of CRSF for Arduino
7 |
8 | ### **Do...**
9 |
10 | 1. Read the README in its entirety _before_ submitting an issue, as your "bug" may very well be a case of PICNIC.
11 | 2. Respond in a timely and respectful manner.
12 | 3. If something isn't working, please provide evidence - EG Screenshots of compiler errors.
13 | 4. Provide concise details.
14 | 5. For general feedback, comments and questions, use the [Discussions Tab](https://github.com/ZZ-Cat/CRSFforArduino/discussions).
15 | 6. Format your code. CRSF for Arduino uses clang-format as a formatter. So, use that if you actually want to contribute to CRSF for Arduino's development.
16 |
17 | ### **Don't...**
18 |
19 | 1. Use CRSF for Arduino on incompatible hardware and write me an issue about "strange behaviour".
20 | 2. Ghost me for more than 14 consecutive days.
21 | 3. Write things like "This isn't working" and refuse to provide any information &/or context beyond that.
22 | 4. Write walls of text. Do this and watch how quickly I mark your issue as "TL;DR" and close it without any response from me.
23 | 5. Beg for updates. Please don't do this. If you do, I will intentionally take longer to release said update to spite you.
24 | 6. Assume that the project is "dead" after any significant amount of time has passed.
25 |
26 | ## A few notable points
27 |
28 | - CRSF for Arduino requires _all_ commits to be properly signed and verfied.
29 | This means that you _must_ have commit signing with either an SSH or GPG key set-up.
30 | Pull Requests with unverified commits _will not_ be accepted.
31 | - Not every Pull Request can or will be accepted.
32 | Simply because you submitted it, that doesn't automatically guarantee that your Pull Request will be merged.
33 | Generally speaking, I will let you know as to why your Pull Request will not be merged. Nine-times-out-of-ten, it's because of something that's easily fixable within reason.
34 | - I reserve the right to decline any Pull Request(s) if I deem it necessary to do so.
35 | - All Pull Requests to the Main-Trunk _must_ be reviewed before they can be merged.
36 | If I suggest to you to make changes to your Pull Request, don't fight me on it. I already have a reason why those changes need to be made and I would have told you what that reason is. If you are having difficulty with something, let me know.
37 | - All checks on your Pull Request _must_ pass before it can be merged.
38 | These checks ensure correct code formatting, and the codebase compiles successfully on all supported development boards.
39 |
40 | ## Ghosting
41 |
42 | ### What is it?
43 |
44 | This describes a situation where I have not received any interaction from you over a signifcant amount of time.
45 | I define "a significant amount of time" to be three weeks or more.
46 | For example, if you open an issue, and I ask for clarification on said issue and you have not replied to that message over a significant amount of time. This is ghosting.
47 | Another example is I tag you in a Pull Request because I require your assistance, yet there has not been any dialog from you over a significant amount of time. That is also ghosting.
48 |
49 | ### Why is ghosting bad?
50 |
51 | Short answer: It's unprofessional.
52 |
53 | Consider this scenario:
54 | You submit an Issue, requesting compatibility for your development board.
55 | I don't have the board-in-question available to me on-hand to test on my own end, so I elect to enlist your assistance.
56 | I go ahead and open a Pull Request, tagging you in it (and asking you to test the Pull Request).
57 | Only...
58 | One week passes. Okay, they're probably busy with life stuff and maybe they will respond over the weekend.
59 | Weekend comes... still no response. Okay, I will give them another week.
60 | Second week comes... still no response. Maybe if I give them another week? Hopefully they might respond?.
61 | Third week goes by... still no response, and CRSF for Arduino's development has stalled.
62 |
63 | ### How I combat it
64 |
65 | For a start, I have a grace period of up to 14 days past the last interaction you have had with me.
66 | After the 14 days is up, I decide (at my discretion) to close your Issue or Pull Request. In the context of a Pull Request, depending on the state of the code (EG Accuracy, completeness and functionality), at my discretion, I may merge the Pull Request "as-is", and any potential bugs that it could introduce (that I may have missed), you are welcome to open an Issue about it later on.
67 |
68 | This grace period exists to mitigate stalled development, and keep the development of CRSF for Arduino moving along.
69 | People that genuinely want to help out with the project, they typically respond within 24~72 hours, with some outlying exceptions responding up to 7~12 days apart.
70 | This grace period strikes a balance between my need to keep the project moving, and giving someone time to do what they need to do in their own private life as well as contributing to CRSF for Arduino.
71 |
72 | ## For more information
73 |
74 | - [About forks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks)
75 | - [Creating a Pull Request from your fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork)
76 | - [Code of Conduct](/CODE_OF_CONDUCT.md)
77 | - [Submit an Issue](https://github.com/ZZ-Cat/CRSFforArduino/issues/new/choose)
78 | - [License](/LICENSE.md)
79 | - [README](/README.md)
80 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: Submit a bug report
2 | description: Create a bug report and help me improve CRSF for Arduino
3 | labels: ["🐞 Bug 🐞", "Pending 📌"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thank you for taking the time to report a bug in CRSF for Arduino.
9 | Please fill out the form below to help me improve CRSF for Arduino.
10 | - type: checkboxes
11 | attributes:
12 | label: Is there an existing issue for this bug?
13 | description: Please check if there is already an issue for this bug.
14 | options:
15 | - label: I have searched the issues and there is no existing issue for this bug.
16 | required: true
17 | - type: dropdown
18 | id: development-environment
19 | attributes:
20 | label: What development environment are you using?
21 | description: Are you using the Arduino IDE or PlatformIO?
22 | options:
23 | - Arduino IDE
24 | - PlatformIO
25 | validations:
26 | required: true
27 | - type: dropdown
28 | id: board
29 | attributes:
30 | label: What board are you using?
31 | description: |
32 | Please select the board you are using.
33 | Please note that only the boards listed below are supported.
34 | options:
35 | - Adafruit Feather ESP32
36 | - Adafruit Feather ESP32-S2
37 | - Adafruit Feather ESP32-S3 (2 MB PSRAM)
38 | - Adafruit Feather ESP32-S3 (No PSRAM)
39 | - Adafruit Feather F405
40 | - Adafruit Feather M0 (Any variants EG Bluefruit LE, LoRa, etc)
41 | - Adafruit Feather M0 Express
42 | - Adafruit Feather M4 Express
43 | - Adafruit Feather M4 CAN Express
44 | - Adafruit Grand Central M4
45 | - Adafruit ItsyBitsy ESP32
46 | - Adafruit ItsyBitsy M0 Express
47 | - Adafruit ItsyBitsy M4 Express
48 | - Adafruit Metro ESP32-S2
49 | - Adafruit Metro M0 Express
50 | - Adafruit Metro M4 Express
51 | - Adafruit Metro M4 AirLift Lite
52 | - Adafruit QtPy ESP32 Pico
53 | - Adafruit QtPy ESP32-C3
54 | - Adafruit QtPy ESP32-S2
55 | - Adafruit QtPy ESP32-S3
56 | - Adafruit QtPy M0
57 | - Adafruit Trinket M0
58 | - Arduino MKR 1000
59 | - Arduino MKR FOX 1200
60 | - Arduino MKR GSM 1400
61 | - Arduino MKR NB 1500
62 | - Arduino MKR VIDOR 4000
63 | - Arduino MKR WAN 1300
64 | - Arduino MKR WAN 1310
65 | - Arduino MKR WiFi 1010
66 | - Arduino MKR ZERO
67 | - Arduino Nano 33 IoT
68 | - Arduino Nano RP2040 Connect
69 | - Arduino Nicla Vision
70 | - Arduino Opta
71 | - Arduino Portenta H7
72 | - Arduino Zero
73 | - Black Pill F103C8
74 | - Black Pill F103C8 (128 KB Flash)
75 | - Black Pill F401CC
76 | - Black Pill F411CE
77 | - Blue Pill F103C6
78 | - Blue Pill F103C8
79 | - Blue Pill F103C8 (128 KB Flash)
80 | - Espressif ESP32-C3 DevKitC-02
81 | - Espressif ESP32-C3 DevKitM-1
82 | - Espressif ESP32-S3 DevKitC-1-N8
83 | - Raspberry Pi Pico RP2040
84 | - Seeed Studio Xiao ESP32-C3
85 | - Seeed Studio Xiao ESP32-S3
86 | - Seeed Studio XIAO SAMD21
87 | - SparkFun ESP32 RedBoard IoT
88 | - SparkFun ESP32 Thing
89 | - SparkFun ESP32 Thing Plus
90 | - SparkFun ESP32-S2 Thing Plus
91 | - SparkFun MicroMod F405
92 | - ST Black F407VE
93 | - ST Black F407VG
94 | - ST Black F407ZE
95 | - ST Black F407ZG
96 | - ST Blue F407VE Mini
97 | - ST Discovery F413ZH
98 | - ST Discovery F746NG
99 | - ST Nucleo F401RE
100 | - ST Nucleo F411RE
101 | - ST Nucleo F429ZI
102 | - ST Nucleo F446RE
103 | - ST Nucleo F722ZE
104 | - ST Nucleo F746ZG
105 | - ST Nucleo F756ZG
106 | - ST Nucleo F767ZI
107 | - ST Nucleo H723ZG
108 | - ST Nucleo H743ZI
109 | - STM32F103C6
110 | - STM32F103C8
111 | - STM32F103CB
112 | - STM32F103R6
113 | - STM32F103R8
114 | - STM32F103RB
115 | - STM32F103RC
116 | - STM32F103RD
117 | - STM32F103RE
118 | - STM32F103RF
119 | - STM32F103RG
120 | - STM32F103T6
121 | - STM32F103T8
122 | - STM32F103TB
123 | - STM32F103V8
124 | - STM32F103VB
125 | - STM32F103VC
126 | - STM32F103VD
127 | - STM32F103VE
128 | - STM32F103VF
129 | - STM32F103VG
130 | - STM32F103ZC
131 | - STM32F103ZD
132 | - STM32F103ZE
133 | - STM32F103ZF
134 | - STM32F103ZG
135 | - STM32F401CB
136 | - STM32F401CC
137 | - STM32F401CD
138 | - STM32F401CE
139 | - STM32F401RB
140 | - STM32F401RC
141 | - STM32F401RD
142 | - STM32F401RE
143 | - STM32F405OE
144 | - STM32F405OG
145 | - STM32F405RG
146 | - STM32F405VG
147 | - STM32F405ZG
148 | - STM32F407VE
149 | - STM32F407VG
150 | - STM32F410C8
151 | - STM32F410CB
152 | - STM32F410R8
153 | - STM32F410RB
154 | - STM32F411CE
155 | - STM32F411RC
156 | - STM32F411RE
157 | - STM32F412CE
158 | - STM32F412CG
159 | - STM32F412RE
160 | - STM32F412RG
161 | - STM32f413CG
162 | - STM32F413CH
163 | - STM32F413RG
164 | - STM32F413RH
165 | - STM32F415RG
166 | - STM32F417VE
167 | - STM32F417VG
168 | - STM32F423CH
169 | - STM32F423RH
170 | - STM32F446RC
171 | - STM32F446RE
172 | - STM32F722IC
173 | - STM32F722IE
174 | - STM32F722RC
175 | - STM32F722RE
176 | - STM32F722VC
177 | - STM32F722VE
178 | - STM32F722ZC
179 | - STM32F722ZE
180 | - STM32H745BG
181 | - STM32H745BI
182 | - STM32H745IG
183 | - STM32H745II
184 | - STM32H745ZG
185 | - STM32H745ZI
186 | - STM32H750BT
187 | - Teensy 3.0
188 | - Teensy 3.1/3.2
189 | - Teensy 3.5
190 | - Teensy 3.6
191 | - Teensy 4.0
192 | - Teensy 4.1
193 | validations:
194 | required: true
195 | - type: dropdown
196 | id: bug-type
197 | attributes:
198 | label: What part of CRSF for Arduino is this bug related to?
199 | description: Please select the part of CRSF for Arduino that this bug is related to.
200 | options:
201 | - Build/Compile/Upload
202 | - Compatibility Table
203 | - RC Channels
204 | - Other (please specify)
205 | validations:
206 | required: true
207 | - type: textarea
208 | attributes:
209 | label: Current behaviour
210 | description: Provide a clear and concise description of the bug.
211 | placeholder: |
212 | A clear and concise description of what the bug is.
213 | EG: When I try to compile the code I get this error...
214 | validations:
215 | required: true
216 | - type: textarea
217 | attributes:
218 | label: Expected behaviour
219 | description: Provide a clear and concise description of what you expected to happen.
220 | placeholder: |
221 | A clear and concise description of what you expected to happen.
222 | EG: The code should compile without any errors.
223 | validations:
224 | required: true
225 | - type: textarea
226 | attributes:
227 | label: Steps to reproduce
228 | description: |
229 | Provide a clear and concise description of how to reproduce the bug.
230 | Please include any code that is required to reproduce the bug.
231 | placeholder: |
232 | A clear and concise description of how to reproduce the bug.
233 | EG: To reproduce the bug, compile the code with the following settings...
234 | validations:
235 | required: true
236 | - type: textarea
237 | attributes:
238 | label: Additional information
239 | description: |
240 | Provide any additional information that may be relevant to the bug.
241 | EG: I am using the following version of the Arduino IDE...
242 |
243 | Tip: You can paste code, logs, or config files into the text box below.
244 | Screenshots can also be pasted into the text box below.
245 | validations:
246 | required: false
247 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/devboard-request.yml:
--------------------------------------------------------------------------------
1 | name: Devboard Compatibility Request
2 | description: Tell me which development board you would like me to add to CRSF for Arduino.
3 | labels: ["✨️ Enhancement ✨️", "Pending 📌"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Request your development board to be added to CRSF for Arduino's Compatibility Table.
9 | - type: checkboxes
10 | attributes:
11 | label: Minimum requirements
12 | description: |
13 | Your devboard _must_ meet these requirements in order for it to be compatible with CRSF for Arduino.
14 | Please check your development board's documentation and the data sheet of its host microcontroller for more information.
15 | options:
16 | - label: Core clock speed is 48 MHz or faster?
17 | required: true
18 | - label: Is the CPU an ARM Cortex M0+ or later?
19 | required: true
20 | - label: Does the host microcontroller have at least 32 KB of flash memory?
21 | required: true
22 | - label: Is the host microcontroller's UART peripheral able to support 420,000 (or higher) baud rate(s)?
23 | required: true
24 | - label: Is your development board currently supported in the Arduino IDE?
25 | required: true
26 | - type: textarea
27 | attributes:
28 | label: What development board would you like me to add?
29 | description: |
30 | Provide a clear and concise description of what your devboard is, what its host microcontroller is,
31 | and provide links to the development board's documentation and the data sheet of its host microcontroller.
32 | placeholder: My development board is...
33 | validations:
34 | required: true
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: Submit a feature request
2 | description: Suggest an idea for CRSF for Arduino to help make it better.
3 | labels: ["✨️ Enhancement ✨️", "Pending 📌"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thank you for suggesting an idea for CRSF for Arduino!
9 |
10 | If your idea is still in its early stages or you're not sure if it will benefit my project,
11 | you can open a discussion in the [Ideas](https://github.com/ZZ-Cat/CRSFforArduino/discussions/categories/ideas) category instead.
12 | - type: checkboxes
13 | attributes:
14 | label: Is there already an issue for this?
15 | description: Please check if there is already an issue for this feature request.
16 | options:
17 | - label: I have searched the issues and there is no existing issue for this feature request.
18 | required: true
19 | - type: textarea
20 | attributes:
21 | label: Is your feature request related to a problem?
22 | description: Please provide a clear and concise description of what the problem is.
23 | placeholder: I'm always frustrated when [...]
24 | validations:
25 | required: true
26 | - type: textarea
27 | attributes:
28 | label: Describe the solution you'd like
29 | description: Please provide a clear and concise description of what you want to happen.
30 | placeholder: I'd like to be able to [...]
31 | validations:
32 | required: true
33 | - type: textarea
34 | attributes:
35 | label: Describe alternatives you've considered
36 | description: Please provide a clear and concise description of any alternative solutions or features you've considered.
37 | placeholder: |
38 | I have considered [...]
39 | But it will not work because [...]
40 | validations:
41 | required: true
42 | - type: textarea
43 | attributes:
44 | label: Additional context
45 | description: Please provide any other context or screenshots about the feature request here.
46 | placeholder: |
47 | Add any other context or screenshots about the feature request here.
48 | EG: I am using [...]
49 | EG: I am using the following version of CRSF for Arduino [...]
50 | validations:
51 | required: false
52 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ "Main-Trunk" ]
17 | pull_request:
18 | branches: [ "Main-Trunk" ]
19 | schedule:
20 | - cron: '31 20 * * 6'
21 |
22 | jobs:
23 | analyze:
24 | name: Scan for vulnerabilities
25 | # Runner size impacts CodeQL analysis time. To learn more, please see:
26 | # - https://gh.io/recommended-hardware-resources-for-running-codeql
27 | # - https://gh.io/supported-runners-and-hardware-resources
28 | # - https://gh.io/using-larger-runners
29 | # Consider using larger runners for possible analysis time improvements.
30 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
31 | timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
32 | permissions:
33 | # required for all workflows
34 | security-events: write
35 |
36 | # only required for workflows in private repositories
37 | actions: read
38 | contents: read
39 |
40 | strategy:
41 | fail-fast: false
42 | matrix:
43 | language: [ 'c-cpp', 'python' ]
44 | # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ]
45 | # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both
46 | # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
47 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
48 |
49 | steps:
50 | - name: Checkout repository
51 | uses: actions/checkout@v4
52 |
53 | # Initializes the CodeQL tools for scanning.
54 | - name: Initialize CodeQL
55 | uses: github/codeql-action/init@v3
56 | with:
57 | languages: ${{ matrix.language }}
58 | # If you wish to specify custom queries, you can do so here or in a config file.
59 | # By default, queries listed here will override any specified in a config file.
60 | # Prefix the list here with "+" to use these queries and those in the config file.
61 |
62 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
63 | # queries: security-extended,security-and-quality
64 |
65 |
66 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
67 | # If this step fails, then you should remove it and run the build manually (see below)
68 | # - name: Autobuild
69 | # uses: github/codeql-action/autobuild@v3
70 |
71 | # ℹ️ Command-line programs to run using the OS shell.
72 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
73 |
74 | # If the Autobuild fails above, remove it and uncomment the following three lines.
75 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
76 |
77 | # - run: |
78 | # echo "Run, Build Application using script"
79 | # ./location_of_script_within_repo/buildscript.sh
80 |
81 | # Setup PlatformIO Build Environment
82 | - uses: actions/cache@v4
83 | with:
84 | path: |
85 | ~/.cache/pip
86 | ~/.platformio/.cache
87 | key: ${{ runner.os }}-pio
88 | - uses: actions/setup-python@v5
89 | with:
90 | python-version: '3.9'
91 | - name: Install PlatformIO Core
92 | run: pip install --upgrade platformio
93 |
94 | # Build the Defect Detector with PlatformIO
95 | - name: Build defect detector
96 | run: |
97 | cd src/build/scripts
98 | python build.py
99 |
100 | # Perform CodeQL Analysis
101 | - name: Perform CodeQL Analysis
102 | uses: github/codeql-action/analyze@v3
103 | with:
104 | category: "/language:${{matrix.language}}"
105 |
--------------------------------------------------------------------------------
/.github/workflows/quality_control.yml:
--------------------------------------------------------------------------------
1 | name: Quality Control
2 |
3 | on:
4 | push:
5 | branches: [ "Main-Trunk" ]
6 | pull_request:
7 | branches: [ "Main-Trunk" ]
8 |
9 | jobs:
10 | # Code formatting with clang-format
11 | code_formatting:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - name: Set up Python
16 | uses: actions/setup-python@v5
17 | with:
18 | python-version: '3.x'
19 | - name: Install Adafruit's Arduino CI
20 | uses: actions/checkout@v4.1.1
21 | with:
22 | repository: adafruit/ci-arduino
23 | path: ci
24 | - name: Install ci/actions_install.sh
25 | run: bash ci/actions_install.sh
26 | - name: Check for correct formatting with clang-format
27 | run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
28 |
29 | # New quality control script using Python and PlatformIO.
30 | defect_detector:
31 | runs-on: ubuntu-latest
32 | steps:
33 | - uses: actions/checkout@v4.1.1
34 | - uses: actions/cache@v4
35 | with:
36 | path: |
37 | ~/.cache/pip
38 | ~/.platformio/.cache
39 | key: ${{runner.os}}-pio
40 | - uses: actions/setup-python@v5
41 | with:
42 | python-version: '3.9'
43 | - name: Install PlatformIO
44 | run: pip install --upgrade platformio
45 | - name: Run Quality Control script
46 | run: |
47 | cd src/build/scripts
48 | python build.py --build-on-compatible-devices
49 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Artefacts for compiling the code
2 | .pio/
3 |
4 | # Artefacts for Visual Studio Code
5 | .vscode/
6 |
7 | # PlatformIO specific files
8 | test/README
9 | examples/platformio/cfa_code_test.cpp
10 | examples/platformio/hac_driver_test.cpp
11 | examples/platformio/hw_multi_mutex_test.cpp
12 | examples/platformio/hw_mutex_test.cpp
13 |
14 | # Template files for CRSF for Arduino
15 | templates/
16 |
17 | # Arduino IDE artefacts
18 | .development
19 |
20 | # Developer's notes
21 | notes/
22 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, caste, color, religion, or sexual
10 | identity and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the overall
26 | community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or advances of
31 | any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email address,
35 | without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | I, Cassandra "ZZ Cat" Robinson, am the sole community leader of this project.
42 | I am responsible for clarifying and enforcing our standards of acceptable behavior
43 | and will take appropriate and fair corrective action in response to any behavior
44 | that is deemed inappropriate, threatening, offensive, or harmful.
45 |
46 | I, Cassandra "ZZ Cat" Robinson, as a community leader have the right and
47 | responsibility to remove, edit, or reject comments, commits, code, wiki edits,
48 | issues, and other contributions that are not aligned to this Code of Conduct, and
49 | will communicate reasons for moderation decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to Cassandra "ZZ Cat" Robinson on either her Discord: ZZ Cat#0174 or
63 | her email at nicad.heli.flier@gmail.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series of
86 | actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or permanent
93 | ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within the
113 | community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.1, available at
119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120 |
121 | Community Impact Guidelines were inspired by
122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123 |
124 | For answers to common questions about this code of conduct, see the FAQ at
125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126 | [https://www.contributor-covenant.org/translations][translations].
127 |
128 | [homepage]: https://www.contributor-covenant.org
129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130 | [Mozilla CoC]: https://github.com/mozilla/diversity
131 | [FAQ]: https://www.contributor-covenant.org/faq
132 | [translations]: https://www.contributor-covenant.org/translations
133 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CRSF for Arduino
2 |
3 | [](https://github.com/ZZ-Cat/CRSFforArduino/releases/latest)
4 | [](https://github.com/ZZ-Cat/CRSFforArduino/blob/Main-Trunk/LICENSE.md)
5 | 
6 | [](https://conventionalcommits.org)
7 |
8 | ## Written and developed by
9 |
10 | Cassandra "ZZ Cat" Robinson
11 |
12 | > [!NOTE]
13 | > CRSF for Arduino is now distributed under the [GNU Affero General Public License v3.](https://github.com/ZZ-Cat/CRSFforArduino/blob/Main-Trunk/LICENSE.md)
14 | > Please take the time to familiarise yourself with the terms of this license _before_ you use this library in your projects.
15 |
16 | ## Description
17 |
18 | CRSF for Arduino brings the Crossfire Protocol to the Arduino ecosystem.
19 | This library enables you to connect either a TBS Crossfire or ExpressLRS receiver to your development board,
20 | giving you access to telemetry and up to 16 11-bit proportional RC channels over a tried-and-true serial protocol.
21 |
22 | The Crossfire Protocol (better known as CRSF) is used by both Team BlackSheep (in their Crossfire and Tracer receivers) and
23 | ExpressLRS. The latter of the two are well-known in the FPV drone community for their ultra low latency and long range control
24 | link.
25 | By pairing CRSF for Arduino with an ExpressLRS transmitter and receiver, you have a control link between your RC handset and your development project that is robust in tough RF environments.
26 |
27 | ## Documentation
28 |
29 | CRSF for Arduino's documentation is now live.
30 | Feel free to peruse the [Wiki](https://github.com/ZZ-Cat/CRSFforArduino/wiki) at your leisure.
31 | For new users, it is _strongly_ recommended that you read the documentation in its entirety.
32 |
33 | ## Features
34 |
35 | CRSF for Arduino comes packaged with these features:
36 |
37 | - 16 11-bit proportional RC channels.
38 | - Diverse modern hardware support from the following architectures:
39 | - ESP32, RP2040, SAMD21, SAMD5x, SAME5x, STM32, and Teensy 4.x.
40 | - Flight Modes, both custom and standard.
41 | - Standard Flight Modes are based on the Flight Modes from Betaflight 4.3.
42 | - Custom Flight Modes use text-based strings that you can assign custom names to for your bespoke purposes.
43 | - Both Standard and Custom Flight Modes can be sent as Telemetry back to your controller.
44 | - Event-driven API.
45 | - Fully configurable.
46 | - CRSF for Arduino can be tailored to suit the needs of your individual projects.
47 | - Telemetry.
48 | - Attitude.
49 | - Barometric Altitude.
50 | - Battery.
51 | - Flight Modes.
52 | - GPS.
53 |
54 | ## Software license
55 |
56 | CRSF for Arduino is distributed under a new license: The [GNU Affero GPL v3](https://github.com/ZZ-Cat/CRSFforArduino/blob/Main-Trunk/LICENSE.md).
57 | For regular users, this may be a non-issue for you, as you are already REQUIRED by existing licensing terms to make CRSF for Arduino's source code available (you're already doing this by linking back to its GitHub Repository).
58 | With the upcoming Serial Transmitter Interface, this increases CRSF for Arduino's potential usage in the context of network servers. With the former GPL v3, you could use CRSF for Arduino as a dependency in your network host and never make the source code available to clients. Updating CRSF for Arduino's license to the Affero GPL v3 closes that loop hole, because you are REQUIRED to make the source code of CRSF for Arduino available in _all_ of its distributions.
59 |
60 | Not a lot has changed across licenses. The same basic four freedoms are upheld: Use, copy, modify, and re-distribute.
61 | The only noteworthy change here you are REQUIRED to make the source code available to clients, if you choose to use CRSF for Arduino as a part of your server-side project. To do this, simply link back to this repository via its URL in addition to the terms outlined in the license.
62 |
63 | ## Attributions
64 |
65 | I give credit where credit is due. Because CRSF for Arduino isn't entirely my own idea, but built on the shoulders of giants. Here is a list of credits to those what helped to make this possible:
66 |
67 | - Inspiration for this library
68 | - [ExpressLRS](https://github.com/ExpressLRS)
69 | - [Development Team](https://github.com/orgs/ExpressLRS/people)
70 | - [License](https://github.com/ExpressLRS/ExpressLRS/blob/master/LICENSE)
71 | - [Source Code](https://github.com/ExpressLRS/ExpressLRS)
72 | - [Website](https://www.expresslrs.org/3.0/)
73 | - [Team BlackSheep FPV](https://github.com/tbs-fpv) - The folks behind the CRSF protocol that both ExpressLRS and CRSF for Arduino uses.
74 | - References for CRSF for Arduino
75 | - [BetaFlight](https://github.com/betaflight)
76 | - [Development Team](https://github.com/orgs/betaflight/people)
77 | - [License](https://github.com/betaflight/betaflight/blob/master/LICENSE)
78 | - [Source Code](https://github.com/betaflight/betaflight)
79 | - [Website](https://betaflight.com/)
80 | - [CRSF-WG](https://github.com/crsf-wg/crsf)
81 | - This is the official repository for The CRSF Protocol, which CRSF for Arduino is based on.
82 | - [RotorFlight](https://github.com/rotorflight)
83 | - [Development Team](https://github.com/rotorflight#credits)
84 | - [License](https://github.com/rotorflight/rotorflight-firmware/blob/master/LICENSE)
85 | - [Source Code](https://github.com/rotorflight/rotorflight-firmware)
86 | - Third Party libraries
87 | - [Adafruit Industries](https://github.com/adafruit)
88 | - [Adafruit_ZeroDMA](https://github.com/adafruit/Adafruit_ZeroDMA)
89 | - [Author](https://github.com/PaintYourDragon)
90 | - [License](https://github.com/adafruit/Adafruit_ZeroDMA/blob/master/LICENSE)
91 | - [Website](https://www.adafruit.com/)
92 |
93 | ## Contributing
94 |
95 | If you would like to contribute to the development to CRSF for Arduino, here is what you can do:
96 |
97 | 1. Read my [code of conduct](https://github.com/ZZ-Cat/CRSFforArduino/blob/Main-Trunk/CODE_OF_CONDUCT.md) and [contribution guidelines](https://github.com/ZZ-Cat/CRSFforArduino/blob/Main-Trunk/.github/CONTRIBUTING.md);
98 | 2. Fork CRSF for Arduino;
99 | 3. Make your contribution to the codebase;
100 | 4. Submit your changes in your fork as a Pull Request back to CRSF for Arduino.
101 |
102 | Your contributions are very welcome, and if it benefits the project and community, it will be merged into the Main-Trunk.
103 |
--------------------------------------------------------------------------------
/examples/flight_modes/flight_modes.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * @file flight_modes.ino
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief Example of how to read flight modes from a receiver.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This example is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "CRSFforArduino.hpp"
26 |
27 | /* Tested with the following equipment:
28 | - Controller: RadioMaster TX16S Max Edition Mk1
29 | - Firmware: EdgeTX 2.10.0 Nightly
30 | - Lua Script: iNav OpenTX Telemetry Widget 2.2.3
31 | - Transmitter Module: RadioMaster Ranger
32 | - Firmware: ExpressLRS 3.3.1
33 | - Receiver: RadioMaster RP3 Diversity
34 | - Firmware: ExpressLRS 3.3.1
35 | - Development Board: Adafruit Metro M4 Express
36 | - Board Package: Adafruit SAMD Boards 1.7.5
37 | - Framework: Arduino 1.8.13
38 | - Library: CRSF for Arduino 0.5.0
39 | */
40 |
41 | #define FLIGHT_MODE_ARM_CHANNEL 5 // Set FLIGHT_MODE_ARM_CHANNEL to the channel that you want to use to simulate arming your drone.
42 | #define FLIGHT_MODE_ARM_MIN 1000
43 | #define FLIGHT_MODE_ARM_MAX 1800
44 |
45 | #define FLIGHT_MODE_ACRO_CHANNEL 8 // Set FLIGHT_MODE_ACRO_CHANNEL to the channel that you want to use to simulate acro mode.
46 | #define FLIGHT_MODE_ACRO_MIN 900
47 | #define FLIGHT_MODE_ACRO_MAX 1300
48 |
49 | #define FLIGHT_MODE_ANGLE_CHANNEL 8 // Set FLIGHT_MODE_ANGLE_CHANNEL to the channel that you want to use to simulate angle mode.
50 | #define FLIGHT_MODE_ANGLE_MIN 1300
51 | #define FLIGHT_MODE_ANGLE_MAX 1700
52 |
53 | #define FLIGHT_MODE_HORIZON_CHANNEL 8 // Set FLIGHT_MODE_HORIZON_CHANNEL to the channel that you want to use to simulate horizon mode.
54 | #define FLIGHT_MODE_HORIZON_MIN 1700
55 | #define FLIGHT_MODE_HORIZON_MAX 2100
56 |
57 | CRSFforArduino crsf = CRSFforArduino(&Serial1);
58 |
59 | void onFlightModeUpdate(serialReceiverLayer::flightModeId_t);
60 |
61 | void setup()
62 | {
63 | // Initialise the Serial Port and wait for it to open.
64 | Serial.begin(115200);
65 | // while (!Serial)
66 | // {
67 | // ;
68 | // }
69 |
70 | Serial.println("Flight Modes Example");
71 |
72 | // Initialise CRSF for Arduino.
73 | if (!crsf.begin())
74 | {
75 | Serial.println("CRSF initialisation failed!");
76 | while (1)
77 | {
78 | ;
79 | }
80 | }
81 |
82 | // Set flight modes.
83 | if (!crsf.setFlightMode(serialReceiverLayer::FLIGHT_MODE_DISARMED, FLIGHT_MODE_ARM_CHANNEL, FLIGHT_MODE_ARM_MIN, FLIGHT_MODE_ARM_MAX))
84 | {
85 | Serial.println("Failed to set \"DISARMED\" flight mode!");
86 | while (1)
87 | {
88 | ;
89 | }
90 | }
91 |
92 | if (!crsf.setFlightMode(serialReceiverLayer::FLIGHT_MODE_ACRO, FLIGHT_MODE_ACRO_CHANNEL, FLIGHT_MODE_ACRO_MIN, FLIGHT_MODE_ACRO_MAX))
93 | {
94 | Serial.println("Failed to set \"ACRO\" flight mode!");
95 | while (1)
96 | {
97 | ;
98 | }
99 | }
100 |
101 | if (!crsf.setFlightMode(serialReceiverLayer::FLIGHT_MODE_ANGLE, FLIGHT_MODE_ANGLE_CHANNEL, FLIGHT_MODE_ANGLE_MIN, FLIGHT_MODE_ANGLE_MAX))
102 | {
103 | Serial.println("Failed to set \"ANGLE\" flight mode!");
104 | while (1)
105 | {
106 | ;
107 | }
108 | }
109 |
110 | if (!crsf.setFlightMode(serialReceiverLayer::FLIGHT_MODE_HORIZON, FLIGHT_MODE_HORIZON_CHANNEL, FLIGHT_MODE_HORIZON_MIN, FLIGHT_MODE_HORIZON_MAX))
111 | {
112 | Serial.println("Failed to set \"HORIZON\" flight mode!");
113 | while (1)
114 | {
115 | ;
116 | }
117 | }
118 |
119 | // Set flight mode callback.
120 | crsf.setFlightModeCallback(onFlightModeUpdate);
121 |
122 | Serial.print("\tArm channel: ");
123 | Serial.println(FLIGHT_MODE_ARM_CHANNEL);
124 | Serial.print("\tFlight Modes Channel: ");
125 | Serial.println(FLIGHT_MODE_ACRO_CHANNEL);
126 | }
127 |
128 | void loop()
129 | {
130 | // Update CRSF for Arduino.
131 | crsf.update();
132 | }
133 |
134 | void onFlightModeUpdate(serialReceiverLayer::flightModeId_t flightMode)
135 | {
136 | /* Here is where you would put your flight mode implementation.
137 | For this example, we will just print the flight mode to the serial port,
138 | and send it to the controller as telemetry. */
139 | static serialReceiverLayer::flightModeId_t lastFlightMode = serialReceiverLayer::FLIGHT_MODE_DISARMED;
140 |
141 | if (flightMode != lastFlightMode)
142 | {
143 | Serial.print("Flight Mode: ");
144 | switch (flightMode)
145 | {
146 | case serialReceiverLayer::FLIGHT_MODE_DISARMED:
147 | Serial.println("Disarmed");
148 | break;
149 | case serialReceiverLayer::FLIGHT_MODE_ACRO:
150 | Serial.println("Acro");
151 | break;
152 | case serialReceiverLayer::FLIGHT_MODE_WAIT:
153 | Serial.println("Wait for GPS Lock");
154 | break;
155 | case serialReceiverLayer::FLIGHT_MODE_FAILSAFE:
156 | Serial.println("Failsafe");
157 | break;
158 | case serialReceiverLayer::FLIGHT_MODE_GPS_RESCUE:
159 | Serial.println("GPS Rescue");
160 | break;
161 | case serialReceiverLayer::FLIGHT_MODE_PASSTHROUGH:
162 | Serial.println("Passthrough");
163 | break;
164 | case serialReceiverLayer::FLIGHT_MODE_ANGLE:
165 | Serial.println("Angle");
166 | break;
167 | case serialReceiverLayer::FLIGHT_MODE_HORIZON:
168 | Serial.println("Horizon");
169 | break;
170 | case serialReceiverLayer::FLIGHT_MODE_AIRMODE:
171 | Serial.println("Airmode");
172 | break;
173 | default:
174 | Serial.println("Unknown");
175 | break;
176 | }
177 | lastFlightMode = flightMode;
178 |
179 | crsf.telemetryWriteFlightMode(flightMode);
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/examples/link_stats/link_stats.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * @file link_stats.ino
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief Example of how to read link statistics from a receiver.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This example is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "CRSFforArduino.hpp"
26 |
27 | /* Tested with the following equipment:
28 | - Controller: RadioMaster TX16S Max Edition Mk1
29 | - Firmware: EdgeTX 2.10.0 Nightly
30 | - Lua Script: iNav OpenTX Telemetry Widget 2.2.3
31 | - Transmitter Module: RadioMaster Ranger
32 | - Firmware: ExpressLRS 3.3.1
33 | - Receiver: RadioMaster RP3 Diversity
34 | - Firmware: ExpressLRS 3.3.1
35 | - Development Board: Adafruit Metro M4 Express
36 | - Board Package: Adafruit SAMD Boards 1.7.5
37 | - Framework: Arduino 1.8.13
38 | - Library: CRSF for Arduino 1.0.0
39 | */
40 |
41 | CRSFforArduino *crsf = nullptr;
42 |
43 | void onLinkStatisticsUpdate(serialReceiverLayer::link_statistics_t);
44 |
45 | void setup()
46 | {
47 | Serial.begin(115200);
48 | while (!Serial)
49 | {
50 | delay(10);
51 | }
52 |
53 | Serial.println("Link Statistics Example.");
54 |
55 | crsf = new CRSFforArduino();
56 |
57 | if (!crsf->begin())
58 | {
59 | Serial.println("CRSF for Arduino failed to initialise.");
60 |
61 | delete crsf;
62 | crsf = nullptr;
63 |
64 | while (1)
65 | {
66 | delay(10);
67 | }
68 | }
69 |
70 | // Set link statistics callback.
71 | crsf->setLinkStatisticsCallback(onLinkStatisticsUpdate);
72 |
73 | Serial.println("Ready.");
74 | delay(1000);
75 | }
76 |
77 | void loop()
78 | {
79 | crsf->update();
80 | }
81 |
82 | void onLinkStatisticsUpdate(serialReceiverLayer::link_statistics_t linkStatistics)
83 | {
84 | static unsigned long lastPrint = 0;
85 | if (millis() - lastPrint >= 200)
86 | {
87 | lastPrint = millis();
88 | Serial.print("Link Statistics: ");
89 | Serial.print("RSSI: ");
90 | Serial.print(linkStatistics.rssi);
91 | Serial.print(", Link Quality: ");
92 | Serial.print(linkStatistics.lqi);
93 | Serial.print(", Signal-to-Noise Ratio: ");
94 | Serial.print(linkStatistics.snr);
95 | Serial.print(", Transmitter Power: ");
96 | Serial.println(linkStatistics.tx_power);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/examples/platformio/main.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file main.cpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This is the main development file for CRSF for Arduino.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "Arduino.h"
26 | #include "CRSFforArduino.hpp"
27 |
28 | CRSFforArduino *crsf = nullptr;
29 |
30 | void onReceiveRcChannels(serialReceiverLayer::rcChannels_t *rcChannels);
31 |
32 | void setup()
33 | {
34 | Serial.begin(115200);
35 | while (!Serial)
36 | {
37 | delay(10);
38 | }
39 |
40 | crsf = new CRSFforArduino();
41 |
42 | if (!crsf->begin())
43 | {
44 | Serial.println("CRSF for Arduino failed to initialise.");
45 |
46 | delete crsf;
47 | crsf = nullptr;
48 |
49 | while (1)
50 | {
51 | delay(10);
52 | }
53 | }
54 |
55 | crsf->setRcChannelsCallback(onReceiveRcChannels);
56 | }
57 |
58 | void loop()
59 | {
60 | crsf->update();
61 | }
62 |
63 | void onReceiveRcChannels(serialReceiverLayer::rcChannels_t *rcChannels)
64 | {
65 | static unsigned long lastPrint = millis();
66 | if (millis() - lastPrint >= 100)
67 | {
68 | lastPrint = millis();
69 |
70 | static bool initialised = false;
71 | static bool lastFailSafe = false;
72 | if (rcChannels->failsafe != lastFailSafe || !initialised)
73 | {
74 | initialised = true;
75 | lastFailSafe = rcChannels->failsafe;
76 | Serial.print("FailSafe: ");
77 | Serial.println(lastFailSafe ? "Active" : "Inactive");
78 | }
79 |
80 | if (rcChannels->failsafe == false)
81 | {
82 | Serial.print("RC Channels rcToUs(rcChannels->value[0]));
84 | Serial.print(", E: ");
85 | Serial.print(crsf->rcToUs(rcChannels->value[1]));
86 | Serial.print(", T: ");
87 | Serial.print(crsf->rcToUs(rcChannels->value[2]));
88 | Serial.print(", R: ");
89 | Serial.print(crsf->rcToUs(rcChannels->value[3]));
90 | Serial.print(", Aux1: ");
91 | Serial.print(crsf->rcToUs(rcChannels->value[4]));
92 | Serial.print(", Aux2: ");
93 | Serial.print(crsf->rcToUs(rcChannels->value[5]));
94 | Serial.print(", Aux3: ");
95 | Serial.print(crsf->rcToUs(rcChannels->value[6]));
96 | Serial.print(", Aux4: ");
97 | Serial.print(crsf->rcToUs(rcChannels->value[7]));
98 | Serial.println(">");
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/examples/rc_channels/rc_channels.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * @file rc_channels.ino
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief Example of how to read rc channels from a receiver.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This example is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "CRSFforArduino.hpp"
26 | #define USE_SERIAL_PLOTTER 0
27 |
28 | CRSFforArduino *crsf = nullptr;
29 |
30 | int rcChannelCount = crsfProtocol::RC_CHANNEL_COUNT;
31 | const char *rcChannelNames[] = {
32 | "A",
33 | "E",
34 | "T",
35 | "R",
36 | "Aux1",
37 | "Aux2",
38 | "Aux3",
39 | "Aux4",
40 |
41 | "Aux5",
42 | "Aux6",
43 | "Aux7",
44 | "Aux8",
45 | "Aux9",
46 | "Aux10",
47 | "Aux11",
48 | "Aux12"};
49 |
50 | void onReceiveRcChannels(serialReceiverLayer::rcChannels_t *rcChannels);
51 |
52 | void setup()
53 | {
54 | // Initialise the serial port & wait for the port to open.
55 | Serial.begin(115200);
56 | while (!Serial)
57 | {
58 | ;
59 | }
60 |
61 | // Initialise CRSF for Arduino.
62 | crsf = new CRSFforArduino();
63 | if (!crsf->begin())
64 | {
65 | crsf->end();
66 |
67 | delete crsf;
68 | crsf = nullptr;
69 |
70 | Serial.println("CRSF for Arduino initialisation failed!");
71 | while (1)
72 | {
73 | delay(10);
74 | }
75 | }
76 |
77 | rcChannelCount = rcChannelCount > crsfProtocol::RC_CHANNEL_COUNT ? crsfProtocol::RC_CHANNEL_COUNT : rcChannelCount;
78 |
79 | crsf->setRcChannelsCallback(onReceiveRcChannels);
80 |
81 | // Show the user that the sketch is ready.
82 | Serial.println("RC Channels Example");
83 | delay(1000);
84 | Serial.println("Ready");
85 | delay(1000);
86 | }
87 |
88 | void loop()
89 | {
90 | crsf->update();
91 | }
92 |
93 | void onReceiveRcChannels(serialReceiverLayer::rcChannels_t *rcChannels)
94 | {
95 | if (rcChannels->failsafe == false)
96 | {
97 | /* Print RC channels every 100 ms. */
98 | unsigned long thisTime = millis();
99 | static unsigned long lastTime = millis();
100 |
101 | /* Compensate for millis() overflow. */
102 | if (thisTime < lastTime)
103 | {
104 | lastTime = thisTime;
105 | }
106 |
107 | if (thisTime - lastTime >= 100)
108 | {
109 | lastTime = thisTime;
110 | #if USE_SERIAL_PLOTTER > 0
111 | for (int i = 1; i <= rcChannelCount; i++)
112 | {
113 | Serial.print(i);
114 | Serial.print(":");
115 | Serial.print(crsf->rcToUs(crsf->getChannel(i)));
116 | Serial.print("\t");
117 | }
118 | Serial.println();
119 | #else
120 | Serial.print("RC Channels <");
121 | for (int i = 1; i <= rcChannelCount; i++)
122 | {
123 | Serial.print(rcChannelNames[i - 1]);
124 | Serial.print(": ");
125 | Serial.print(crsf->rcToUs(crsf->getChannel(i)));
126 |
127 | if (i < rcChannelCount)
128 | {
129 | Serial.print(", ");
130 | }
131 | }
132 | Serial.println(">");
133 | #endif
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/examples/telemetry/telemetry.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * @file flight_modes.ino
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief Example of how to send telemetry back to your RC handset using CRSF for Arduino.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This example is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "CRSFforArduino.hpp"
26 |
27 | /* Configuration Options. */
28 | #define VIEW_RC_CHANNELS 0 // Set VIEW_RC_CHANNELS to 1 to view the RC channel data in the serial monitor.
29 | #define GENERATE_RANDOM_BATTERY_DATA 0 // Set GENERATE_RANDOM_BATTERY_DATA to 1 to generate random battery sensor telemetry data.
30 | #define GENERATE_RANDOM_GPS_DATA 0 // Set GENERATE_RANDOM_GPS_DATA to 1 to generate random GPS telemetry data.
31 |
32 | uint32_t timeNow = 0;
33 |
34 | /* Initialise the attitude telemetry with default values. */
35 | int16_t roll = -200; // Roll is in decided degrees (eg -200 = -20.0 degrees).
36 | int16_t pitch = 150; // Pitch is in decided degrees (eg 150 = 15.0 degrees).
37 | uint16_t yaw = 2758; // Yaw is in decided degrees (eg 2758 = 275.8 degrees).
38 |
39 | /* Initialise the barometric altitude telemetry with default values. */
40 | uint16_t baroAltitude = 10; // Barometric altitude is in decimetres (eg 10 = 1.0 metres).
41 | int16_t verticalSpeed = 50; // Vertical speed is in centimetres per second (eg 50 = 0.5 metres per second).
42 |
43 | /* Initialise the battery sensor telemetry with default values. */
44 | float batteryVoltage = 385.0F; // Battery voltage is in millivolts (mV * 100).
45 | float batteryCurrent = 150.0F; // Battery current is in milliamps (mA * 10).
46 | uint32_t batteryFuel = 700; // Battery fuel is in milliamp hours (mAh).
47 | uint8_t batteryPercent = 50; // Battery percentage remaining is in percent (0 - 100).
48 |
49 | /* Initialise the GPS telemetry data with default values. */
50 | float latitude = -41.18219482686493F; // Latitude is in decimal degrees.
51 | float longitude = 174.9497131419602F; // Longitude is in decimal degrees.
52 | float altitude = 100.0F; // Altitude is in centimetres.
53 | float speed = 500.0F; // Speed is in cm/s
54 | float groundCourse = 275.8F; // Ground Course is in degrees.
55 | uint8_t satellites = 7; // 7 satellites are in view (implies a 3D fix).
56 |
57 | CRSFforArduino crsf = CRSFforArduino(&Serial1);
58 |
59 | #if VIEW_RC_CHANNELS > 0
60 | const int channelCount = 8;
61 | const char *channelNames[crsfProtocol::RC_CHANNEL_COUNT] = {
62 | "A", "E", "T", "R", "Aux1", "Aux2", "Aux3", "Aux4", "Aux5", "Aux6", "Aux7", "Aux8", "Aux9", "Aux10", "Aux11", "Aux12"};
63 |
64 | static_assert(channelCount <= crsfProtocol::RC_CHANNEL_COUNT, "The number of RC channels must be less than or equal to the maximum number of RC channels supported by CRSF.");
65 | #endif
66 |
67 | void setup()
68 | {
69 | #if VIEW_RC_CHANNELS > 0 || defined(CRSF_DEBUG)
70 | Serial.begin(115200);
71 | while (!Serial)
72 | {
73 | ;
74 | }
75 |
76 | Serial.println("GPS Telemetry Example");
77 | #endif
78 |
79 | /* Initialise CRSF for Arduino */
80 | if (!crsf.begin())
81 | {
82 | #if VIEW_RC_CHANNELS > 0 || defined(CRSF_DEBUG)
83 | Serial.println("CRSF for Arduino initialization failed!");
84 | #endif
85 | while (1)
86 | {
87 | ;
88 | }
89 | }
90 |
91 | #if VIEW_RC_CHANNELS > 0 || defined(CRSF_DEBUG)
92 | /* Show the user that the sketch is ready. */
93 | Serial.println("Ready");
94 | delay(1000);
95 | #endif
96 | }
97 |
98 | void loop()
99 | {
100 |
101 | // Use timeNow to store the current time in milliseconds.
102 | timeNow = millis();
103 |
104 | /* Attitude Telemetry
105 |
106 | Normally, you would read the raw attitude data from your IMU and convert it to roll, pitch and yaw values.
107 | For the purposes of this example, we will just update the following with random values:
108 | - Roll
109 | - Pitch
110 | - Yaw
111 |
112 | These values are updated at a rate of 100 Hz.
113 | */
114 |
115 | /* Update the attitude telemetry at a rate of 100 Hz. */
116 | static unsigned long lastAttitudeUpdate = 0;
117 | if (timeNow - lastAttitudeUpdate >= 10)
118 | {
119 | lastAttitudeUpdate = timeNow;
120 |
121 | /* Update the attitude telemetry with the new values. */
122 | crsf.telemetryWriteAttitude(roll, pitch, yaw);
123 | }
124 |
125 | /* Barometric Altitude Telemetry
126 |
127 | Normally, you would read the barometric altitude and vertical speed from a barometric pressure sensor
128 | connected to your Arduino board.
129 |
130 | For the purposes of this example, we will just update the following with random values:
131 | - Barometric Altitude
132 | - Vertical Speed
133 |
134 | These values are updated at a rate of 10 Hz.
135 | */
136 |
137 | /* Update the barometric altitude telemetry at a rate of 10 Hz. */
138 | static unsigned long lastBaroAltitudeUpdate = 0;
139 | if (timeNow - lastBaroAltitudeUpdate >= 100)
140 | {
141 | lastBaroAltitudeUpdate = timeNow;
142 |
143 | /* Update the barometric altitude telemetry with the new values. */
144 | crsf.telemetryWriteBaroAltitude(baroAltitude, verticalSpeed);
145 | }
146 |
147 | /* Battery Telemetry
148 |
149 | Normally, you read the battery voltage and current from two analog pins on your Arduino board or from a
150 | battery sensor connected to your Arduino board.
151 | For the purposes of this example, we will just update the following with random values:
152 | - Battery Voltage
153 | - Battery Current
154 |
155 | These values are updated at a rate of 10 Hz.
156 | Battery fuel and percentage remaining are calculated from the battery voltage and current values, with
157 | a simulated battery capacity of 1000 mAh. */
158 |
159 | /* Update the battery sensor telemetry at a rate of 10 Hz. */
160 | static unsigned long lastBatteryUpdate = 0;
161 | if (timeNow - lastBatteryUpdate >= 100)
162 | {
163 | lastBatteryUpdate = timeNow;
164 |
165 | #if GENERATE_RANDOM_BATTERY_DATA > 0
166 | // Generate random values for the battery sensor telemetry.
167 | batteryVoltage = random(300, 420);
168 | batteryCurrent = random(0, 1000);
169 | #endif
170 |
171 | // Calculate the battery fuel and percentage remaining.
172 | // batteryFuel = (uint32_t)(batteryFuel + (batteryCurrent / 36000));
173 | // batteryPercent = (uint8_t)(batteryFuel / 10);
174 |
175 | // Update the battery sensor telemetry with the new values.
176 | crsf.telemetryWriteBattery(batteryVoltage, batteryCurrent, batteryFuel, batteryPercent);
177 | }
178 |
179 | /* GPS Telemetry
180 |
181 | Normally, you would update the GPS telemetry data with the latest values from your GPS module.
182 | For the purposes of this example, we will just update the following with random values:
183 | - Latitude
184 | - Longitude
185 | - Altitude
186 | - Speed
187 | - Ground Course
188 | - Satellites
189 |
190 | These values are updated at a rate of 1 Hz.
191 | Normally, you would update these values at a rate of 5 Hz or higher.
192 | */
193 |
194 | /* Update the GPS telemetry data at a rate of 1 Hz. */
195 | static unsigned long lastGpsUpdate = 0;
196 | if (timeNow - lastGpsUpdate >= 1000)
197 | {
198 | lastGpsUpdate = timeNow;
199 |
200 | #if GENERATE_RANDOM_GPS_DATA > 0
201 | // Generate random values for the GPS telemetry data.
202 | latitude = random(-90, 90);
203 | longitude = random(-180, 180);
204 | altitude = random(0, 500000);
205 | speed = random(0, 6625);
206 | groundCourse = random(0, 359);
207 | satellites = random(0, 16);
208 | #endif
209 |
210 | // Update the GPS telemetry data with the new values.
211 | crsf.telemetryWriteGPS(latitude, longitude, altitude, speed, groundCourse, satellites);
212 | }
213 |
214 | /* Call crsf.update() in the main loop to process CRSF packets. */
215 | crsf.update();
216 |
217 | /* You can process RC channel data here. */
218 | #if VIEW_RC_CHANNELS > 0
219 | static unsigned long lastPrint = 0;
220 | if (timeNow - lastPrint >= 100)
221 | {
222 | lastPrint = timeNow;
223 | Serial.print("RC Channels <");
224 | for (uint8_t i = 0; i < channelCount; i++)
225 | {
226 | Serial.print(channelNames[i]);
227 | Serial.print(": ");
228 | Serial.print(crsf.rcToUs(crsf.getChannel(i + 1)));
229 | if (i < channelCount - 1)
230 | {
231 | Serial.print(", ");
232 | }
233 | }
234 | Serial.println(">");
235 | }
236 | #endif
237 | }
238 |
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 | # Syntax colouring map for CRSF for Arduino.
2 |
3 | # Namespaces (KEYWORD1)
4 | crsfProtocol KEYWORD1
5 | hal KEYWORD1
6 | genericStreamBuffer KEYWORD1
7 | serialReceiver KEYWORD1
8 | sketchLayer KEYWORD1
9 |
10 | # Datatypes (KEYWORD1)
11 | CRSF_DEBUG_SERIAL_PORT KEYWORD1
12 | crsf KEYWORD1
13 | CRSFforArduino KEYWORD1
14 |
15 | # Functions (KEYWORD2)
16 | begin KEYWORD2
17 | end KEYWORD2
18 | getChannel KEYWORD2
19 | rcToUs KEYWORD2
20 | readRcChannel KEYWORD2
21 | telemetryWriteAttitude KEYWORD2
22 | telemetryWriteBaroAltitude KEYWORD2
23 | telemetryWriteBattery KEYWORD2
24 | telemetryWriteGPS KEYWORD2
25 | setRcChannelsCallback KEYWORD2
26 | setLinkStatisticsCallback KEYWORD2
27 | setFlightModeCallback KEYWORD2
28 | setFlightMode KEYWORD2
29 | update KEYWORD2
30 |
31 | # Structures (KEYWORD3)
32 |
33 | # Constants (LITERAL1)
34 | BAUD_RATE LITERAL1
35 | CRSFFORARDUINO_VERSION LITERAL1
36 | CRSFFORARDUINO_VERSION_DATE LITERAL1
37 | CRSFFORARDUINO_VERSION_MAJOR LITERAL1
38 | CRSFFORARDUINO_VERSION_MINOR LITERAL1
39 | CRSFFORARDUINO_VERSION_PATCH LITERAL1
40 | CRSF_RC_ENABLED LITERAL1
41 | CRSF_RC_MAX_CHANNELS LITERAL1
42 | CRSF_RC_MAX_CHANNELS LITERAL1
43 | CRSF_RC_CHANNEL_MAX LITERAL1
44 | CRSF_RC_CHANNEL_CENTER LITERAL1
45 | CRSF_RC_INITIALISE_CHANNELS LITERAL1
46 | CRSF_RC_INITIALISE_THROTTLECHANNEL LITERAL1
47 | CRSF_TELEMETRY_ENABLED LITERAL1
48 | CRSF_TELEMETRY_ATTITUDE_ENABLED LITERAL1
49 | CRSF_TELEMETRY_BAROALTITUDE_ENABLED LITERAL1
50 | CRSF_TELEMETRY_BATTERY_ENABLED LITERAL1
51 | CRSF_TELEMETRY_GPS_ENABLED LITERAL1
52 | CRSF_DEBUG_ENABLED LITERAL1
53 | RC_CHANNEL_ROLL LITERAL1
54 | RC_CHANNEL_PITCH LITERAL1
55 | RC_CHANNEL_THROTTLE LITERAL1
56 | RC_CHANNEL_YAW LITERAL1
57 | RC_CHANNEL_AUX1 LITERAL1
58 | RC_CHANNEL_AUX2 LITERAL1
59 | RC_CHANNEL_AUX3 LITERAL1
60 | RC_CHANNEL_AUX4 LITERAL1
61 | RC_CHANNEL_AUX5 LITERAL1
62 | RC_CHANNEL_AUX6 LITERAL1
63 | RC_CHANNEL_AUX7 LITERAL1
64 | RC_CHANNEL_AUX8 LITERAL1
65 | RC_CHANNEL_AUX9 LITERAL1
66 | RC_CHANNEL_AUX10 LITERAL1
67 | RC_CHANNEL_AUX11 LITERAL1
68 | RC_CHANNEL_AUX12 LITERAL1
69 | RC_CHANNEL_COUNT LITERAL1
70 |
--------------------------------------------------------------------------------
/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json",
3 | "name": "CRSFforArduino",
4 | "version": "2025.9.2",
5 | "description": "An Arduino Library for communicating with ExpressLRS and TBS Crossfire receivers.",
6 | "keywords": "arduino, remote-control, arduino-library, protocols, rc, radio-control, crsf, expresslrs",
7 | "repository":
8 | {
9 | "type": "git",
10 | "url": "https://github.com/ZZ-Cat/CRSFforArduino.git"
11 | },
12 | "authors":
13 | [
14 | {
15 | "name": "Cassandra Robinson",
16 | "email": "nicad.heli.flier@gmail.com",
17 | "url": "https://github.com/ZZ-Cat",
18 | "maintainer": true
19 | }
20 | ],
21 | "license": "GNU AGPLv3",
22 | "homepage": "https://github.com/ZZ-Cat/CRSFforArduino",
23 | "dependencies": {
24 | },
25 | "frameworks": "Arduino",
26 | "platforms": [
27 | "atmelsam",
28 | "espressif32",
29 | "raspberrypi",
30 | "ststm32",
31 | "teensy"
32 | ],
33 | "examples": [
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=CRSFforArduino
2 | version=2025.9.2
3 | author=Cassandra Robinson
4 | maintainer=Cassandra Robinson
5 | sentence=CRSF for Arduino brings the Crossfire Protocol to the Arduino ecosystem.
6 | category=Communication
7 | url=https://github.com/ZZ-Cat/CRSFforArduino
8 | dot_a_linkage=false
9 | includes=CRSFforArduino.hpp
10 |
--------------------------------------------------------------------------------
/src/CFA_Config.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CFA_Config.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This is the configuration file for CRSF for Arduino.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #pragma once
26 |
27 | #include "Arduino.h"
28 |
29 | /* The following defines are used to configure CRSF for Arduino.
30 | You can change these values to suit your needs. */
31 |
32 | namespace crsfForArduinoConfig
33 | {
34 | /* CRSFforArduino version
35 | Versioning is based on a rolling release model
36 | and is backwards-compatible with Semantic Versioning 2.0.0.
37 | See https://semver.org/ for more information. */
38 | #define CRSFFORARDUINO_VERSION "2025.9.2"
39 | #define CRSFFORARDUINO_VERSION_DATE "2025-09-02"
40 | #define CRSFFORARDUINO_VERSION_MAJOR 2025
41 | #define CRSFFORARDUINO_VERSION_MINOR 9
42 | #define CRSFFORARDUINO_VERSION_PATCH 2
43 |
44 | // This is set to 1 if the version is a pre-release version.
45 | #define CRSFFORARDUINO_VERSION_IS_PRERELEASE 0
46 |
47 | // These are the pre-release version details which are only used if CRSFFORARDUINO_VERSION_IS_PRERELEASE is set to 1.
48 | // NOTE: Pre-release versions are not recommended for production use.
49 | // #if CRSFFORARDUINO_VERSION_IS_PRERELEASE == 1
50 | // #define CRSFFORARDUINO_VERSION_PRE "2025.8.30"
51 | // #define CRSFFORARDUINO_VERSION_BUILD_DATE "2025-08-30"
52 | // #define CRSFFORARDUINO_VERSION_BUILD_MAJOR 2025
53 | // #define CRSFFORARDUINO_VERSION_BUILD_MINOR 8
54 | // #define CRSFFORARDUINO_VERSION_BUILD_PATCH 30
55 | // #endif
56 |
57 | /* Failsafe Options
58 | - CRSF_FAILSAFE_LQI_THRESHOLD: The minimum LQI value for the receiver to be considered connected.
59 | - CRSF_FAILSAFE_RSSI_THRESHOLD: The minimum RSSI value for the receiver to be considered connected.
60 | - NB: It is considered good practice to set this value to the same as the RSSI Sensitivity Limit in your Lua script.
61 | */
62 | #define CRSF_FAILSAFE_LQI_THRESHOLD 80
63 | #define CRSF_FAILSAFE_RSSI_THRESHOLD 105
64 |
65 | /* RC Options
66 | - RC_ENABLED: Enables or disables the RC API.
67 | - RC_MAX_CHANNELS: The maximum number of RC channels to be received.
68 | - RC_CHANNEL_MIN: The minimum value of an RC channel.
69 | - RC_CHANNEL_MAX: The maximum value of an RC channel.
70 | - RC_CHANNEL_CENTER: The center value of an RC channel.
71 | - RC_INITIALISE_CHANNELS: Whether or not to initialise the RC channels to their center values.
72 | - RC_INITIALISE_ARMCHANNEL: When enabled, the arm channel is set to its minimum value.
73 | - NB: This refers to the Aux1 channel and is intended for use with ExpressLRS receivers.
74 | - RC_INITIALISE_THROTTLECHANNEL: When enabled, the throttle channel is set to its minimum value. */
75 | #define CRSF_RC_ENABLED 1
76 | #define CRSF_RC_MAX_CHANNELS 16
77 | #define CRSF_RC_CHANNEL_MIN 172
78 | #define CRSF_RC_CHANNEL_MAX 1811
79 | #define CRSF_RC_CHANNEL_CENTER 992
80 | #define CRSF_RC_INITIALISE_CHANNELS 1
81 | #define CRSF_RC_INITIALISE_ARMCHANNEL 1
82 | #define CRSF_RC_INITIALISE_THROTTLECHANNEL 1
83 |
84 | /* Flight Modes
85 | Enables or disables the Flight Mode API.
86 | When enabled, you are given an event-driven API that allows you to easily implement flight modes
87 | and assign them to a switch on your controller.
88 | Pro Tip: You can combine the Flight Mode API with the Telemetry API to send flight mode
89 | information back to your controller. */
90 | #define CRSF_FLIGHTMODES_ENABLED 0
91 |
92 | /* Custom Flight Modes
93 | Enables or disables the Custom Flight Modes.
94 | When enabled, this allows you to implement flight modes with custom names
95 | and assign them to a switch on your controller. */
96 | #define CRSF_CUSTOM_FLIGHT_MODES_ENABLED 0
97 |
98 | /* Telemetry Options
99 | - TELEMETRY_ENABLED: Enables or disables the Telemetry API.
100 | - TELEMETRY_ATTITUDE_ENABLED: Enables or disables attitude telemetry output.
101 | - TELEMETRY_BAROALTITUDE_ENABLED: Enables or disables barometric altitude telemetry output.
102 | - TELEMETRY_BATTERY_ENABLED: Enables or disables battery telemetry output.
103 | - TELEMETRY_FLIGHTMODE_ENABLED: Enables or disables flight mode telemetry output.
104 | - TELEMETRY_GPS_ENABLED: Enables or disables GPS telemetry output.
105 | - TELEMETRY_SIMULATE_ARBITRARY_VALUES: When enabled, arbitrary values are sent for telemetry. */
106 | #define CRSF_TELEMETRY_ENABLED 1
107 |
108 | #define CRSF_TELEMETRY_ATTITUDE_ENABLED 1
109 | #define CRSF_TELEMETRY_BAROALTITUDE_ENABLED 1
110 | #define CRSF_TELEMETRY_BATTERY_ENABLED 1
111 |
112 | #ifndef CRSF_TELEMETRY_FLIGHTMODE_ENABLED
113 | #define CRSF_TELEMETRY_FLIGHTMODE_ENABLED 0
114 | #endif
115 |
116 | #define CRSF_TELEMETRY_GPS_ENABLED 1
117 |
118 | #define CRSF_LINK_STATISTICS_ENABLED 1
119 |
120 | /* Debug Options
121 | - DEBUG_ENABLED: Enables or disables debug output over the selected serial port.
122 | - CRSF_DEBUG_SERIAL_PORT: The serial port to use for debug output. Usually the native USB port.
123 | - CRSF_DEBUG_ENABLE_COMPATIBILITY_TABLE_OUTPUT: Enables or disables debug output from the compatibility table.
124 | - CRSF_DEBUG_ENABLE_CONFIGURATION_DUMP: When enabled, this will print the configuration of CFA to the Serial Monitor.
125 | - CRSF_DEBUG_ENABLE_VERSION_OUTPUT: When enabled, this will print the version of CFA to the Serial Monitor. */
126 | #define CRSF_DEBUG_ENABLED 0
127 | #define CRSF_DEBUG_SERIAL_PORT Serial
128 | #define CRSF_DEBUG_ENABLE_COMPATIBILITY_TABLE_OUTPUT 0
129 | #define CRSF_DEBUG_ENABLE_CONFIGURATION_DUMP 0
130 | #define CRSF_DEBUG_ENABLE_VERSION_OUTPUT 1
131 |
132 | /* All warnings and asserts below this point are to ensure that the configuration is valid. */
133 |
134 | /* Compiler warning if both RC and Telemetry are disabled. */
135 | #if CRSF_RC_ENABLED == 0 && CRSF_TELEMETRY_ENABLED == 0
136 | #warning "Both CRSF_RC_ENABLED and CRSF_TELEMETRY_ENABLED are disabled. CRSF for Arduino will not do anything."
137 | #endif
138 |
139 | /* Static assert if Flight Modes are enabled, but RC is disabled. */
140 | #if CRSF_FLIGHTMODES_ENABLED == 1 && CRSF_RC_ENABLED == 0
141 | static_assert(false, "CRSF_FLIGHTMODES_ENABLED is enabled, but CRSF_RC_ENABLED is disabled. Flight Modes require RC to be enabled.");
142 | #endif
143 |
144 | /* Static assert if all telemetry options are disabled.
145 | Better to use CRSF_TELEMETRY_ENABLED instead. */
146 | #if CRSF_TELEMETRY_ATTITUDE_ENABLED == 0 && CRSF_TELEMETRY_BAROALTITUDE_ENABLED == 0 && CRSF_TELEMETRY_BATTERY_ENABLED == 0 && CRSF_TELEMETRY_FLIGHTMODE_ENABLED == 0 && CRSF_TELEMETRY_GPS_ENABLED == 0
147 | static_assert(false, "All telemetry options are disabled. Set CRSF_TELEMETRY_ENABLED to 0 to disable telemetry instead.");
148 | #endif
149 |
150 | }; // namespace crsfForArduinoConfig
151 |
--------------------------------------------------------------------------------
/src/CRSFforArduino.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CRSFforArduino.cpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This is the Sketch Layer, which is a simplified API for CRSF for Arduino.
5 | * It is intended to be used by the user in their sketches.
6 | *
7 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
8 | *
9 | * @section License GNU Affero General Public License v3.0
10 | * This source file is a part of the CRSF for Arduino library.
11 | * CRSF for Arduino is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU Affero General Public License as published by
13 | * the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * CRSF for Arduino is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU Affero General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU Affero General Public License
22 | * along with CRSF for Arduino. If not, see .
23 | *
24 | */
25 |
26 | #include "CRSFforArduino.hpp"
27 | #include "Arduino.h"
28 |
29 | namespace sketchLayer
30 | {
31 | /**
32 | * @brief Construct a new CRSFforArduino object.
33 | *
34 | */
35 | CRSFforArduino::CRSFforArduino() : SerialReceiver()
36 | {
37 | }
38 |
39 | /**
40 | * @brief Construct a new CRSFforArduino object with the specified serial port.
41 | *
42 | * @param serialPort
43 | */
44 | CRSFforArduino::CRSFforArduino(HardwareSerial *serialPort) : SerialReceiver(serialPort)
45 | {
46 | }
47 |
48 | /**
49 | * @brief Construct a new CRSFforArduino object with the specified RX and TX pins.
50 | *
51 | * @param rxPin
52 | * @param txPin
53 | */
54 | CRSFforArduino::CRSFforArduino(HardwareSerial *serialPort, int rxPin, int txPin) : SerialReceiver(serialPort, rxPin, txPin)
55 | {
56 | }
57 |
58 | /**
59 | * @brief Destroy the CRSFforArduino object.
60 | *
61 | */
62 | CRSFforArduino::~CRSFforArduino()
63 | {
64 | }
65 |
66 | /**
67 | * @brief Initialises CRSF for Arduino.
68 | *
69 | * @return true if CRSF for Arduino was initialised successfully.
70 | */
71 | bool CRSFforArduino::begin(const uint32_t baud_rate)
72 | {
73 | #if CRSF_DEBUG_ENABLED > 0 && CRSF_DEBUG_ENABLE_VERSION_OUTPUT > 0
74 | CRSF_DEBUG_SERIAL_PORT.println("[CRSF for Arduino | INFO]: ");
75 | CRSF_DEBUG_SERIAL_PORT.print("- Version: ");
76 | CRSF_DEBUG_SERIAL_PORT.print(CRSFFORARDUINO_VERSION);
77 | #if CRSFFORARDUINO_VERSION_IS_PRERELEASE > 0
78 | CRSF_DEBUG_SERIAL_PORT.print("-");
79 | CRSF_DEBUG_SERIAL_PORT.println(CRSFFORARDUINO_VERSION_PRE);
80 | #endif
81 | CRSF_DEBUG_SERIAL_PORT.print("- Version Date: ");
82 | CRSF_DEBUG_SERIAL_PORT.println(CRSFFORARDUINO_VERSION_DATE);
83 | #if CRSFFORARDUINO_VERSION_IS_PRERELEASE > 0
84 | CRSF_DEBUG_SERIAL_PORT.print("- Build Date: ");
85 | CRSF_DEBUG_SERIAL_PORT.println(CRSFFORARDUINO_VERSION_BUILD_DATE);
86 | #endif
87 | #endif
88 |
89 | #if CRSF_RC_ENABLED > 0 || CRSF_TELEMETRY_ENABLED > 0
90 | return this->SerialReceiver::begin(baud_rate);
91 | #else
92 | // Return false if RC is disabled
93 | return false;
94 | #endif
95 | }
96 |
97 | /**
98 | * @brief Ends CRSF for Arduino.
99 | *
100 | */
101 | void CRSFforArduino::end()
102 | {
103 | #if CRSF_RC_ENABLED > 0 || CRSF_TELEMETRY_ENABLED > 0
104 | this->SerialReceiver::end();
105 | #endif
106 | }
107 |
108 | /**
109 | * @brief This processes RC and Telemetry frames.
110 | * It should be called as often as possible.
111 | *
112 | */
113 | void CRSFforArduino::update()
114 | {
115 | #if CRSF_RC_ENABLED > 0 || CRSF_TELEMETRY_ENABLED > 0
116 | this->SerialReceiver::processFrames();
117 | #endif
118 |
119 | #if CRSF_RC_ENABLED > 0 && CRSF_FLIGHTMODES_ENABLED > 0
120 | this->SerialReceiver::handleFlightMode();
121 | #endif
122 | }
123 |
124 | /**
125 | * @brief Reads the specified RC channel.
126 | * @param channel The channel to read.
127 | * @param raw If true, returns the raw RC value. If false, returns the scaled RC value in microseconds.
128 | *
129 | * @return The RC value.
130 | */
131 | [[deprecated("Use RC channel callback instead")]] uint16_t CRSFforArduino::readRcChannel(uint8_t channel, bool raw)
132 | {
133 | #if CRSF_RC_ENABLED > 0
134 | return this->SerialReceiver::readRcChannel(channel - 1, raw);
135 | #else
136 | // Prevent compiler warnings
137 | (void)channel;
138 | (void)raw;
139 |
140 | // Return 0 if RC is disabled
141 | return 0;
142 | #endif
143 | }
144 |
145 | /**
146 | * @brief Alias for readRcChannel(channel, true).
147 | *
148 | * @param channel The channel to read.
149 | * @return The RC value.
150 | */
151 | [[deprecated("Use RC channel callback instead")]] uint16_t CRSFforArduino::getChannel(uint8_t channel)
152 | {
153 | #if CRSF_RC_ENABLED > 0
154 | return this->SerialReceiver::getChannel(channel - 1);
155 | #else
156 | // Prevent compiler warnings
157 | (void)channel;
158 |
159 | // Return 0 if RC is disabled
160 | return 0;
161 | #endif
162 | }
163 |
164 | /**
165 | * @brief Converts a raw RC value to microseconds.
166 | *
167 | * @param rc The raw RC value to convert.
168 | * @return The converted RC value in microseconds.
169 | */
170 | uint16_t CRSFforArduino::rcToUs(uint16_t rc)
171 | {
172 | #if CRSF_RC_ENABLED > 0
173 | return this->SerialReceiver::rcToUs(rc);
174 | #else
175 | // Prevent compiler warnings
176 | (void)rc;
177 |
178 | // Return 0 if RC is disabled
179 | return 0;
180 | #endif
181 | }
182 |
183 | void CRSFforArduino::setRcChannelsCallback(void (*callback)(serialReceiverLayer::rcChannels_t *rcChannels))
184 | {
185 | #if CRSF_RC_ENABLED > 0
186 | this->SerialReceiver::setRcChannelsCallback(callback);
187 | #else
188 | // Prevent compiler warnings
189 | (void)callback;
190 | #endif
191 | }
192 |
193 | void CRSFforArduino::setRawDataCallback(void (*callback)(int8_t byteReceived))
194 | {
195 | this->SerialReceiver::setRawDataCallback(callback);
196 | }
197 |
198 | void CRSFforArduino::setLinkUpCallback(void (*callback)())
199 | {
200 | this->SerialReceiver::setLinkUpCallback(callback);
201 | }
202 |
203 | void CRSFforArduino::setLinkDownCallback(void (*callback)())
204 | {
205 | this->SerialReceiver::setLinkDownCallback(callback);
206 | }
207 |
208 | void CRSFforArduino::setLinkStatisticsCallback(void (*callback)(serialReceiverLayer::link_statistics_t linkStatistics))
209 | {
210 | #if CRSF_LINK_STATISTICS_ENABLED > 0
211 | this->SerialReceiver::setLinkStatisticsCallback(callback);
212 | #else
213 | // Prevent compiler warnings
214 | (void)callback;
215 | #endif
216 | }
217 |
218 | /**
219 | * @brief Assigns a Flight Mode to the specified channel.
220 | *
221 | * @param flightModeId The ID of the Flight Mode to assign.
222 | * @param flightModeName The name of the Flight Mode to assign.
223 | * @param channel The channel to assign the Flight Mode to.
224 | * @param min The minimum RC value for the Flight Mode to be active.
225 | * @param max The maximum RC value for the Flight Mode to be active.
226 | * @return true if the Flight Mode was assigned successfully.
227 | */
228 | bool CRSFforArduino::setFlightMode(serialReceiverLayer::flightModeId_t flightModeId, const char *flightModeName, uint8_t channel, uint16_t min, uint16_t max)
229 | {
230 | #if CRSF_RC_ENABLED > 0 && CRSF_FLIGHTMODES_ENABLED > 0
231 | return this->SerialReceiver::setFlightMode(flightModeId, flightModeName, channel - 1, this->SerialReceiver::usToRc(min), this->SerialReceiver::usToRc(max));
232 | #else
233 | // Prevent compiler warnings
234 | (void)flightModeId;
235 | (void)flightModeName;
236 | (void)channel;
237 | (void)min;
238 | (void)max;
239 |
240 | // Return false if RC is disabled
241 | return false;
242 | #endif
243 | }
244 |
245 | /**
246 | * @brief Assigns a Flight Mode to the specified channel.
247 | *
248 | * @param flightMode The Flight Mode to assign.
249 | * @param channel The channel to assign the Flight Mode to.
250 | * @param min The minimum RC value for the Flight Mode to be active.
251 | * @param max The maximum RC value for the Flight Mode to be active.
252 | * @return true if the Flight Mode was assigned successfully.
253 | */
254 | [[deprecated("This function must pass in the name of the Flight Mode as well as its ID.")]] bool CRSFforArduino::setFlightMode(serialReceiverLayer::flightModeId_t flightMode, uint8_t channel, uint16_t min, uint16_t max)
255 | {
256 | #if CRSF_RC_ENABLED > 0 && CRSF_FLIGHTMODES_ENABLED > 0
257 | return this->SerialReceiver::setFlightMode(flightMode, channel - 1, this->SerialReceiver::usToRc(min), this->SerialReceiver::usToRc(max));
258 | #else
259 | // Prevent compiler warnings
260 | (void)flightMode;
261 | (void)channel;
262 | (void)min;
263 | (void)max;
264 |
265 | // Return false if RC is disabled
266 | return false;
267 | #endif
268 | }
269 |
270 | /**
271 | * @brief Registers a callback function to be called when a Flight Mode is activated.
272 | * This is called when the RC value for the Flight Mode channel is between the min and max values.
273 | * @param callback The callback function to register.
274 | */
275 | void CRSFforArduino::setFlightModeCallback(void (*callback)(serialReceiverLayer::flightModeId_t flightMode))
276 | {
277 | #if CRSF_RC_ENABLED > 0 && CRSF_FLIGHTMODES_ENABLED > 0
278 | this->SerialReceiver::setFlightModeCallback(callback);
279 | #else
280 | // Prevent compiler warnings
281 | (void)callback;
282 | #endif
283 | }
284 |
285 | /**
286 | * @brief Sends a CRSF Telemetry Frame with the current attitude data.
287 | *
288 | * @param roll In decidegrees (eg 15 degrees = 150).
289 | * @param pitch In decidegrees (eg 20 degrees = 200).
290 | * @param yaw In decidegrees (eg 30 degrees = 300).
291 | */
292 | void CRSFforArduino::telemetryWriteAttitude(int16_t roll, int16_t pitch, int16_t yaw)
293 | {
294 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_ATTITUDE_ENABLED > 0
295 | this->SerialReceiver::telemetryWriteAttitude(roll, pitch, yaw);
296 | #else
297 | // Prevent compiler warnings
298 | (void)roll;
299 | (void)pitch;
300 | (void)yaw;
301 | #endif
302 | }
303 |
304 | /**
305 | * @brief Sends a CRSF Telemetry Frame with the current barometric altitude data.
306 | *
307 | * @param altitude In decimeters (eg 1m = 10)
308 | * @param vario In centimetres per second (eg 1m/s = 100)
309 | */
310 | void CRSFforArduino::telemetryWriteBaroAltitude(uint16_t altitude, int16_t vario)
311 | {
312 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_BAROALTITUDE_ENABLED > 0
313 | this->SerialReceiver::telemetryWriteBaroAltitude(altitude, vario);
314 | #else
315 | // Prevent compiler warnings
316 | (void)altitude;
317 | (void)vario;
318 | #endif
319 | }
320 |
321 | /**
322 | * @brief Sends a CRSF Telemetry Frame with the current battery data.
323 | *
324 | * @param voltage In millivolts * 100 (eg 3.8V = 380.0F).
325 | * @param current In milliamps * 10 (eg 1.5A = 150.0F).
326 | * @param fuel In milliampere hours (eg 100 mAh = 100).
327 | * @param percent In percent (eg 50% = 50).
328 | */
329 | void CRSFforArduino::telemetryWriteBattery(float voltage, float current, uint32_t fuel, uint8_t percent)
330 | {
331 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_BATTERY_ENABLED > 0
332 | this->SerialReceiver::telemetryWriteBattery(voltage, current, fuel, percent);
333 | #else
334 | // Prevent compiler warnings
335 | (void)voltage;
336 | (void)current;
337 | (void)fuel;
338 | (void)percent;
339 | #endif
340 | }
341 |
342 | /**
343 | * @brief Sends a CRSF Telemetry Frame with the current Flight Mode.
344 | *
345 | * @param flightMode The Flight Mode to send.
346 | */
347 | void CRSFforArduino::telemetryWriteFlightMode(serialReceiverLayer::flightModeId_t flightMode, bool disarmed)
348 | {
349 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_FLIGHTMODE_ENABLED > 0
350 | this->SerialReceiver::telemetryWriteFlightMode(flightMode, disarmed);
351 | #else
352 | // Prevent compiler warnings
353 | (void)flightMode;
354 | (void)disarmed;
355 | #endif
356 | }
357 |
358 | /**
359 | * @brief Sends a CRSF Telemetry Frame with a custom Flight Mode string.
360 | *
361 | * @param flightMode The Flight Mode string to send.
362 | */
363 | [[deprecated("This is nos handled automatically with telemetryWriteFlightMode()")]] void CRSFforArduino::telemetryWriteCustomFlightMode(const char *flightMode, bool armed)
364 | {
365 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_FLIGHTMODE_ENABLED > 0
366 | this->SerialReceiver::telemetryWriteCustomFlightMode(flightMode, armed);
367 | #else
368 | // Prevent compiler warnings
369 | (void)flightMode;
370 | #endif
371 | }
372 |
373 | /**
374 | * @brief Sends a CRSF Telemetry Frame with the current GPS data.
375 | *
376 | * @param latitude In decimal degrees.
377 | * @param longitude In decimal degrees.
378 | * @param altitude In centimetres.
379 | * @param speed in centimeters per second.
380 | * @param groundCourse In degrees.
381 | * @param satellites In view.
382 | */
383 | void CRSFforArduino::telemetryWriteGPS(float latitude, float longitude, float altitude, float speed, float groundCourse, uint8_t satellites)
384 | {
385 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_GPS_ENABLED > 0
386 | this->SerialReceiver::telemetryWriteGPS(latitude, longitude, altitude, speed, groundCourse, satellites);
387 | #else
388 | // Prevent compiler warnings
389 | (void)latitude;
390 | (void)longitude;
391 | (void)altitude;
392 | (void)speed;
393 | (void)groundCourse;
394 | (void)satellites;
395 | #endif
396 | }
397 | } // namespace sketchLayer
398 |
--------------------------------------------------------------------------------
/src/CRSFforArduino.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CRSFforArduino.cpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This is the Sketch Layer, which is a simplified API for CRSF for Arduino.
5 | * It is intended to be used by the user in their sketches.
6 | *
7 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
8 | *
9 | * @section License GNU Affero General Public License v3.0
10 | * This source file is a part of the CRSF for Arduino library.
11 | * CRSF for Arduino is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU Affero General Public License as published by
13 | * the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * CRSF for Arduino is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU Affero General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU Affero General Public License
22 | * along with CRSF for Arduino. If not, see .
23 | *
24 | */
25 |
26 | #pragma once
27 |
28 | #include "Arduino.h"
29 | #include "SerialReceiver/SerialReceiver.hpp"
30 |
31 | namespace sketchLayer
32 | {
33 | class CRSFforArduino : private serialReceiverLayer::SerialReceiver
34 | {
35 | public:
36 | CRSFforArduino();
37 | explicit CRSFforArduino(HardwareSerial *serialPort);
38 | CRSFforArduino(HardwareSerial *serialPort, int rxPin, int txPin);
39 | ~CRSFforArduino();
40 | bool begin(const uint32_t baud_rate = crsfProtocol::BAUD_RATE);
41 | void end();
42 | void update();
43 |
44 | // RC channel functions.
45 | uint16_t getChannel(uint8_t channel);
46 | uint16_t rcToUs(uint16_t rc);
47 | uint16_t readRcChannel(uint8_t channel, bool raw = false);
48 | void setRcChannelsCallback(void (*callback)(serialReceiverLayer::rcChannels_t *rcChannels));
49 |
50 | // Link statistics functions.
51 | void setLinkStatisticsCallback(void (*callback)(serialReceiverLayer::link_statistics_t linkStatistics));
52 |
53 | // Flight mode functions.
54 | bool setFlightMode(serialReceiverLayer::flightModeId_t flightModeId, const char *flightModeName, uint8_t channel, uint16_t min, uint16_t max);
55 | bool setFlightMode(serialReceiverLayer::flightModeId_t flightMode, uint8_t channel, uint16_t min, uint16_t max);
56 | void setFlightModeCallback(void (*callback)(serialReceiverLayer::flightModeId_t flightMode));
57 | void setRawDataCallback(void (*callback)(int8_t byteReceived));
58 |
59 | void setLinkUpCallback(void (*callback)());
60 | void setLinkDownCallback(void (*callback)());
61 |
62 | // Telemetry functions.
63 | void telemetryWriteAttitude(int16_t roll, int16_t pitch, int16_t yaw);
64 | void telemetryWriteBaroAltitude(uint16_t altitude, int16_t vario);
65 | void telemetryWriteBattery(float voltage, float current, uint32_t fuel, uint8_t percent);
66 | void telemetryWriteFlightMode(serialReceiverLayer::flightModeId_t flightMode, bool disarmed = false);
67 | void telemetryWriteCustomFlightMode(const char *flightMode, bool armed = false);
68 | void telemetryWriteGPS(float latitude, float longitude, float altitude, float speed, float groundCourse, uint8_t satellites);
69 |
70 | private:
71 | };
72 | } // namespace sketchLayer
73 |
74 | using namespace sketchLayer;
75 |
--------------------------------------------------------------------------------
/src/SerialReceiver/CRC/CRC.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CRC.cpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief A generic CRC8 implementation for the CRSF for Arduino library.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "CRC.hpp"
26 | #include "stdlib.h"
27 |
28 | namespace genericCrc
29 | {
30 | GenericCRC::GenericCRC()
31 | {
32 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SPEED)
33 | crc_8_dvb_s2_table = new uint8_t[256];
34 |
35 | for (uint16_t i = 0; i < 256; i++)
36 | {
37 | uint8_t crc = i;
38 | for (uint8_t j = 0; j < 8; j++)
39 | {
40 | if (crc & 0x80)
41 | {
42 | crc = (crc << 1) ^ 0xd5;
43 | }
44 | else
45 | {
46 | crc <<= 1;
47 | }
48 | }
49 |
50 | crc_8_dvb_s2_table[i] = crc & 0xff;
51 | }
52 | #endif
53 | }
54 |
55 | /* GenericCRC copy constructor. */
56 | GenericCRC::GenericCRC(const GenericCRC &other)
57 | {
58 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SPEED)
59 | crc_8_dvb_s2_table = new uint8_t[256];
60 | for (uint16_t i = 0; i < 256; i++)
61 | {
62 | crc_8_dvb_s2_table[i] = other.crc_8_dvb_s2_table[i];
63 | }
64 | #endif
65 | }
66 |
67 | /* GenericCRC operator= */
68 | GenericCRC &GenericCRC::operator=(const GenericCRC &other)
69 | {
70 | if (this != &other)
71 | {
72 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SPEED)
73 | crc_8_dvb_s2_table = other.crc_8_dvb_s2_table;
74 | #endif
75 | }
76 | return *this;
77 | }
78 |
79 | GenericCRC::~GenericCRC()
80 | {
81 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SPEED)
82 | delete[] crc_8_dvb_s2_table;
83 | crc_8_dvb_s2_table = nullptr;
84 | #endif
85 | }
86 |
87 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SIZE)
88 | uint8_t GenericCRC::crc_8_dvb_s2(uint8_t crc, uint8_t data)
89 | {
90 | crc ^= data;
91 | for (uint8_t i = 0; i < 8; i++)
92 | {
93 | if (crc & 0x80)
94 | {
95 | crc = (crc << 1) ^ 0xd5;
96 | }
97 | else
98 | {
99 | crc <<= 1;
100 | }
101 | }
102 | return crc;
103 | }
104 | #endif
105 |
106 | uint8_t GenericCRC::calculate(uint8_t start, const uint8_t *data, uint8_t length)
107 | {
108 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SPEED)
109 | uint8_t crc = crc_8_dvb_s2_table[0 ^ start];
110 |
111 | for (uint8_t i = 0; i < length; i++)
112 | {
113 | crc = crc_8_dvb_s2_table[crc ^ data[i]];
114 | }
115 |
116 | return crc;
117 | #elif (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SIZE)
118 | uint8_t crc = crc_8_dvb_s2(0, start);
119 |
120 | for (uint8_t i = 0; i < length; i++)
121 | {
122 | crc = crc_8_dvb_s2(crc, data[i]);
123 | }
124 |
125 | return crc;
126 | #elif (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_HARDWARE)
127 | #error "CRC_OPTIMISATION_LEVEL is set to CRC_OPTIMISATION_HARDWARE, but no hardware implementation is available."
128 | #endif
129 | }
130 |
131 | uint8_t GenericCRC::calculate(uint8_t offset, uint8_t start, const uint8_t *data, uint8_t length)
132 | {
133 | (void)start;
134 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SPEED)
135 | uint8_t crc = crc_8_dvb_s2_table[0 ^ data[offset]];
136 |
137 | for (uint8_t i = offset + 1; i < length; i++)
138 | {
139 | crc = crc_8_dvb_s2_table[crc ^ data[i]];
140 | }
141 |
142 | return crc;
143 | #elif (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SIZE)
144 | uint8_t crc = crc_8_dvb_s2(0, data[offset]);
145 |
146 | for (uint8_t i = offset + 1; i < length; i++)
147 | {
148 | crc = crc_8_dvb_s2(crc, data[i]);
149 | }
150 |
151 | return crc;
152 | #elif (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_HARDWARE)
153 | #error "CRC_OPTIMISATION_LEVEL is set to CRC_OPTIMISATION_HARDWARE, but no hardware implementation is available."
154 | #endif
155 | }
156 | } // namespace genericCrc
157 |
--------------------------------------------------------------------------------
/src/SerialReceiver/CRC/CRC.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file GenericCRC.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief A generic CRC8 implementation for the CRSF for Arduino library.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #pragma once
26 |
27 | #include "stdint.h"
28 |
29 | namespace genericCrc
30 | {
31 | #define CRC_OPTIMISATION_SPEED 0
32 | #define CRC_OPTIMISATION_SIZE 1
33 | #define CRC_OPTIMISATION_HARDWARE 2
34 |
35 | class GenericCRC
36 | {
37 | public:
38 | GenericCRC();
39 | /* GenericCRC copy constructor. */
40 | GenericCRC(const GenericCRC &other);
41 | /* GenericCRC operator= */
42 | GenericCRC &operator=(const GenericCRC &other);
43 | virtual ~GenericCRC();
44 |
45 | uint8_t calculate(uint8_t start, const uint8_t *data, uint8_t length);
46 | uint8_t calculate(uint8_t offset, uint8_t start, const uint8_t *data, uint8_t length);
47 |
48 | private:
49 | #if (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SPEED)
50 | uint8_t *crc_8_dvb_s2_table;
51 | #elif (CRC_OPTIMISATION_LEVEL == CRC_OPTIMISATION_SIZE)
52 | uint8_t crc_8_dvb_s2(uint8_t crc, uint8_t data);
53 | #endif
54 | };
55 | } // namespace genericCrc
56 |
--------------------------------------------------------------------------------
/src/SerialReceiver/CRSF/CRSF.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CRSF.cpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This decodes CRSF frames from a serial port.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "CRSF.hpp"
26 | #include "Arduino.h"
27 |
28 | using namespace crsfProtocol;
29 | using namespace genericCrc;
30 |
31 | namespace serialReceiverLayer
32 | {
33 | CRSF::CRSF()
34 | {
35 | rcFrameReceived = false;
36 | frameCount = 0;
37 | timePerFrame = 0;
38 |
39 | crc8 = new GenericCRC();
40 | }
41 |
42 | CRSF::CRSF(const CRSF &crsf)
43 | {
44 | rcFrameReceived = crsf.rcFrameReceived;
45 | frameCount = crsf.frameCount;
46 | timePerFrame = crsf.timePerFrame;
47 |
48 | memcpy(rxFrame.raw, crsf.rxFrame.raw, CRSF_FRAME_SIZE_MAX);
49 | memcpy(rcChannelsFrame.raw, crsf.rcChannelsFrame.raw, CRSF_FRAME_SIZE_MAX);
50 |
51 | crc8 = new GenericCRC(*crsf.crc8);
52 | }
53 |
54 | CRSF &CRSF::operator=(const CRSF &crsf)
55 | {
56 | if (this != &crsf)
57 | {
58 | rcFrameReceived = crsf.rcFrameReceived;
59 | frameCount = crsf.frameCount;
60 | timePerFrame = crsf.timePerFrame;
61 |
62 | memcpy(rxFrame.raw, crsf.rxFrame.raw, CRSF_FRAME_SIZE_MAX);
63 | memcpy(rcChannelsFrame.raw, crsf.rcChannelsFrame.raw, CRSF_FRAME_SIZE_MAX);
64 |
65 | *crc8 = *crsf.crc8;
66 | }
67 |
68 | return *this;
69 | }
70 |
71 | CRSF::~CRSF()
72 | {
73 | delete crc8;
74 | crc8 = nullptr;
75 | }
76 |
77 | void CRSF::begin()
78 | {
79 | rcFrameReceived = false;
80 | frameCount = 0;
81 | timePerFrame = 0;
82 |
83 | memset(rxFrame.raw, 0, CRSF_FRAME_SIZE_MAX);
84 | memset(rcChannelsFrame.raw, 0, CRSF_FRAME_SIZE_MAX);
85 | }
86 |
87 | void CRSF::end()
88 | {
89 | memset(rcChannelsFrame.raw, 0, CRSF_FRAME_SIZE_MAX);
90 | memset(rxFrame.raw, 0, CRSF_FRAME_SIZE_MAX);
91 |
92 | timePerFrame = 0;
93 | frameCount = 0;
94 | rcFrameReceived = false;
95 | }
96 |
97 | void CRSF::setFrameTime(uint32_t baudRate, uint8_t packetCount)
98 | {
99 | /* Calculate the time per frame based on the baud rate and packet count. */
100 | timePerFrame = ((1000000 * packetCount) / (baudRate / (CRSF_FRAME_SIZE_MAX - 1)));
101 | }
102 |
103 | bool CRSF::receiveFrames(uint8_t rxByte)
104 | {
105 | static uint8_t framePosition = 0;
106 | static uint32_t frameStartTime = 0;
107 | const uint32_t currentTime = micros();
108 |
109 | /* Reset the frame position if the frame time has expired. */
110 | if (currentTime - frameStartTime > timePerFrame)
111 | {
112 | framePosition = 0;
113 |
114 | if (currentTime < frameStartTime)
115 | {
116 | frameStartTime = currentTime;
117 | }
118 | }
119 |
120 | if (framePosition == 0)
121 | {
122 | frameStartTime = currentTime;
123 | }
124 |
125 | /* Assume the full frame length is 5 bytes until the frame length byte is received. */
126 | const int fullFrameLength = framePosition < 3 ? 5 : min(rxFrame.frame.frameLength + CRSF_FRAME_LENGTH_ADDRESS + CRSF_FRAME_LENGTH_FRAMELENGTH, (int)CRSF_FRAME_SIZE_MAX);
127 |
128 | if (framePosition < fullFrameLength)
129 | {
130 | /* Store the received byte in the frame buffer. */
131 | rxFrame.raw[framePosition] = rxByte;
132 | framePosition++;
133 |
134 | if (framePosition >= fullFrameLength)
135 | {
136 | /* Frame is complete, calculate the CRC and check if it is valid. */
137 | const uint8_t crc = calculateFrameCRC();
138 |
139 | if (crc == rxFrame.raw[fullFrameLength - 1])
140 | {
141 | switch (rxFrame.frame.type)
142 | {
143 | case crsfProtocol::CRSF_FRAMETYPE_RC_CHANNELS_PACKED:
144 | if (rxFrame.frame.deviceAddress == CRSF_ADDRESS_FLIGHT_CONTROLLER)
145 | {
146 | memcpy(&rcChannelsFrame, &rxFrame, CRSF_FRAME_SIZE_MAX);
147 | rcFrameReceived = true;
148 | }
149 | break;
150 |
151 | #if CRSF_LINK_STATISTICS_ENABLED > 0
152 | case CRSF_FRAMETYPE_LINK_STATISTICS:
153 | if ((rxFrame.frame.deviceAddress == CRSF_ADDRESS_FLIGHT_CONTROLLER) && (rxFrame.frame.frameLength == CRSF_FRAME_ORIGIN_DEST_SIZE + CRSF_FRAME_LINK_STATISTICS_PAYLOAD_SIZE))
154 | {
155 | crsf_payload_link_statistics_t linkStatisticsPayload;
156 | memcpy(&linkStatisticsPayload, rxFrame.frame.payload, sizeof(crsf_payload_link_statistics_t));
157 |
158 | linkStatistics.rssi = (linkStatisticsPayload.active_antenna ? linkStatisticsPayload.uplink_rssi_2 : linkStatisticsPayload.uplink_rssi_1);
159 | linkStatistics.lqi = linkStatisticsPayload.uplink_link_quality;
160 | linkStatistics.snr = linkStatisticsPayload.uplink_snr;
161 | linkStatistics.tx_power = (linkStatisticsPayload.uplink_tx_power < 9) ? tx_power_table[linkStatisticsPayload.uplink_tx_power] : 0;
162 | }
163 | break;
164 | #endif
165 | }
166 | }
167 |
168 | /* Clear the frame buffer and reset the frame position. */
169 | memset(rxFrame.raw, 0, CRSF_FRAME_SIZE_MAX);
170 | framePosition = 0;
171 | return true;
172 | }
173 | }
174 |
175 | return false;
176 | }
177 |
178 | void CRSF::getFailSafe(bool *failSafe)
179 | {
180 | /* Set the failsafe flag based on the link statistics thresholds. */
181 | if (linkStatistics.lqi <= CRSF_FAILSAFE_LQI_THRESHOLD || linkStatistics.rssi >= CRSF_FAILSAFE_RSSI_THRESHOLD)
182 | {
183 | *failSafe = true;
184 | }
185 | else
186 | {
187 | *failSafe = false;
188 | }
189 | }
190 |
191 | void CRSF::getRcChannels(uint16_t *rcChannels)
192 | {
193 | /* Decode RC frames if one has been received. */
194 | if (rcFrameReceived)
195 | {
196 | rcFrameReceived = false;
197 | if (rcChannelsFrame.frame.type == CRSF_FRAMETYPE_RC_CHANNELS_PACKED)
198 | {
199 | rcChannelsPacked_t rcChannelsPacked;
200 | memcpy(&rcChannelsPacked, rcChannelsFrame.frame.payload, sizeof(rcChannelsPacked_t));
201 |
202 | rcChannels[RC_CHANNEL_ROLL] = rcChannelsPacked.channel0;
203 | rcChannels[RC_CHANNEL_PITCH] = rcChannelsPacked.channel1;
204 | rcChannels[RC_CHANNEL_THROTTLE] = rcChannelsPacked.channel2;
205 | rcChannels[RC_CHANNEL_YAW] = rcChannelsPacked.channel3;
206 | rcChannels[RC_CHANNEL_AUX1] = rcChannelsPacked.channel4;
207 | rcChannels[RC_CHANNEL_AUX2] = rcChannelsPacked.channel5;
208 | rcChannels[RC_CHANNEL_AUX3] = rcChannelsPacked.channel6;
209 | rcChannels[RC_CHANNEL_AUX4] = rcChannelsPacked.channel7;
210 | rcChannels[RC_CHANNEL_AUX5] = rcChannelsPacked.channel8;
211 | rcChannels[RC_CHANNEL_AUX6] = rcChannelsPacked.channel9;
212 | rcChannels[RC_CHANNEL_AUX7] = rcChannelsPacked.channel10;
213 | rcChannels[RC_CHANNEL_AUX8] = rcChannelsPacked.channel11;
214 | rcChannels[RC_CHANNEL_AUX9] = rcChannelsPacked.channel12;
215 | rcChannels[RC_CHANNEL_AUX10] = rcChannelsPacked.channel13;
216 | rcChannels[RC_CHANNEL_AUX11] = rcChannelsPacked.channel14;
217 | rcChannels[RC_CHANNEL_AUX12] = rcChannelsPacked.channel15;
218 | }
219 | }
220 | }
221 |
222 | void CRSF::getLinkStatistics(link_statistics_t *linkStats)
223 | {
224 | #if CRSF_LINK_STATISTICS_ENABLED > 0
225 | memcpy(linkStats, &linkStatistics, sizeof(link_statistics_t));
226 | #else
227 | (void)linkStats;
228 | #endif
229 | }
230 |
231 | uint8_t CRSF::calculateFrameCRC()
232 | {
233 | return crc8->calculate(rxFrame.frame.type, rxFrame.frame.payload, rxFrame.frame.frameLength - CRSF_FRAME_LENGTH_TYPE_CRC);
234 | }
235 | } // namespace serialReceiverLayer
236 |
--------------------------------------------------------------------------------
/src/SerialReceiver/CRSF/CRSF.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CRSF.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This decodes CRSF frames from a serial port.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #pragma once
26 |
27 | #include "../CRC/CRC.hpp"
28 | #include "CRSFProtocol.hpp"
29 |
30 | namespace serialReceiverLayer
31 | {
32 | typedef struct link_statistics_s
33 | {
34 | int16_t rssi = 0;
35 | int16_t lqi = 0;
36 | int16_t snr = 0;
37 | int16_t tx_power = 0;
38 | } link_statistics_t;
39 |
40 | const uint16_t tx_power_table[9] = {
41 | 0, // 0 mW
42 | 10, // 10 mW
43 | 25, // 25 mW
44 | 100, // 100 mW
45 | 500, // 500 mW
46 | 1000, // 1 W
47 | 2000, // 2 W
48 | 250, // 250 mW
49 | 50 // 50 mW
50 | };
51 |
52 | class CRSF
53 | {
54 | public:
55 | CRSF();
56 | CRSF(const CRSF &crsf);
57 | CRSF &operator=(const CRSF &crsf);
58 | virtual ~CRSF();
59 | void begin();
60 | void end();
61 | void setFrameTime(uint32_t baudRate, uint8_t packetCount = 10);
62 | bool receiveFrames(uint8_t rxByte);
63 | void getFailSafe(bool *failSafe);
64 | void getRcChannels(uint16_t *rcChannels);
65 | void getLinkStatistics(link_statistics_t *linkStats);
66 |
67 | private:
68 | bool rcFrameReceived;
69 | uint16_t frameCount;
70 | uint32_t timePerFrame;
71 | crsfProtocol::frame_t rxFrame;
72 | crsfProtocol::frame_t rcChannelsFrame;
73 | link_statistics_t linkStatistics;
74 | genericCrc::GenericCRC *crc8 = nullptr;
75 | uint8_t calculateFrameCRC();
76 | };
77 | } // namespace serialReceiverLayer
78 |
--------------------------------------------------------------------------------
/src/SerialReceiver/CRSF/CRSFProtocol.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CRSFProtocol.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This file contains enums and structs for the CRSF protocol.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "stdint.h"
26 |
27 | #pragma once
28 |
29 | #ifndef ENV_DEFECT_DETECTOR
30 | #include "../../CFA_Config.hpp"
31 | #endif
32 |
33 | namespace crsfProtocol
34 | {
35 | enum rc_channels_e
36 | {
37 | RC_CHANNEL_ROLL = 0,
38 | RC_CHANNEL_PITCH,
39 | RC_CHANNEL_THROTTLE,
40 | RC_CHANNEL_YAW,
41 | RC_CHANNEL_AUX1,
42 | RC_CHANNEL_AUX2,
43 | RC_CHANNEL_AUX3,
44 | RC_CHANNEL_AUX4,
45 | RC_CHANNEL_AUX5,
46 | RC_CHANNEL_AUX6,
47 | RC_CHANNEL_AUX7,
48 | RC_CHANNEL_AUX8,
49 | RC_CHANNEL_AUX9,
50 | RC_CHANNEL_AUX10,
51 | RC_CHANNEL_AUX11,
52 | RC_CHANNEL_AUX12,
53 | RC_CHANNEL_COUNT
54 | };
55 |
56 | enum syncByte_e
57 | {
58 | CRSF_SYNC_BYTE = 0xC8,
59 | };
60 |
61 | enum frameSize_e
62 | {
63 | CRSF_FRAME_SIZE_MAX = 64,
64 | CRSF_PAYLOAD_SIZE_MAX = CRSF_FRAME_SIZE_MAX - 6
65 | };
66 |
67 | enum payloadSize_e
68 | {
69 | CRSF_FRAME_GPS_PAYLOAD_SIZE = 15,
70 | CRSF_FRAME_VARIO_PAYLOAD_SIZE = 2,
71 | CRSF_FRAME_BARO_ALTITUDE_PAYLOAD_SIZE = 4, // TBS is 2, ExpressLRS is 4 (combines vario)
72 | CRSF_FRAME_BATTERY_SENSOR_PAYLOAD_SIZE = 8,
73 | CRSF_FRAME_DEVICE_INFO_PAYLOAD_SIZE = 48,
74 | CRSF_FRAME_FLIGHT_MODE_PAYLOAD_SIZE = 16,
75 | CRSF_FRAME_HEARTBEAT_PAYLOAD_SIZE = 2,
76 | CRSF_FRAME_LINK_STATISTICS_PAYLOAD_SIZE = 10,
77 | CRSF_FRAME_LINK_STATISTICS_TX_PAYLOAD_SIZE = 6,
78 | CRSF_FRAME_RC_CHANNELS_PAYLOAD_SIZE = 22,
79 | CRSF_FRAME_ATTITUDE_PAYLOAD_SIZE = 6
80 | };
81 |
82 | enum frameLength_e
83 | {
84 | CRSF_FRAME_LENGTH_ADDRESS = 1, // Length of the address field in bytes.
85 | CRSF_FRAME_LENGTH_FRAMELENGTH = 1, // Length of the frame length field in bytes.
86 | CRSF_FRAME_LENGTH_TYPE = 1, // Length of the type field in bytes.
87 | CRSF_FRAME_LENGTH_CRC = 1, // Length of the CRC field in bytes.
88 | CRSF_FRAME_LENGTH_TYPE_CRC = CRSF_FRAME_LENGTH_TYPE + CRSF_FRAME_LENGTH_CRC, // Length of the type and CRC fields in bytes.
89 | CRSF_FRAME_LENGTH_EXT_TYPE_CRC = 4, // Length of the extended Dest/Origin, type, and CRC fields in bytes.
90 | CRSF_FRAME_LENGTH_NON_PAYLOAD = 4 // Combined length of all fields except the payload in bytes.
91 | };
92 |
93 | typedef enum frameType_e
94 | {
95 | CRSF_FRAMETYPE_GPS = 0x02,
96 | CRSF_FRAMETYPE_VARIO = 0x07,
97 | CRSF_FRAMETYPE_BATTERY_SENSOR = 0x08,
98 | CRSF_FRAMETYPE_BARO_ALTITUDE = 0x09,
99 | CRSF_FRAMETYPE_HEARTBEAT = 0x0B,
100 | CRSF_FRAMETYPE_LINK_STATISTICS = 0x14,
101 | CRSF_FRAMETYPE_RC_CHANNELS_PACKED = 0x16,
102 | CRSF_FRAMETYPE_SUBSET_RC_CHANNELS_PACKED = 0x17,
103 | CRSF_FRAMETYPE_LINK_STATISTICS_RX = 0x1C,
104 | CRSF_FRAMETYPE_LINK_STATISTICS_TX = 0x1D,
105 | CRSF_FRAMETYPE_ATTITUDE = 0x1E,
106 | CRSF_FRAMETYPE_FLIGHT_MODE = 0x21,
107 |
108 | CRSF_FRAMETYPE_DEVICE_PING = 0x28,
109 | CRSF_FRAMETYPE_DEVICE_INFO = 0x29,
110 | CRSF_FRAMETYPE_PARAMETER_SETTINGS_ENTRY = 0x2B,
111 | CRSF_FRAMETYPE_PARAMETER_READ = 0x2C,
112 | CRSF_FRAMETYPE_PARAMETER_WRITE = 0x2D,
113 | CRSF_FRAMETYPE_COMMAND = 0x32,
114 |
115 | CRSF_FRAMETYPE_MSP_REQ = 0x7A,
116 | CRSF_FRAMETYPE_MSP_RESP = 0x7B,
117 | CRSF_FRAMETYPE_MSP_WRITE = 0x7C,
118 | CRSF_FRAMETYPE_DISPLAYPORT_CMD = 0x7D,
119 | } frameType_t;
120 |
121 | #if CRSF_TELEMETRY_ENABLED == 1 || CRSF_LINK_STATISTICS_ENABLED == 1
122 | #define CRSF_FRAME_ORIGIN_DEST_SIZE 2
123 | #endif
124 |
125 | typedef enum address_e
126 | {
127 | CRSF_ADDRESS_BROADCAST = 0x00,
128 | CRSF_ADDRESS_USB = 0x10,
129 | CRSF_ADDRESS_TBS_CORE_PNP_PRO = 0x80,
130 | CRSF_ADDRESS_RESERVED1 = 0x8A,
131 | CRSF_ADDRESS_CURRENT_SENSOR = 0xC0,
132 | CRSF_ADDRESS_GPS = 0xC2,
133 | CRSF_ADDRESS_TBS_BLACKBOX = 0xC4,
134 | CRSF_ADDRESS_FLIGHT_CONTROLLER = 0xC8,
135 | CRSF_ADDRESS_RESERVED2 = 0xCA,
136 | CRSF_ADDRESS_RACE_TAG = 0xCC,
137 | CRSF_ADDRESS_RADIO_TRANSMITTER = 0xEA,
138 | CRSF_ADDRESS_CRSF_RECEIVER = 0xEC,
139 | CRSF_ADDRESS_CRSF_TRANSMITTER = 0xEE
140 | } address_t;
141 |
142 | // Schedule array to send telemetry frames.
143 | typedef enum
144 | {
145 | CRSF_TELEMETRY_FRAME_START_INDEX = 0,
146 | CRSF_TELEMETRY_FRAME_ATTITUDE_INDEX,
147 | CRSF_TELEMETRY_FRAME_BARO_ALTITUDE_INDEX,
148 | CRSF_TELEMETRY_FRAME_BATTERY_SENSOR_INDEX,
149 | CRSF_TELEMETRY_FRAME_FLIGHT_MODE_INDEX,
150 | CRSF_TELEMETRY_FRAME_GPS_INDEX,
151 | // CRSF_TELEMETRY_FRAME_HEARTBEAT_INDEX,
152 | // CRSF_TELEMETRY_FRAME_VARIO_INDEX,
153 | CRSF_TELEMETRY_FRAME_SCHEDULE_MAX
154 | } telemetryFrame_t;
155 |
156 | // RC Channels Packed. 22 bytes (11 bits per channel, 16 channels) total.
157 | struct rcChannelsPacked_s
158 | {
159 | uint16_t channel0 : 11;
160 | uint16_t channel1 : 11;
161 | uint16_t channel2 : 11;
162 | uint16_t channel3 : 11;
163 | uint16_t channel4 : 11;
164 | uint16_t channel5 : 11;
165 | uint16_t channel6 : 11;
166 | uint16_t channel7 : 11;
167 | uint16_t channel8 : 11;
168 | uint16_t channel9 : 11;
169 | uint16_t channel10 : 11;
170 | uint16_t channel11 : 11;
171 | uint16_t channel12 : 11;
172 | uint16_t channel13 : 11;
173 | uint16_t channel14 : 11;
174 | uint16_t channel15 : 11;
175 | } __attribute__((packed));
176 |
177 | typedef struct rcChannelsPacked_s rcChannelsPacked_t;
178 |
179 | typedef struct frameDefinition_s
180 | {
181 | uint8_t deviceAddress; // Frame address.
182 | uint8_t frameLength; // Frame length. Includes payload and CRC.
183 | uint8_t type; // Frame type.
184 | uint8_t payload[CRSF_PAYLOAD_SIZE_MAX + CRSF_FRAME_LENGTH_CRC]; // Frame payload.
185 | } frameDefinition_t;
186 |
187 | typedef union frame_u
188 | {
189 | uint8_t raw[CRSF_FRAME_SIZE_MAX];
190 | frameDefinition_t frame;
191 | } frame_t;
192 |
193 | #if CRSF_LINK_STATISTICS_ENABLED > 0
194 | // Link Statistics frame.
195 | // Uplink is the connection from the transmitter to the receiver. Downlink is in the opposite direction.
196 | typedef struct crsf_payload_link_statistics_s
197 | {
198 | uint8_t uplink_rssi_1; // Uplink RSSI Antenna 1 (dBm * -1)
199 | uint8_t uplink_rssi_2; // Uplink RSSI Antenna 2 (dBm * -1)
200 | uint8_t uplink_link_quality; // Uplink Link Quality/Packet Success Rate (%)
201 | int8_t uplink_snr; // Uplink Signal-to-Noise Ratio (dB)
202 | uint8_t active_antenna; // Active Antenna (0 = Antenna 1, 1 = Antenna 2)
203 | uint8_t rf_mode; // RF Mode (4 fps = 0, 50 fps = 1, 150 fps = 2, 250 fps = 3, 500 fps = 4, 1000 fps = 5)
204 | uint8_t uplink_tx_power; // Uplink TX Power (0 mW = 0, 10 mW = 1, 25 mW = 2, 100 mW = 3, 250 mW = 4, 500 mW = 5, 1000 mW = 6, 2000 mW = 7)
205 | uint8_t downlink_rssi; // Downlink RSSI (dBm * -1)
206 | uint8_t downlink_link_quality; // Downlink Link Quality/Packet Success Rate (%)
207 | int8_t downlink_snr; // Downlink Signal-to-Noise Ratio (dB)
208 | } crsf_payload_link_statistics_t;
209 | #endif
210 |
211 | // Attitude Data to pass to the telemetry frame.
212 | typedef struct attitudeData_s
213 | {
214 | int16_t roll; // Roll angle in radians.
215 | int16_t pitch; // Pitch angle in radians.
216 | int16_t yaw; // Yaw angle in radians.
217 | } attitudeData_t;
218 |
219 | // Barometric Altitude and Variometer Data to pass to the telemetry frame.
220 | typedef struct baroAltitudeData_s
221 | {
222 | uint16_t altitude; // Altitude in decimeters + 10000 or metres if high bit is set.
223 | int16_t vario; // Variometer in centimeters per second.
224 | } baroAltitudeData_t;
225 |
226 | // Battery Sensor Data to pass to the telemetry frame.
227 | typedef struct batterySensorData_s
228 | {
229 | uint16_t voltage; // Average battery cell voltage.
230 | uint16_t current; // Amperage.
231 | uint32_t capacity; // mAh drawn.
232 | uint8_t percent; // Battery % remaining.
233 | } batterySensorData_t;
234 |
235 | // Flight Mode Data to pass to the telemetry frame.
236 | typedef struct flightModeData_s
237 | {
238 | char flightMode[CRSF_FRAME_FLIGHT_MODE_PAYLOAD_SIZE]; // Flight mode string.
239 | } flightModeData_t;
240 |
241 | // GPS Data to pass to the telemetry frame.
242 | typedef struct gpsData_s
243 | {
244 | int32_t latitude;
245 | int32_t longitude;
246 | uint16_t altitude;
247 | uint16_t speed;
248 | uint16_t groundCourse;
249 | uint8_t satellites;
250 | } gpsData_t;
251 |
252 | // Struct to hold data for the telemetry frame.
253 | typedef struct telemetryData_s
254 | {
255 | attitudeData_t attitude;
256 | baroAltitudeData_t baroAltitude;
257 | batterySensorData_t battery;
258 | flightModeData_t flightMode;
259 | gpsData_t gps;
260 | } telemetryData_t;
261 |
262 | enum baudRate_e
263 | {
264 | BAUD_RATE_LEGACY = 420000,
265 | BAUD_RATE = 416666
266 | };
267 | } // namespace crsfProtocol
268 |
--------------------------------------------------------------------------------
/src/SerialReceiver/SerialBuffer/SerialBuffer.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file SerialBuffer.cpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief A generic serial buffer for the CRSF for Arduino library.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "SerialBuffer.hpp"
26 | #include "cstring"
27 |
28 | namespace genericStreamBuffer
29 | {
30 | SerialBuffer::SerialBuffer(size_t size)
31 | {
32 | bufferIndex = 0;
33 | bufferLength = 0;
34 | bufferSizeMax = size;
35 | buffer = new uint8_t[bufferSizeMax];
36 |
37 | memset(buffer, 0, bufferSizeMax);
38 | }
39 |
40 | SerialBuffer::SerialBuffer(const SerialBuffer &serialBuffer)
41 | {
42 | bufferIndex = serialBuffer.bufferIndex;
43 | bufferLength = serialBuffer.bufferLength;
44 | bufferSizeMax = serialBuffer.bufferSizeMax;
45 | buffer = new uint8_t[bufferSizeMax];
46 |
47 | memcpy(buffer, serialBuffer.buffer, bufferSizeMax);
48 | }
49 |
50 | SerialBuffer &SerialBuffer::operator=(const SerialBuffer &serialBuffer)
51 | {
52 | if (this != &serialBuffer)
53 | {
54 | bufferIndex = serialBuffer.bufferIndex;
55 | bufferLength = serialBuffer.bufferLength;
56 | bufferSizeMax = serialBuffer.bufferSizeMax;
57 |
58 | delete[] buffer;
59 | buffer = new uint8_t[bufferSizeMax];
60 |
61 | memcpy(buffer, serialBuffer.buffer, bufferSizeMax);
62 | }
63 |
64 | return *this;
65 | }
66 |
67 | SerialBuffer::~SerialBuffer()
68 | {
69 | delete[] buffer;
70 | bufferIndex = 0;
71 | bufferLength = 0;
72 | bufferSizeMax = 0;
73 | }
74 |
75 | void SerialBuffer::reset()
76 | {
77 | bufferIndex = 0;
78 | bufferLength = 0;
79 | memset(buffer, 0, bufferSizeMax);
80 | }
81 |
82 | size_t SerialBuffer::write8(int8_t value)
83 | {
84 | if (bufferIndex + 1 > bufferSizeMax)
85 | {
86 | return 0;
87 | }
88 |
89 | buffer[bufferIndex++] = value;
90 | bufferLength = bufferIndex;
91 |
92 | return 1;
93 | }
94 |
95 | size_t SerialBuffer::write16(int16_t value)
96 | {
97 | if (bufferIndex + 2 > bufferSizeMax)
98 | {
99 | return 0;
100 | }
101 |
102 | buffer[bufferIndex++] = value & 0xFF;
103 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
104 | bufferLength = bufferIndex;
105 |
106 | return 2;
107 | }
108 |
109 | size_t SerialBuffer::write32(int32_t value)
110 | {
111 | if (bufferIndex + 4 > bufferSizeMax)
112 | {
113 | return 0;
114 | }
115 |
116 | buffer[bufferIndex++] = value & 0xFF;
117 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
118 | buffer[bufferIndex++] = (value >> 16) & 0xFF;
119 | buffer[bufferIndex++] = (value >> 24) & 0xFF;
120 | bufferLength = bufferIndex;
121 |
122 | return 4;
123 | }
124 |
125 | size_t SerialBuffer::writeU8(uint8_t value)
126 | {
127 | if (bufferIndex + 1 > bufferSizeMax)
128 | {
129 | return 0;
130 | }
131 |
132 | buffer[bufferIndex++] = value;
133 | bufferLength = bufferIndex;
134 |
135 | return 1;
136 | }
137 |
138 | size_t SerialBuffer::writeU16(uint16_t value)
139 | {
140 | if (bufferIndex + 2 > bufferSizeMax)
141 | {
142 | return 0;
143 | }
144 |
145 | buffer[bufferIndex++] = value & 0xFF;
146 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
147 | bufferLength = bufferIndex;
148 |
149 | return 2;
150 | }
151 |
152 | size_t SerialBuffer::writeU32(uint32_t value)
153 | {
154 | if (bufferIndex + 4 > bufferSizeMax)
155 | {
156 | return 0;
157 | }
158 |
159 | buffer[bufferIndex++] = value & 0xFF;
160 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
161 | buffer[bufferIndex++] = (value >> 16) & 0xFF;
162 | buffer[bufferIndex++] = (value >> 24) & 0xFF;
163 | bufferLength = bufferIndex;
164 |
165 | return 4;
166 | }
167 |
168 | size_t SerialBuffer::write8BE(int8_t value)
169 | {
170 | if (bufferIndex + 1 > bufferSizeMax)
171 | {
172 | return 0;
173 | }
174 |
175 | buffer[bufferIndex++] = value;
176 | bufferLength = bufferIndex;
177 |
178 | return 1;
179 | }
180 |
181 | size_t SerialBuffer::write16BE(int16_t value)
182 | {
183 | if (bufferIndex + 2 > bufferSizeMax)
184 | {
185 | return 0;
186 | }
187 |
188 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
189 | buffer[bufferIndex++] = value & 0xFF;
190 | bufferLength = bufferIndex;
191 |
192 | return 2;
193 | }
194 |
195 | size_t SerialBuffer::write32BE(int32_t value)
196 | {
197 | if (bufferIndex + 4 > bufferSizeMax)
198 | {
199 | return 0;
200 | }
201 |
202 | buffer[bufferIndex++] = (value >> 24) & 0xFF;
203 | buffer[bufferIndex++] = (value >> 16) & 0xFF;
204 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
205 | buffer[bufferIndex++] = value & 0xFF;
206 | bufferLength = bufferIndex;
207 |
208 | return 4;
209 | }
210 |
211 | size_t SerialBuffer::writeU8BE(uint8_t value)
212 | {
213 | if (bufferIndex + 1 > bufferSizeMax)
214 | {
215 | return 0;
216 | }
217 |
218 | buffer[bufferIndex++] = value;
219 | bufferLength = bufferIndex;
220 |
221 | return 1;
222 | }
223 |
224 | size_t SerialBuffer::writeU16BE(uint16_t value)
225 | {
226 | if (bufferIndex + 2 > bufferSizeMax)
227 | {
228 | return 0;
229 | }
230 |
231 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
232 | buffer[bufferIndex++] = value & 0xFF;
233 | bufferLength = bufferIndex;
234 |
235 | return 2;
236 | }
237 |
238 | size_t SerialBuffer::writeU24BE(uint32_t value)
239 | {
240 | if (bufferIndex + 3 > bufferSizeMax)
241 | {
242 | return 0;
243 | }
244 |
245 | buffer[bufferIndex++] = (value >> 16) & 0xFF;
246 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
247 | buffer[bufferIndex++] = value & 0xFF;
248 | bufferLength = bufferIndex;
249 |
250 | return 3;
251 | }
252 |
253 | size_t SerialBuffer::writeU32BE(uint32_t value)
254 | {
255 | if (bufferIndex + 4 > bufferSizeMax)
256 | {
257 | return 0;
258 | }
259 |
260 | buffer[bufferIndex++] = (value >> 24) & 0xFF;
261 | buffer[bufferIndex++] = (value >> 16) & 0xFF;
262 | buffer[bufferIndex++] = (value >> 8) & 0xFF;
263 | buffer[bufferIndex++] = value & 0xFF;
264 | bufferLength = bufferIndex;
265 |
266 | return 4;
267 | }
268 |
269 | size_t SerialBuffer::writeString(const char *string)
270 | {
271 | size_t length = strlen(string);
272 |
273 | if (bufferIndex + length > bufferSizeMax)
274 | {
275 | return 0;
276 | }
277 |
278 | memcpy(buffer + bufferIndex, string, length);
279 | bufferIndex += length;
280 | bufferLength = bufferIndex;
281 |
282 | return length;
283 | }
284 |
285 | size_t SerialBuffer::getLength()
286 | {
287 | return bufferLength;
288 | }
289 |
290 | size_t SerialBuffer::getMaxSize()
291 | {
292 | return bufferSizeMax;
293 | }
294 |
295 | size_t SerialBuffer::getIndex()
296 | {
297 | return bufferIndex;
298 | }
299 |
300 | uint8_t SerialBuffer::getByte(size_t index)
301 | {
302 | if (index >= bufferSizeMax)
303 | {
304 | return 0;
305 | }
306 |
307 | return buffer[index];
308 | }
309 |
310 | uint8_t *SerialBuffer::getBuffer()
311 | {
312 | return buffer;
313 | }
314 | } // namespace genericStreamBuffer
315 |
--------------------------------------------------------------------------------
/src/SerialReceiver/SerialBuffer/SerialBuffer.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file SerialBuffer.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief A generic serial buffer for the CRSF for Arduino library.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #pragma once
26 |
27 | #include "stddef.h"
28 | #include "stdint.h"
29 |
30 | namespace genericStreamBuffer
31 | {
32 | class SerialBuffer
33 | {
34 | public:
35 | explicit SerialBuffer(size_t size = 64);
36 | SerialBuffer(const SerialBuffer &serialBuffer);
37 | SerialBuffer &operator=(const SerialBuffer &serialBuffer);
38 | ~SerialBuffer();
39 |
40 | void reset();
41 |
42 | size_t write8(int8_t value);
43 | size_t write16(int16_t value);
44 | size_t write32(int32_t value);
45 |
46 | size_t writeU8(uint8_t value);
47 | size_t writeU16(uint16_t value);
48 | size_t writeU32(uint32_t value);
49 |
50 | size_t write8BE(int8_t value);
51 | size_t write16BE(int16_t value);
52 | size_t write32BE(int32_t value);
53 |
54 | size_t writeU8BE(uint8_t value);
55 | size_t writeU16BE(uint16_t value);
56 | size_t writeU24BE(uint32_t value);
57 | size_t writeU32BE(uint32_t value);
58 |
59 | size_t writeString(const char *string);
60 |
61 | size_t getLength();
62 |
63 | size_t getMaxSize();
64 |
65 | size_t getIndex();
66 |
67 | uint8_t getByte(size_t index);
68 |
69 | uint8_t *getBuffer();
70 |
71 | private:
72 | size_t bufferSizeMax;
73 | size_t bufferLength;
74 | size_t bufferIndex;
75 | uint8_t *buffer;
76 | };
77 | } // namespace genericStreamBuffer
78 |
--------------------------------------------------------------------------------
/src/SerialReceiver/SerialReceiver.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file SerialReceiver.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief The Serial Receiver layer for the CRSF for Arduino library.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #pragma once
26 |
27 | #ifndef ENV_DEFECT_DETECTOR
28 | #include "../CFA_Config.hpp"
29 | #endif
30 | #include "Arduino.h"
31 | #include "CRSF/CRSF.hpp"
32 | #include "Telemetry/Telemetry.hpp"
33 |
34 | namespace serialReceiverLayer
35 | {
36 | typedef enum flightModeId_e
37 | {
38 | FLIGHT_MODE_DISARMED = 0,
39 | FLIGHT_MODE_ACRO,
40 | FLIGHT_MODE_WAIT,
41 | FLIGHT_MODE_FAILSAFE,
42 | FLIGHT_MODE_GPS_RESCUE,
43 | FLIGHT_MODE_PASSTHROUGH,
44 | FLIGHT_MODE_ANGLE,
45 | FLIGHT_MODE_HORIZON,
46 | FLIGHT_MODE_AIRMODE,
47 |
48 | #if CRSF_CUSTOM_FLIGHT_MODES_ENABLED > 0
49 | CUSTOM_FLIGHT_MODE1,
50 | CUSTOM_FLIGHT_MODE2,
51 | CUSTOM_FLIGHT_MODE3,
52 | CUSTOM_FLIGHT_MODE4,
53 | CUSTOM_FLIGHT_MODE5,
54 | CUSTOM_FLIGHT_MODE6,
55 | CUSTOM_FLIGHT_MODE7,
56 | CUSTOM_FLIGHT_MODE8,
57 | #endif
58 | FLIGHT_MODE_COUNT
59 | } flightModeId_t;
60 |
61 | typedef struct rcChannels_s
62 | {
63 | bool valid;
64 | bool failsafe;
65 | uint16_t value[crsfProtocol::RC_CHANNEL_COUNT];
66 | } rcChannels_t;
67 |
68 | /* Function pointers for callbacks. */
69 | typedef void (*rcChannelsCallback_t)(rcChannels_t *);
70 | typedef void (*flightModeCallback_t)(flightModeId_t);
71 | typedef void (*linkStatisticsCallback_t)(link_statistics_t);
72 | typedef void (*rawDataCallback_t)(int8_t);
73 |
74 | typedef void (*linkUpCallback_t)();
75 | typedef void (*linkDownCallback_t)();
76 |
77 | class SerialReceiver
78 | {
79 | public:
80 | static const unsigned int CRSF_FAILSAFE_STAGE1_MS = 300;
81 |
82 | SerialReceiver();
83 | explicit SerialReceiver(HardwareSerial *hwUartPort);
84 | SerialReceiver(HardwareSerial *hwUartPort, int8_t rxPin, int8_t txPin);
85 | SerialReceiver(const SerialReceiver &serialReceiver);
86 | SerialReceiver &operator=(const SerialReceiver &serialReceiver);
87 | virtual ~SerialReceiver();
88 |
89 | bool begin(const uint32_t baudRate);
90 | void end();
91 |
92 | #if CRSF_RC_ENABLED > 0 || CRSF_TELEMETRY_ENABLED > 0 || CRSF_LINK_STATISTICS_ENABLED > 0
93 | void processFrames();
94 | #endif
95 |
96 |
97 |
98 | #if CRSF_LINK_STATISTICS_ENABLED > 0
99 | void setLinkStatisticsCallback(linkStatisticsCallback_t callback);
100 | #endif
101 |
102 | #if CRSF_RC_ENABLED > 0
103 | void setRcChannelsCallback(rcChannelsCallback_t callback);
104 | uint16_t getChannel(uint8_t channel);
105 | uint16_t rcToUs(uint16_t rc);
106 | uint16_t usToRc(uint16_t us);
107 | uint16_t readRcChannel(uint8_t channel, bool raw = false);
108 |
109 | #if CRSF_FLIGHTMODES_ENABLED > 0
110 | bool setFlightMode(flightModeId_t flightModeId, const char *flightModeName, uint8_t channel, uint16_t min, uint16_t max);
111 | bool setFlightMode(flightModeId_t flightMode, uint8_t channel, uint16_t min, uint16_t max);
112 | void setFlightModeCallback(flightModeCallback_t callback);
113 | void handleFlightMode();
114 | #endif
115 | #endif
116 |
117 | void setRawDataCallback(rawDataCallback_t callback);
118 | void setLinkDownCallback(linkDownCallback_t callback);
119 | void setLinkUpCallback(linkUpCallback_t callback);
120 | bool isLinkUp() const;
121 | void checkLinkDown();
122 | void setLinkUp();
123 |
124 | #if CRSF_TELEMETRY_ENABLED > 0
125 | void telemetryWriteAttitude(int16_t roll, int16_t pitch, int16_t yaw);
126 | void telemetryWriteBaroAltitude(uint16_t altitude, int16_t vario);
127 | void telemetryWriteBattery(float voltage, float current, uint32_t fuel, uint8_t percent);
128 | void telemetryWriteFlightMode(flightModeId_t flightMode, bool disarmed = false);
129 | void telemetryWriteCustomFlightMode(const char *flightMode, bool armed = true);
130 | void telemetryWriteGPS(float latitude, float longitude, float altitude, float speed, float groundCourse, uint8_t satellites);
131 | #endif
132 |
133 | private:
134 | CRSF *crsf = nullptr;
135 | HardwareSerial *_uart;
136 |
137 | int8_t _rxPin = -1;
138 | int8_t _txPin = -1;
139 | bool _linkIsUp;
140 | uint32_t _lastChannelsPacket;
141 |
142 | #if CRSF_TELEMETRY_ENABLED > 0
143 | Telemetry *telemetry = nullptr;
144 | #endif
145 |
146 | #if CRSF_RC_ENABLED > 0
147 | rcChannels_t *_rcChannels = nullptr;
148 | rcChannelsCallback_t _rcChannelsCallback = nullptr;
149 | #endif
150 |
151 | #if CRSF_TELEMETRY_ENABLED > 0
152 | const char *flightModeStr = "ACRO";
153 | #endif
154 |
155 | #if CRSF_LINK_STATISTICS_ENABLED > 0
156 | link_statistics_t _linkStatistics;
157 | linkStatisticsCallback_t _linkStatisticsCallback = nullptr;
158 | #endif
159 |
160 | #if CRSF_RC_ENABLED > 0 && CRSF_FLIGHTMODES_ENABLED > 0
161 | typedef struct flightMode_s
162 | {
163 | const char *name = nullptr;
164 | uint8_t channel = 0;
165 | uint16_t min = 0;
166 | uint16_t max = 0;
167 | } flightMode_t;
168 |
169 | flightMode_t *_flightModes = nullptr;
170 | flightModeCallback_t _flightModeCallback = nullptr;
171 | #endif
172 |
173 | #if CRSF_RC_ENABLED > 0 || CRSF_TELEMETRY_ENABLED > 0
174 | void flushRemainingFrames();
175 | #endif
176 |
177 | rawDataCallback_t _rawDataCallback = nullptr;
178 | linkUpCallback_t _linkUpCallback = nullptr;
179 | linkDownCallback_t _linkDownCallback = nullptr;
180 | };
181 | } // namespace serialReceiverLayer
182 |
--------------------------------------------------------------------------------
/src/SerialReceiver/Telemetry/Telemetry.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Telemetry.cpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This encodes data into CRSF telemetry frames for transmission to the RC handset.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #include "Telemetry.hpp"
26 | #ifndef ENV_DEFECT_DETECTOR
27 | #include "CFA_Config.hpp"
28 | #endif
29 |
30 | using namespace crsfProtocol;
31 |
32 | namespace serialReceiverLayer
33 | {
34 | #ifndef PI
35 | #define PI 3.1415926535897932384626433832795F
36 | #endif
37 |
38 | #ifndef RAD
39 | #define RAD PI / 180.0F
40 | #endif
41 |
42 | Telemetry::Telemetry() :
43 | SerialBuffer(CRSF_FRAME_SIZE_MAX)
44 | {
45 | _telemetryFrameScheduleCount = 0;
46 | memset(_telemetryFrameSchedule, 0, sizeof(_telemetryFrameSchedule));
47 | memset(&_telemetryData, 0, sizeof(_telemetryData));
48 | }
49 |
50 | Telemetry::~Telemetry()
51 | {
52 | }
53 |
54 | void Telemetry::begin()
55 | {
56 | SerialBuffer::reset();
57 |
58 | uint8_t index = 0;
59 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_ATTITUDE_ENABLED > 0
60 | _telemetryFrameSchedule[index++] = (1 << CRSF_TELEMETRY_FRAME_ATTITUDE_INDEX);
61 | #endif
62 |
63 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_BAROALTITUDE_ENABLED > 0
64 | _telemetryFrameSchedule[index++] = (1 << CRSF_TELEMETRY_FRAME_BARO_ALTITUDE_INDEX);
65 | #endif
66 |
67 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_BATTERY_ENABLED > 0
68 | _telemetryFrameSchedule[index++] = (1 << CRSF_TELEMETRY_FRAME_BATTERY_SENSOR_INDEX);
69 | #endif
70 |
71 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_FLIGHTMODE_ENABLED > 0
72 | _telemetryFrameSchedule[index++] = (1 << CRSF_TELEMETRY_FRAME_FLIGHT_MODE_INDEX);
73 | #endif
74 |
75 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_GPS_ENABLED > 0
76 | _telemetryFrameSchedule[index++] = (1 << CRSF_TELEMETRY_FRAME_GPS_INDEX);
77 | #endif
78 |
79 | _telemetryFrameScheduleCount = index;
80 | }
81 |
82 | void Telemetry::end()
83 | {
84 | SerialBuffer::reset();
85 | }
86 |
87 | bool Telemetry::update()
88 | {
89 | #if CRSF_TELEMETRY_ENABLED > 0
90 | bool sendFrame = false;
91 |
92 | static uint8_t scheduleIndex = 0;
93 | const uint8_t currentSchedule = _telemetryFrameSchedule[scheduleIndex];
94 |
95 | #if CRSF_TELEMETRY_ATTITUDE_ENABLED > 0
96 | if (currentSchedule & (1 << CRSF_TELEMETRY_FRAME_ATTITUDE_INDEX))
97 | {
98 | _initialiseFrame();
99 | _appendAttitudeData();
100 | _finaliseFrame();
101 | sendFrame = true;
102 | }
103 | #endif
104 |
105 | #if CRSF_TELEMETRY_BAROALTITUDE_ENABLED > 0
106 | if (currentSchedule & (1 << CRSF_TELEMETRY_FRAME_BARO_ALTITUDE_INDEX))
107 | {
108 | _initialiseFrame();
109 | _appendBaroAltitudeData();
110 | _finaliseFrame();
111 | sendFrame = true;
112 | }
113 | #endif
114 |
115 | #if CRSF_TELEMETRY_BATTERY_ENABLED > 0
116 | if (currentSchedule & (1 << CRSF_TELEMETRY_FRAME_BATTERY_SENSOR_INDEX))
117 | {
118 | _initialiseFrame();
119 | _appendBatterySensorData();
120 | _finaliseFrame();
121 | sendFrame = true;
122 | }
123 | #endif
124 |
125 | #if CRSF_TELEMETRY_FLIGHTMODE_ENABLED > 0
126 | if (currentSchedule & (1 << CRSF_TELEMETRY_FRAME_FLIGHT_MODE_INDEX))
127 | {
128 | _initialiseFrame();
129 | _appendFlightModeData();
130 | _finaliseFrame();
131 | sendFrame = true;
132 | }
133 | #endif
134 |
135 | #if CRSF_TELEMETRY_GPS_ENABLED > 0
136 | if (currentSchedule & (1 << CRSF_TELEMETRY_FRAME_GPS_INDEX))
137 | {
138 | _initialiseFrame();
139 | _appendGPSData();
140 | _finaliseFrame();
141 | sendFrame = true;
142 | }
143 | #endif
144 |
145 | scheduleIndex = (scheduleIndex + 1) % _telemetryFrameScheduleCount;
146 |
147 | return sendFrame;
148 | #else
149 | return false;
150 | #endif
151 | }
152 |
153 | void Telemetry::setAttitudeData(int16_t roll, int16_t pitch, int16_t yaw)
154 | {
155 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_ATTITUDE_ENABLED > 0
156 | _telemetryData.attitude.roll = _decidegreeToRadians(roll);
157 | _telemetryData.attitude.pitch = -_decidegreeToRadians(pitch);
158 | _telemetryData.attitude.yaw = _decidegreeToRadians(yaw);
159 | #else
160 | (void)roll;
161 | (void)pitch;
162 | (void)yaw;
163 | #endif
164 | }
165 |
166 | void Telemetry::setBaroAltitudeData(uint16_t altitude, int16_t vario)
167 | {
168 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_BAROALTITUDE_ENABLED > 0
169 | _telemetryData.baroAltitude.altitude = altitude + 10000;
170 | _telemetryData.baroAltitude.vario = vario;
171 | #else
172 | (void)altitude;
173 | (void)vario;
174 | #endif
175 | }
176 |
177 | void Telemetry::setBatteryData(float voltage, float current, uint32_t capacity, uint8_t percent)
178 | {
179 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_BATTERY_ENABLED > 0
180 | _telemetryData.battery.voltage = (voltage + 5) / 10;
181 | _telemetryData.battery.current = current / 10;
182 | _telemetryData.battery.capacity = capacity;
183 | _telemetryData.battery.percent = percent;
184 | #else
185 | (void)voltage;
186 | (void)current;
187 | (void)capacity;
188 | (void)percent;
189 | #endif
190 | }
191 |
192 | void Telemetry::setFlightModeData(const char *flightMode, bool armed)
193 | {
194 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_FLIGHTMODE_ENABLED > 0
195 | size_t length = strlen(flightMode);
196 | memset(_telemetryData.flightMode.flightMode, 0, sizeof(_telemetryData.flightMode.flightMode));
197 | memcpy(_telemetryData.flightMode.flightMode, flightMode, length);
198 |
199 | if (armed)
200 | {
201 | strcat(_telemetryData.flightMode.flightMode, "*");
202 | }
203 | #else
204 | (void)flightMode;
205 | (void)armed;
206 | #endif
207 | }
208 |
209 | void Telemetry::setGPSData(float latitude, float longitude, float altitude, float speed, float course, uint8_t satellites)
210 | {
211 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_GPS_ENABLED > 0
212 | _telemetryData.gps.latitude = latitude * 10000000;
213 | _telemetryData.gps.longitude = longitude * 10000000;
214 | _telemetryData.gps.altitude = (constrain(altitude, 0, 5000 * 100) / 100) + 1000;
215 | _telemetryData.gps.speed = ((speed * 36 + 50) / 100);
216 | _telemetryData.gps.groundCourse = (course * 100);
217 | _telemetryData.gps.satellites = satellites;
218 | #else
219 | (void)latitude;
220 | (void)longitude;
221 | (void)altitude;
222 | (void)speed;
223 | (void)course;
224 | (void)satellites;
225 | #endif
226 | }
227 |
228 | void Telemetry::sendTelemetryData(HardwareSerial *db)
229 | {
230 | uint8_t *buffer = SerialBuffer::getBuffer();
231 | size_t length = SerialBuffer::getLength();
232 |
233 | db->write(buffer, length);
234 | }
235 |
236 | int16_t Telemetry::_decidegreeToRadians(int16_t decidegrees)
237 | {
238 | while (decidegrees > 18000)
239 | {
240 | decidegrees -= 36000;
241 | }
242 | while (decidegrees < -18000)
243 | {
244 | decidegrees += 36000;
245 | }
246 | return (int16_t)(RAD * 1000.0F * decidegrees);
247 | }
248 |
249 | void Telemetry::_initialiseFrame()
250 | {
251 | SerialBuffer::reset();
252 | SerialBuffer::writeU8(CRSF_SYNC_BYTE);
253 | }
254 |
255 | void Telemetry::_appendAttitudeData()
256 | {
257 | SerialBuffer::writeU8(CRSF_FRAME_ATTITUDE_PAYLOAD_SIZE + CRSF_FRAME_LENGTH_TYPE_CRC);
258 | SerialBuffer::writeU8(CRSF_FRAMETYPE_ATTITUDE);
259 |
260 | SerialBuffer::writeU16BE(_telemetryData.attitude.pitch);
261 | SerialBuffer::writeU16BE(_telemetryData.attitude.roll);
262 | SerialBuffer::writeU16BE(_telemetryData.attitude.yaw);
263 | }
264 |
265 | void Telemetry::_appendBaroAltitudeData()
266 | {
267 | SerialBuffer::writeU8(CRSF_FRAME_BARO_ALTITUDE_PAYLOAD_SIZE + CRSF_FRAME_LENGTH_TYPE_CRC);
268 | SerialBuffer::writeU8(CRSF_FRAMETYPE_BARO_ALTITUDE);
269 |
270 | SerialBuffer::writeU16BE(_telemetryData.baroAltitude.altitude);
271 | SerialBuffer::writeU16BE(_telemetryData.baroAltitude.vario);
272 | }
273 |
274 | void Telemetry::_appendBatterySensorData()
275 | {
276 | SerialBuffer::writeU8(CRSF_FRAME_BATTERY_SENSOR_PAYLOAD_SIZE + CRSF_FRAME_LENGTH_TYPE_CRC);
277 | SerialBuffer::writeU8(CRSF_FRAMETYPE_BATTERY_SENSOR);
278 |
279 | SerialBuffer::writeU16BE(_telemetryData.battery.voltage);
280 | SerialBuffer::writeU16BE(_telemetryData.battery.current);
281 | SerialBuffer::writeU24BE(_telemetryData.battery.capacity);
282 | SerialBuffer::writeU8(_telemetryData.battery.percent);
283 | }
284 |
285 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_FLIGHTMODE_ENABLED > 0
286 | void Telemetry::_appendFlightModeData()
287 | {
288 | size_t length = strlen(_telemetryData.flightMode.flightMode) + 1;
289 | if (length > CRSF_FRAME_FLIGHT_MODE_PAYLOAD_SIZE)
290 | {
291 | return;
292 | }
293 |
294 | SerialBuffer::writeU8(length + CRSF_FRAME_LENGTH_TYPE_CRC);
295 | SerialBuffer::writeU8(CRSF_FRAMETYPE_FLIGHT_MODE);
296 |
297 | SerialBuffer::writeString(_telemetryData.flightMode.flightMode);
298 |
299 | SerialBuffer::writeU8('\0');
300 | }
301 | #endif
302 |
303 | void Telemetry::_appendGPSData()
304 | {
305 | SerialBuffer::writeU8(CRSF_FRAME_GPS_PAYLOAD_SIZE + CRSF_FRAME_LENGTH_TYPE_CRC);
306 | SerialBuffer::writeU8(CRSF_FRAMETYPE_GPS);
307 |
308 | SerialBuffer::write32BE(_telemetryData.gps.latitude);
309 | SerialBuffer::write32BE(_telemetryData.gps.longitude);
310 | SerialBuffer::writeU16BE(_telemetryData.gps.speed);
311 | SerialBuffer::writeU16BE(_telemetryData.gps.groundCourse);
312 | SerialBuffer::writeU16BE(_telemetryData.gps.altitude);
313 | SerialBuffer::writeU8(_telemetryData.gps.satellites);
314 | }
315 |
316 | void Telemetry::_finaliseFrame()
317 | {
318 | uint8_t *buffer = SerialBuffer::getBuffer();
319 | uint8_t length = SerialBuffer::getLength();
320 | uint8_t crc = GenericCRC::calculate(2, buffer[2], buffer, length);
321 |
322 | SerialBuffer::writeU8(crc);
323 | }
324 | } // namespace serialReceiverLayer
325 |
--------------------------------------------------------------------------------
/src/SerialReceiver/Telemetry/Telemetry.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Telemetry.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief This encodes data into CRSF telemetry frames for transmission to the RC handset.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #pragma once
26 |
27 | #include "Arduino.h"
28 |
29 | #include "../CRC/CRC.hpp"
30 | #include "../CRSF/CRSFProtocol.hpp"
31 | #include "../SerialBuffer/SerialBuffer.hpp"
32 |
33 | namespace serialReceiverLayer
34 | {
35 | class Telemetry : private genericCrc::GenericCRC, private genericStreamBuffer::SerialBuffer
36 | {
37 | public:
38 | Telemetry();
39 | ~Telemetry();
40 |
41 | void begin();
42 | void end();
43 |
44 | bool update();
45 |
46 | void setAttitudeData(int16_t roll, int16_t pitch, int16_t yaw);
47 | void setBaroAltitudeData(uint16_t altitude, int16_t vario);
48 | void setBatteryData(float voltage, float current, uint32_t capacity, uint8_t percent);
49 | void setFlightModeData(const char *flightMode, bool armed = false);
50 | void setGPSData(float latitude, float longitude, float altitude, float speed, float course, uint8_t satellites);
51 |
52 | void sendTelemetryData(HardwareSerial *db);
53 |
54 | private:
55 | uint8_t _telemetryFrameScheduleCount;
56 | uint8_t _telemetryFrameSchedule[crsfProtocol::CRSF_TELEMETRY_FRAME_SCHEDULE_MAX];
57 | crsfProtocol::telemetryData_t _telemetryData;
58 |
59 | int16_t _decidegreeToRadians(int16_t decidegrees);
60 |
61 | void _initialiseFrame();
62 | void _appendAttitudeData();
63 | void _appendBaroAltitudeData();
64 | void _appendBatterySensorData();
65 | #if CRSF_TELEMETRY_ENABLED > 0 && CRSF_TELEMETRY_FLIGHTMODE_ENABLED > 0
66 | void _appendFlightModeData();
67 | #endif
68 | void _appendGPSData();
69 | void _finaliseFrame();
70 | };
71 | } // namespace serialReceiverLayer
72 |
--------------------------------------------------------------------------------
/src/build/scripts/build.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | import sys
3 |
4 | if __name__ == "__main__":
5 | # Run the defect detector to check for any issues in the code.
6 | command = "pio check -e defect_detector --fail-on-defect=low --fail-on-defect=medium --fail-on-defect=high"
7 | try:
8 | subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
9 | except subprocess.CalledProcessError as e:
10 | print(f"{e.stdout.strip()}")
11 | print(f"{e.stderr.strip()}")
12 | print("There were issues detected in the code-base. Please resolve them before proceeding.")
13 | exit(1)
14 |
15 | # Get the command line arguments.
16 | args = sys.argv[1:]
17 | # If --deploy was specified as a command line argument, deploy the code to the device.
18 | if "--deploy" in args:
19 | # Run the PlatformIO upload command.
20 | command = "pio run -e development -t upload"
21 | try:
22 | subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
23 | except subprocess.CalledProcessError as e:
24 | print(f"{e.stdout.strip()}")
25 | print(f"{e.stderr.strip()}")
26 | print("Deployment failed. Please resolve the issues before proceeding.")
27 | exit(1)
28 |
29 | # If --deploy-and-monitor was specified as a command line argument,
30 | # deploy the code to the device, wait for it to finish, and then start the serial monitor.
31 | elif "--deploy-and-monitor" in args:
32 | # Run the PlatformIO upload command.
33 | command = "pio run -e development -t upload"
34 | try:
35 | subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
36 | except subprocess.CalledProcessError as e:
37 | print(f"{e.stdout.strip()}")
38 | print(f"{e.stderr.strip()}")
39 | print("Deployment failed. Please resolve the issues before proceeding.")
40 | exit(1)
41 | # Start the serial monitor.
42 | command = "pio device monitor"
43 | try:
44 | subprocess.run(command, shell=True, check=True, text=True)
45 | except subprocess.CalledProcessError as e:
46 | print(f"{e.stdout.strip()}")
47 | print(f"{e.stderr.strip()}")
48 | print("Failed to start the serial monitor. Please resolve the issues before proceeding.")
49 | exit(1)
50 |
51 | # Check compatibility across verified devices.
52 | # TO-DO:
53 | # - Conduct static analysis across verified devices.
54 | # - May need to update platformio.ini and the other targets files for this.
55 | # - For now, this just works.
56 | elif "--build-on-compatible-devices" in args:
57 | # No arguments provided—defaults to building across commonly used devices.
58 | # Because these are the ones that are tested and verified It Just Works.
59 | command = "pio run"
60 | try:
61 | subprocess.run(command, shell=True, check=True, capture_output=True)
62 | except subprocess.CalledProcessError as e:
63 | print(f"{e.stdout.strip()}")
64 | print(f"{e.stderr.strip()}")
65 | print("Build failed. One or more devices are not compatible.")
66 | exit(1)
67 |
68 | # If no arguments were specified, run the build command.
69 | else:
70 | # Run the PlatformIO build command.
71 | command = "pio run -e development"
72 | try:
73 | subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
74 | except subprocess.CalledProcessError as e:
75 | print(f"{e.stdout.strip()}")
76 | print(f"{e.stderr.strip()}")
77 | print("Build failed. Please resolve the issues before proceeding.")
78 | exit(1)
79 |
80 | # Exit with code 0 if everything is fine.
81 | exit(0)
82 |
--------------------------------------------------------------------------------
/src/build/scripts/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [platformio]
12 | core_dir = ../../../.pio/core
13 | workspace_dir = ../../../.pio
14 | default_envs =
15 | ; defect_detector
16 | ; development
17 | ${build.commonly_used}
18 | extra_configs =
19 | ../../../src/build/targets/common.ini
20 | ../../../src/build/targets/quality_control.ini
21 | ../../../src/build/targets/unified_esp32.ini
22 | ../../../src/build/targets/unified_rp2040.ini
23 | ../../../src/build/targets/unified_samd21.ini
24 | ../../../src/build/targets/unified_samd51.ini
25 | ../../../src/build/targets/unified_stm32.ini
26 | ../../../src/build/targets/unified_teensy3x.ini
27 | ../../../src/build/targets/unified_teensy4x.ini
28 | include_dir = ../../../src
29 | lib_dir = ../../../src
30 | src_dir = ../../../src
31 | test_dir =
32 |
33 | [env:development]
34 | board = adafruit_metro_m4
35 | build_src_filter =
36 | +<../examples/platformio/main.cpp>
37 | +
38 | +
39 | +
40 | +
41 | +
42 | +
43 | +
44 | build_type = debug
45 | extends = env_common_samd51
46 |
--------------------------------------------------------------------------------
/src/build/targets/common.ini:
--------------------------------------------------------------------------------
1 | [optimise_level]
2 | tiny = -Oz
3 | default = -Os
4 | debug = -Og
5 | fast = -O2
6 | faster = -O3
7 | fastest = -Ofast
8 | here_be_dragons = -Ofast -funroll-loops
9 |
10 | [common]
11 | build_flags =
12 | -DCRC_OPTIMISATION_LEVEL=0
13 | ${optimise_level.fastest}
14 |
15 | [env_common_esp32]
16 | platform = espressif32@6.4.0
17 |
18 | [env_common_rp2040]
19 | platform = https://github.com/maxgerhardt/platform-raspberrypi.git
20 | board_build.core = earlephilhower
21 | board_build.filesystem_size = 0.5m
22 | platform_packages =
23 | maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#master
24 |
25 | [env_common_samd21]
26 | platform = atmelsam@8.2.0
27 |
28 | [env_common_samd51]
29 | platform = atmelsam@8.2.0
30 |
31 | [env_common_stm32]
32 | platform = ststm32@17.2.0
33 |
34 | [env_common_teensy]
35 | platform = teensy@4.18.0
36 |
37 | [env]
38 | framework = arduino
39 | build_src_filter =
40 | +<../examples/platformio/main.cpp>
41 | +
42 | +
43 | +
44 | +
45 | +
46 | +
47 | +
48 | ; -<../examples/platformio/cfa_code_test.cpp>
49 | ; +<../examples/platformio/main.cpp>
50 | ; +<*/*/*.cpp>
51 | ; +<*.cpp>
52 | build_unflags =
53 | -Os
54 | build_flags =
55 | ${common.build_flags}
56 |
--------------------------------------------------------------------------------
/src/build/targets/quality_control.ini:
--------------------------------------------------------------------------------
1 | [env:defect_detector]
2 | board = adafruit_metro_m4
3 | build_flags =
4 | ; An isolated configuration from CFA_Config.hpp is used here to test EVERY possible
5 | ; configuration, and ensure that defects (if any) are picked up.
6 | ; The `ENV_DEFECT_DETECTOR` define configures CRSF for Arduino for use with the Defect Detector.
7 | -DENV_DEFECT_DETECTOR
8 |
9 | -DCRSF_FAILSAFE_LQI_THRESHOLD=80
10 | -DCRSF_FAILSAFE_RSSI_THRESHOLD=105
11 |
12 | -DCRSF_RC_ENABLED=1
13 | -DCRSF_RC_MAX_CHANNELS=16
14 | -DCRSF_RC_CHANNEL_MIN=172
15 | -DCRSF_RC_CHANNEL_MAX=1811
16 | -DCRSF_RC_CHANNEL_CENTER=992
17 | -DCRSF_RC_INITIALISE_CHANNELS=1
18 | -DCRSF_RC_INITIALISE_ARMCHANNEL=1
19 | -DCRSF_RC_INITIALISE_THROTTLECHANNEL=1
20 |
21 | -DCRSF_FLIGHTMODES_ENABLED=1
22 | -DCRSF_CUSTOM_FLIGHT_MODES_ENABLED=1
23 |
24 | -DCRSF_TELEMETRY_ENABLED=1
25 | -DCRSF_TELEMETRY_ATTITUDE_ENABLED=1
26 | -DCRSF_TELEMETRY_BAROALTITUDE_ENABLED=1
27 | -DCRSF_TELEMETRY_BATTERY_ENABLED=1
28 | -DCRSF_TELEMETRY_FLIGHTMODE_ENABLED=1
29 | -DCRSF_TELEMETRY_GPS_ENABLED=1
30 |
31 | -DCRSF_LINK_STATISTICS_ENABLED=1
32 |
33 | build_src_filter =
34 | +<../examples/platformio/main.cpp>
35 | +
36 | +
37 | +
38 | +
39 | +
40 | +
41 | +
42 | ; +<../examples/platformio/main.cpp>
43 | ; +<*/*/*.cpp>
44 | ; +<*.cpp>
45 | build_type = debug
46 | check_flags =
47 | --disable=unusedFunction
48 | check_severity = low, medium, high
49 | check_skip_packages = yes
50 | check_tool = cppcheck
51 | extends = env_common_samd51
52 |
53 | [build]
54 | ; Intentionally left blank to allow PlatformIO to process _all_ targets CRSF for Arduino is compatible with.
55 | all =
56 |
57 | ; Build check will be restricted to commonly used targets, if this is selected in platformio.ini.
58 | commonly_used =
59 | adafruit_feather_m0
60 | adafruit_feather_m4
61 | adafruit_feather_m4_can
62 | adafruit_metro_m4
63 | adafruit_qtpy_esp32
64 | adafruit_qtpy_esp32c3
65 | adafruit_qtpy_esp32s2
66 | adafruit_qtpy_esp32s3_nopsram
67 | arduino_nano_rp2040_connect
68 | seeed_xiao_esp32c3
69 | seeed_xiao_esp32s3
70 | stm32f103cb
71 | stm32f405rg
72 | stm32f411re
73 | stm32h750vb
74 | teensy_41
75 |
--------------------------------------------------------------------------------
/src/build/targets/unified_esp32.ini:
--------------------------------------------------------------------------------
1 | [env:adafruit_qtpy_esp32]
2 | extends = env_common_esp32
3 | board = adafruit_qtpy_esp32
4 |
5 | [env:adafruit_qtpy_esp32c3]
6 | extends = env_common_esp32
7 | board = adafruit_qtpy_esp32c3
8 |
9 | [env:adafruit_qtpy_esp32s2]
10 | extends = env_common_esp32
11 | board = adafruit_qtpy_esp32s2
12 |
13 | [env:adafruit_qtpy_esp32s3_nopsram]
14 | extends = env_common_esp32
15 | board = adafruit_qtpy_esp32s3_nopsram
16 |
17 | [env:adafruit_feather_esp32s3]
18 | extends = env_common_esp32
19 | board = adafruit_feather_esp32s3
20 |
21 | [env:adafruit_feather_esp32s3_nopsram]
22 | extends = env_common_esp32
23 | board = adafruit_feather_esp32s3_nopsram
24 |
25 | [env:adafruit_itsybitsy_esp32]
26 | extends = env_common_esp32
27 | board = adafruit_itsybitsy_esp32
28 |
29 | [env:adafruit_metro_esp32s2]
30 | extends = env_common_esp32
31 | board = adafruit_metro_esp32s2
32 |
33 | [env:adafruit_feather_esp32]
34 | extends = env_common_esp32
35 | board = featheresp32
36 |
37 | [env:adafruit_feather_esp32-s2]
38 | extends = env_common_esp32
39 | board = featheresp32-s2
40 |
41 | [env:arduino_nano_esp32]
42 | extends = env_common_esp32
43 | board = arduino_nano_esp32
44 |
45 | [env:esp32-c3-devkit-02]
46 | extends = env_common_esp32
47 | board = esp32-c3-devkitc-02
48 |
49 | [env:esp32-c3-devkitm-1]
50 | extends = env_common_esp32
51 | board = esp32-c3-devkitm-1
52 |
53 | [env:esp32-s3-devkitc-1]
54 | extends = env_common_esp32
55 | board = esp32-s3-devkitc-1
56 |
57 | [env:seeed_xiao_esp32c3]
58 | extends = env_common_esp32
59 | board = seeed_xiao_esp32c3
60 |
61 | [env:seeed_xiao_esp32s3]
62 | extends = env_common_esp32
63 | board = seeed_xiao_esp32s3
64 |
65 | [env:sparkfun_esp32_thing]
66 | extends = env_common_esp32
67 | board = esp32thing
68 |
69 | [env:sparkfun_esp32_thing_plus]
70 | extends = env_common_esp32
71 | board = esp32thing_plus
72 |
73 | [env:sparkfun_esp32_iot_redboard]
74 | extends = env_common_esp32
75 | board = sparkfun_esp32_iot_redboard
76 |
77 | [env:sparkfun_esp32s2_thing_plus]
78 | extends = env_common_esp32
79 | board = sparkfun_esp32s2_thing_plus
80 |
--------------------------------------------------------------------------------
/src/build/targets/unified_rp2040.ini:
--------------------------------------------------------------------------------
1 | [env:arduino_nano_rp2040_connect]
2 | extends = env_common_rp2040
3 | board = arduino_nano_connect
4 |
5 | [env:raspberrypi_pico_rp2040]
6 | extends = env_common_rp2040
7 | board = rpipico
8 |
--------------------------------------------------------------------------------
/src/build/targets/unified_samd21.ini:
--------------------------------------------------------------------------------
1 | [env:adafruit_feather_m0]
2 | extends = env_common_samd21
3 | board = adafruit_feather_m0
4 |
5 | [env:adafruit_feather_m0_express]
6 | extends = env_common_samd21
7 | board = adafruit_feather_m0_express
8 |
9 | [env:adafruit_itsybitsy_m0]
10 | extends = env_common_samd21
11 | board = adafruit_itsybitsy_m0
12 |
13 | [env:adafruit_metro_m0]
14 | extends = env_common_samd21
15 | board = adafruit_metro_m0
16 |
17 | [env:arduino_mkrwan1310]
18 | extends = env_common_samd21
19 | board = mkrwan1310
20 |
21 | [env:arduino_mkrwifi1010]
22 | extends = env_common_samd21
23 | board = mkrwifi1010
24 |
25 | [env:arduino_mkrzero]
26 | extends = env_common_samd21
27 | board = mkrzero
28 |
29 | [env:arduino_nano_33_iot]
30 | extends = env_common_samd21
31 | board = nano_33_iot
32 |
33 | [env:arduino_zero]
34 | extends = env_common_samd21
35 | board = zero
36 |
37 | [env:arduino_zeroUSB]
38 | extends = env_common_samd21
39 | board = zeroUSB
40 |
41 | [env:seeed_xiao_samd21]
42 | extends = env_common_samd21
43 | board = seeed_xiao
44 |
--------------------------------------------------------------------------------
/src/build/targets/unified_samd51.ini:
--------------------------------------------------------------------------------
1 | [env:adafruit_feather_m4]
2 | extends = env_common_samd51
3 | board = adafruit_feather_m4
4 |
5 | [env:adafruit_feather_m4_can]
6 | extends = env_common_samd51
7 | board = adafruit_feather_m4_can
8 |
9 | [env:adafruit_grandcentral_m4]
10 | extends = env_common_samd51
11 | board = adafruit_grandcentral_m4
12 |
13 | [env:adafruit_itsybitsy_m4]
14 | extends = env_common_samd51
15 | board = adafruit_itsybitsy_m4
16 |
17 | [env:adafruit_metro_m4]
18 | extends = env_common_samd51
19 | board = adafruit_metro_m4
20 |
21 | [env:adafruit_metro_m4_airliftlite]
22 | extends = env_common_samd51
23 | board = adafruit_metro_m4_airliftlite
24 |
--------------------------------------------------------------------------------
/src/build/targets/unified_stm32.ini:
--------------------------------------------------------------------------------
1 | [env:adafruit_feather_f405]
2 | extends = env_common_stm32
3 | board = adafruit_feather_f405
4 |
5 | [env:arduino_nicla_vision]
6 | extends = env_common_stm32
7 | board = nicla_vision
8 |
9 | [env:arduino_nicla_vision_m4_core]
10 | extends = env_common_stm32
11 | board = nicla_vision_m4
12 |
13 | [env:arduino_opta]
14 | extends = env_common_stm32
15 | board = opta
16 |
17 | [env:arduino_nicla_opta_m4_core]
18 | extends = env_common_stm32
19 | board = opta_m4
20 |
21 | [env:arduino_portenta_m4_core]
22 | extends = env_common_stm32
23 | board = portenta_h7_m4
24 |
25 | [env:arduino_portenta_m7_core]
26 | extends = env_common_stm32
27 | board = portenta_h7_m7
28 |
29 | [env:blackpill_stm32f103c8]
30 | extends = env_common_stm32
31 | board = blackpill_f103c8
32 |
33 | [env:blackpill_stm32f103c8_128]
34 | extends = env_common_stm32
35 | board = blackpill_f103c8_128
36 |
37 | [env:blackpill_stm32f401cc]
38 | extends = env_common_stm32
39 | board = blackpill_f401cc
40 |
41 | [env:blackpill_stm32f401ce]
42 | extends = env_common_stm32
43 | board = blackpill_f401ce
44 |
45 | [env:blackpill_stm32f411ce]
46 | extends = env_common_stm32
47 | board = blackpill_f411ce
48 |
49 | [env:bluepill_stm32f103c6]
50 | extends = env_common_stm32
51 | board = bluepill_f103c6
52 |
53 | [env:bluepill_stm32f103c8]
54 | extends = env_common_stm32
55 | board = bluepill_f103c8
56 |
57 | [env:bluepill_stm32f103c8_128]
58 | extends = env_common_stm32
59 | board = bluepill_f103c8_128k
60 |
61 | [env:st_black_stm32f407ve]
62 | extends = env_common_stm32
63 | board = black_f407ve
64 |
65 | [env:st_black_stm32f407vg]
66 | extends = env_common_stm32
67 | board = black_f407vg
68 |
69 | [env:st_black_stm32f407ze]
70 | extends = env_common_stm32
71 | board = black_f407ze
72 |
73 | [env:st_black_stm32f407zg]
74 | extends = env_common_stm32
75 | board = black_f407zg
76 |
77 | [env:st_blue_stm32f407ve_mini]
78 | extends = env_common_stm32
79 | board = blue_f407ve_mini
80 |
81 | [env:st_discovery_f413]
82 | extends = env_common_stm32
83 | board = disco_f413zh
84 |
85 | [env:st_discovery_f746]
86 | extends = env_common_stm32
87 | board = disco_f746ng
88 |
89 | [env:st_nucleo_f401re]
90 | extends = env_common_stm32
91 | board = nucleo_f401re
92 |
93 | [env:st_nucleo_f411re]
94 | extends = env_common_stm32
95 | board = nucleo_f411re
96 |
97 | [env:st_nucleo_f429zi]
98 | extends = env_common_stm32
99 | board = nucleo_f429zi
100 |
101 | [env:st_nucleo_f446re]
102 | extends = env_common_stm32
103 | board = nucleo_f446re
104 |
105 | [env:st_nucleo_f722ze]
106 | extends = env_common_stm32
107 | board = nucleo_f722ze
108 |
109 | [env:st_nucleo_f746zg]
110 | extends = env_common_stm32
111 | board = nucleo_f746zg
112 |
113 | [env:st_nucleo_f756zg]
114 | extends = env_common_stm32
115 | board = nucleo_f756zg
116 |
117 | [env:st_nucleo_f767zi]
118 | extends = env_common_stm32
119 | board = nucleo_f767zi
120 |
121 | [env:st_nucleo_h723zg]
122 | extends = env_common_stm32
123 | board = nucleo_h723zg
124 |
125 | [env:st_nucleo_h743zi]
126 | extends = env_common_stm32
127 | board = nucleo_h743zi
128 |
129 | [env:stm32f103c6]
130 | extends = env_common_stm32
131 | board = genericSTM32F103C6
132 |
133 | [env:stm32f103c8]
134 | extends = env_common_stm32
135 | board = genericSTM32F103C8
136 |
137 | [env:stm32f103cb]
138 | extends = env_common_stm32
139 | board = genericSTM32F103CB
140 |
141 | [env:stm32f103r6]
142 | extends = env_common_stm32
143 | board = genericSTM32F103R6
144 |
145 | [env:stm32f103r8]
146 | extends = env_common_stm32
147 | board = genericSTM32F103R8
148 |
149 | [env:stm32f103rb]
150 | extends = env_common_stm32
151 | board = genericSTM32F103RB
152 |
153 | [env:stm32f103rc]
154 | extends = env_common_stm32
155 | board = genericSTM32F103RC
156 |
157 | [env:stm32f103rd]
158 | extends = env_common_stm32
159 | board = genericSTM32F103RD
160 |
161 | [env:stm32f103re]
162 | extends = env_common_stm32
163 | board = genericSTM32F103RE
164 |
165 | [env:stm32f103rf]
166 | extends = env_common_stm32
167 | board = genericSTM32F103RF
168 |
169 | [env:stm32f103rg]
170 | extends = env_common_stm32
171 | board = genericSTM32F103RG
172 |
173 | [env:stm32f103t6]
174 | extends = env_common_stm32
175 | board = genericSTM32F103T6
176 |
177 | [env:stm32f103t8]
178 | extends = env_common_stm32
179 | board = genericSTM32F103T8
180 |
181 | [env:stm32f103tb]
182 | extends = env_common_stm32
183 | board = genericSTM32F103TB
184 |
185 | [env:stm32f103v8]
186 | extends = env_common_stm32
187 | board = genericSTM32F103V8
188 |
189 | [env:stm32f103vb]
190 | extends = env_common_stm32
191 | board = genericSTM32F103VB
192 |
193 | [env:stm32f103vc]
194 | extends = env_common_stm32
195 | board = genericSTM32F103VC
196 |
197 | [env:stm32f103vd]
198 | extends = env_common_stm32
199 | board = genericSTM32F103VD
200 |
201 | [env:stm32f103ve]
202 | extends = env_common_stm32
203 | board = genericSTM32F103VE
204 |
205 | [env:stm32f103vf]
206 | extends = env_common_stm32
207 | board = genericSTM32F103VF
208 |
209 | [env:stm32f103vg]
210 | extends = env_common_stm32
211 | board = genericSTM32F103VG
212 |
213 | [env:stm32f103zc]
214 | extends = env_common_stm32
215 | board = genericSTM32F103ZC
216 |
217 | [env:stm32f103zd]
218 | extends = env_common_stm32
219 | board = genericSTM32F103ZD
220 |
221 | [env:stm32f103ze]
222 | extends = env_common_stm32
223 | board = genericSTM32F103ZE
224 |
225 | [env:stm32f103zf]
226 | extends = env_common_stm32
227 | board = genericSTM32F103ZF
228 |
229 | [env:stm32f103zg]
230 | extends = env_common_stm32
231 | board = genericSTM32F103ZG
232 |
233 | [env:stm32f401cb]
234 | extends = env_common_stm32
235 | board = genericSTM32F401CB
236 |
237 | [env:stm32f401cc]
238 | extends = env_common_stm32
239 | board = genericSTM32F401CC
240 |
241 | [env:stm32f401cd]
242 | extends = env_common_stm32
243 | board = genericSTM32F401CD
244 |
245 | [env:stm32f401ce]
246 | extends = env_common_stm32
247 | board = genericSTM32F401CE
248 |
249 | [env:stm32f401rb]
250 | extends = env_common_stm32
251 | board = genericSTM32F401RB
252 |
253 | [env:stm32f401rc]
254 | extends = env_common_stm32
255 | board = genericSTM32F401RC
256 |
257 | [env:stm32f401rd]
258 | extends = env_common_stm32
259 | board = genericSTM32F401RD
260 |
261 | [env:stm32f401re]
262 | extends = env_common_stm32
263 | board = genericSTM32F401RE
264 |
265 | [env:stm32f405rg]
266 | extends = env_common_stm32
267 | board = genericSTM32F405RG
268 |
269 | [env:stm32f407ve]
270 | extends = env_common_stm32
271 | board = genericSTM32F407VET6
272 |
273 | [env:stm32f407vg]
274 | extends = env_common_stm32
275 | board = genericSTM32F407VGT6
276 |
277 | [env:stm32f410c8]
278 | extends = env_common_stm32
279 | board = genericSTM32F410C8
280 |
281 | [env:stm32f410cb]
282 | extends = env_common_stm32
283 | board = genericSTM32F410CB
284 |
285 | [env:stm32f410r8]
286 | extends = env_common_stm32
287 | board = genericSTM32F410R8
288 |
289 | [env:stm32f410rb]
290 | extends = env_common_stm32
291 | board = genericSTM32F410RB
292 |
293 | [env:stm32f411ce]
294 | extends = env_common_stm32
295 | board = genericSTM32F411CE
296 |
297 | [env:stm32f411rc]
298 | extends = env_common_stm32
299 | board = genericSTM32F411RC
300 |
301 | [env:stm32f411re]
302 | extends = env_common_stm32
303 | board = genericSTM32F411RE
304 |
305 | [env:stm32f412ce]
306 | extends = env_common_stm32
307 | board = genericSTM32F412CE
308 |
309 | [env:stm32f412cg]
310 | extends = env_common_stm32
311 | board = genericSTM32F412CG
312 |
313 | [env:stm32f412re]
314 | extends = env_common_stm32
315 | board = genericSTM32F412RE
316 |
317 | [env:stm32f412rg]
318 | extends = env_common_stm32
319 | board = genericSTM32F412RG
320 |
321 | [env:stm32f413cg]
322 | extends = env_common_stm32
323 | board = genericSTM32F413CG
324 |
325 | [env:stm32f413ch]
326 | extends = env_common_stm32
327 | board = genericSTM32F413CH
328 |
329 | [env:stm32f413rg]
330 | extends = env_common_stm32
331 | board = genericSTM32F413RG
332 |
333 | [env:stm32f413rh]
334 | extends = env_common_stm32
335 | board = genericSTM32F413RH
336 |
337 | [env:stm32f415rg]
338 | extends = env_common_stm32
339 | board = genericSTM32F415RG
340 |
341 | [env:stm32f417ve]
342 | extends = env_common_stm32
343 | board = genericSTM32F417VE
344 |
345 | [env:stm32f417vg]
346 | extends = env_common_stm32
347 | board = genericSTM32F417VG
348 |
349 | [env:stm32f423ch]
350 | extends = env_common_stm32
351 | board = genericSTM32F423CH
352 |
353 | [env:stm32f423rh]
354 | extends = env_common_stm32
355 | board = genericSTM32F423RH
356 |
357 | [env:stm32f446rc]
358 | extends = env_common_stm32
359 | board = genericSTM32F446RC
360 |
361 | [env:stm32f446re]
362 | extends = env_common_stm32
363 | board = genericSTM32F446RE
364 |
365 | [env:stm32h750vb]
366 | extends = env_common_stm32
367 | board = genericSTM32H750VB
368 |
369 | [env:sparkfun_micromod_f405]
370 | extends = env_common_stm32
371 | board = sparkfun_micromod_f405
372 |
--------------------------------------------------------------------------------
/src/build/targets/unified_teensy3x.ini:
--------------------------------------------------------------------------------
1 | [env:teensy_30]
2 | extends = env_common_teensy
3 | board = teensy30
4 |
5 | [env:teensy_31]
6 | extends = env_common_teensy
7 | board = teensy31
8 |
9 | [env:teensy_32]
10 | extends = env_common_teensy
11 | board = teensy31
12 |
13 | [env:teensy_35]
14 | extends = env_common_teensy
15 | board = teensy35
16 |
17 | [env:teensy_36]
18 | extends = env_common_teensy
19 | board = teensy36
20 |
--------------------------------------------------------------------------------
/src/build/targets/unified_teensy4x.ini:
--------------------------------------------------------------------------------
1 | [env:teensy_40]
2 | extends = env_common_teensy
3 | board = teensy40
4 |
5 | [env:teensy_41]
6 | extends = env_common_teensy
7 | board = teensy41
8 |
--------------------------------------------------------------------------------
/src/hal/CompatibilityTable/CompatibilityTable.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file CompatibilityTable.hpp
3 | * @author Cassandra "ZZ Cat" Robinson (nicad.heli.flier@gmail.com)
4 | * @brief The Compatibility Table determines if the target development board is compatible with CRSF for Arduino.
5 | *
6 | * @copyright Copyright (c) 2024, Cassandra "ZZ Cat" Robinson. All rights reserved.
7 | *
8 | * @section License GNU Affero General Public License v3.0
9 | * This source file is a part of the CRSF for Arduino library.
10 | * CRSF for Arduino is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * CRSF for Arduino is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with CRSF for Arduino. If not, see .
22 | *
23 | */
24 |
25 | #pragma once
26 |
27 | namespace hal
28 | {
29 | class CompatibilityTable
30 | {
31 | public:
32 | CompatibilityTable();
33 | virtual ~CompatibilityTable();
34 |
35 | bool isDevboardCompatible(const char *name);
36 | const char *getDevboardName();
37 |
38 | private:
39 | typedef enum ct_devboards_e
40 | {
41 | // Incompatible device. Non-permissive.
42 | DEVBOARD_IS_INCOMPATIBLE = 0,
43 |
44 | // Permissive incompatibility:
45 | // - The architecture and chip is known, but the board is not.
46 | // - The architecture is known, but the board and chip are not.
47 | DEVBOARD_IS_PERMISSIVELY_INCOMPATIBLE_UNKNOWN_BOARD,
48 | DEVBOARD_IS_PERMISSIVELY_INCOMPATIBLE_UNKNOWN_BOARD_AND_CHIP,
49 |
50 | // Adafruit ESP32 boards.
51 | DEVBOARD_ADAFRUIT_FEATHER_ESP32,
52 | DEVBOARD_ADAFRUIT_FEATHER_ESP32S2,
53 | DEVBOARD_ADAFRUIT_FEATHER_ESP32S3,
54 | DEVBOARD_ADAFRUIT_FEATHER_ESP32S3_NOPSRAM,
55 | DEVBOARD_ADAFRUIT_ITSYBITSY_ESP32,
56 | DEVBOARD_ADAFRUIT_METRO_ESP32S2,
57 | DEVBOARD_ADAFRUIT_QTPY_ESP32C3,
58 | DEVBOARD_ADAFRUIT_QTPY_ESP32_PICO,
59 | DEVBOARD_ADAFRUIT_QTPY_ESP32S2,
60 | DEVBOARD_ADAFRUIT_QTPY_ESP32S3,
61 |
62 | // Adafruit SAMD21 boards.
63 | DEVBOARD_ADAFRUIT_FEATHER_M0,
64 | DEVBOARD_ADAFRUIT_FEATHER_M0_EXPRESS,
65 | DEVBOARD_ADAFRUIT_ITSYBITSY_M0_EXPRESS,
66 | DEVBOARD_ADAFRUIT_METRO_M0_EXPRESS,
67 | DEVBOARD_ADAFRUIT_QTPY_M0,
68 | DEVBOARD_ADAFRUIT_TRINKET_M0,
69 |
70 | // Adafruit SAMD51 boards.
71 | DEVBOARD_ADAFRUIT_FEATHER_M4_EXPRESS,
72 | DEVBOARD_ADAFRUIT_GRAND_CENTRAL_M4,
73 | DEVBOARD_ADAFRUIT_ITSYBITSY_M4_EXPRESS,
74 | DEVBOARD_ADAFRUIT_METRO_M4_AIRLIFT_LITE,
75 | DEVBOARD_ADAFRUIT_METRO_M4_EXPRESS,
76 |
77 | // Adafruit SAME51 boards.
78 | DEVBOARD_ADAFRUIT_FEATHER_M4_CAN,
79 |
80 | // Arduino ESP32 boards.
81 | DEVBOARD_ARDUINO_NANO_ESP32,
82 |
83 | // Arduino RP2040 boards.
84 | DEVBOARD_ARDUINO_NANO_RP2040_CONNECT,
85 |
86 | // Arduino SAMD21 boards.
87 | DEVBOARD_ARDUINO_MKR1000,
88 | DEVBOARD_ARDUINO_MKRFOX1200,
89 | DEVBOARD_ARDUINO_MKRGSM1400,
90 | DEVBOARD_ARDUINO_MKRNB1500,
91 | DEVBOARD_ARDUINO_MKRVIDOR4000,
92 | DEVBOARD_ARDUINO_MKRWAN1300,
93 | DEVBOARD_ARDUINO_MKRWAN1310,
94 | DEVBOARD_ARDUINO_MKRWIFI1010,
95 | DEVBOARD_ARDUINO_MKRZERO,
96 | DEVBOARD_ARDUINO_NANO_33_IOT,
97 | DEVBOARD_ARDUINO_ZERO,
98 |
99 | // Arduino STM32 boards.
100 | DEVBOARD_ARDUINO_NICLA_VISION,
101 | DEVBOARD_ARDUINO_OPTA,
102 | DEVBOARD_ARDUINO_PORTENTA_H7,
103 | DEVBOARD_ARDUINO_PORTENTA_H7_M4,
104 |
105 | // Espressif ESP32 boards.
106 | DEVBOARD_ESPRESSIF_ESP32C3_DEVKIT,
107 | DEVBOARD_ESPRESSIF_ESP32S3_DEVKIT,
108 |
109 | // Raspberry Pi RP2040 boards.
110 | DEVBOARD_RASPBERRYPI_PICO,
111 |
112 | // Seeed Studio boards.
113 | DEVBOARD_SEEEDSTUDIO_XIAO_ESP32C3,
114 | DEVBOARD_SEEEDSTUDIO_XIAO_ESP32S3,
115 | DEVBOARD_SEEEDSTUDIO_XIAO_M0,
116 |
117 | // SparkFun Boards
118 | DEVBOARD_SPARKFUN_MICROMOD_F405,
119 | DEVBOARD_SPARKFUN_REDBOARD_ESP32_IOT,
120 | DEVBOARD_SPARKFUN_THING_ESP32,
121 | DEVBOARD_SPARKFUN_THING_PLUS_ESP32,
122 | DEVBOARD_SPARKFUN_THING_PLUS_ESP32S2,
123 |
124 | // STM32 boards.
125 | DEVBOARD_ADAFRUIT_FEATHER_F405,
126 | DEVBOARD_ST_BLACK_F407VE,
127 | DEVBOARD_ST_BLACK_F407VG,
128 | DEVBOARD_ST_BLACK_F407ZE,
129 | DEVBOARD_ST_BLACK_F407ZG,
130 | DEVBOARD_ST_BLUE_F407VE_MINI,
131 | DEVBOARD_ST_DISCOVERY_F413ZH,
132 | DEVBOARD_ST_DISCOVERY_F746NG,
133 | DEVBOARD_ST_NUCLEO_F401RE,
134 | DEVBOARD_ST_NUCLEO_F411RE,
135 | DEVBOARD_ST_NUCLEO_F429ZI,
136 | DEVBOARD_ST_NUCLEO_F446RE,
137 | DEVBOARD_ST_NUCLEO_F722ZE,
138 | DEVBOARD_ST_NUCLEO_F746ZG,
139 | DEVBOARD_ST_NUCLEO_F756ZG,
140 | DEVBOARD_ST_NUCLEO_F767ZI,
141 | DEVBOARD_ST_NUCLEO_H723ZG,
142 | DEVBOARD_ST_NUCLEO_H743ZI,
143 | DEVBOARD_STM32_BLACKPILL_STM32F103C8,
144 | DEVBOARD_STM32_BLACKPILL_STM32F401CC,
145 | DEVBOARD_STM32_BLACKPILL_STM32F411CE,
146 | DEVBOARD_STM32_BLUEPILL_STM32F103C6,
147 | DEVBOARD_STM32_BLUEPILL_STM32F103C8,
148 | DEVBOARD_STM32F103C6,
149 | DEVBOARD_STM32F103C8,
150 | DEVBOARD_STM32F103CB,
151 | DEVBOARD_STM32F103R6,
152 | DEVBOARD_STM32F103R8,
153 | DEVBOARD_STM32F103RB,
154 | DEVBOARD_STM32F103RC,
155 | DEVBOARD_STM32F103RD,
156 | DEVBOARD_STM32F103RE,
157 | DEVBOARD_STM32F103RF,
158 | DEVBOARD_STM32F103RG,
159 | DEVBOARD_STM32F103T6,
160 | DEVBOARD_STM32F103T8,
161 | DEVBOARD_STM32F103TB,
162 | DEVBOARD_STM32F103V8,
163 | DEVBOARD_STM32F103VB,
164 | DEVBOARD_STM32F103VC,
165 | DEVBOARD_STM32F103VD,
166 | DEVBOARD_STM32F103VE,
167 | DEVBOARD_STM32F103VF,
168 | DEVBOARD_STM32F103VG,
169 | DEVBOARD_STM32F103ZC,
170 | DEVBOARD_STM32F103ZD,
171 | DEVBOARD_STM32F103ZE,
172 | DEVBOARD_STM32F103ZF,
173 | DEVBOARD_STM32F103ZG,
174 | DEVBOARD_STM32F401CB,
175 | DEVBOARD_STM32F401CC,
176 | DEVBOARD_STM32F401CD,
177 | DEVBOARD_STM32F401CE,
178 | DEVBOARD_STM32F401RB,
179 | DEVBOARD_STM32F401RC,
180 | DEVBOARD_STM32F401RD,
181 | DEVBOARD_STM32F401RE,
182 | DEVBOARD_STM32F405RG,
183 | DEVBOARD_STM32F407VE,
184 | DEVBOARD_STM32F407VG,
185 | DEVBOARD_STM32F410C8,
186 | DEVBOARD_STM32F410CB,
187 | DEVBOARD_STM32F410R8,
188 | DEVBOARD_STM32F410RB,
189 | DEVBOARD_STM32F411CE,
190 | DEVBOARD_STM32F411RC,
191 | DEVBOARD_STM32F411RE,
192 | DEVBOARD_STM32F412CE,
193 | DEVBOARD_STM32F412CG,
194 | DEVBOARD_STM32F412RE,
195 | DEVBOARD_STM32F412RG,
196 | DEVBOARD_STM32F413CG,
197 | DEVBOARD_STM32F413CH,
198 | DEVBOARD_STM32F413RG,
199 | DEVBOARD_STM32F413RH,
200 | DEVBOARD_STM32F415RG,
201 | DEVBOARD_STM32F417VE,
202 | DEVBOARD_STM32F417VG,
203 | DEVBOARD_STM32F423CH,
204 | DEVBOARD_STM32F423RH,
205 | DEVBOARD_STM32F446RC,
206 | DEVBOARD_STM32F446RE,
207 | DEVBOARD_STM32H750BT,
208 |
209 | // STM32duino STM32F405 boards.
210 | DEVBOARD_STM32F405OE,
211 | DEVBOARD_STM32F405OG,
212 | DEVBOARD_STM32F405VG,
213 | DEVBOARD_STM32F405ZG,
214 |
215 | // STM32duino STM32F722 boards.
216 | DEVBOARD_STM32F722IC,
217 | DEVBOARD_STM32F722IE,
218 | DEVBOARD_STM32F722RC,
219 | DEVBOARD_STM32F722RE,
220 | DEVBOARD_STM32F722VC,
221 | DEVBOARD_STM32F722VE,
222 | DEVBOARD_STM32F722ZC,
223 |
224 | // STM32duino STM32H745 boards.
225 | DEVBOARD_STM32H745BG,
226 | DEVBOARD_STM32H745BI,
227 | DEVBOARD_STM32H745IG,
228 | DEVBOARD_STM32H745II,
229 | DEVBOARD_STM32H745ZG,
230 | DEVBOARD_STM32H745ZI,
231 |
232 | // Teensy boards.
233 | DEVBOARD_TEENSY_30,
234 | DEVBOARD_TEENSY_31_32,
235 | DEVBOARD_TEENSY_35,
236 | DEVBOARD_TEENSY_36,
237 | DEVBOARD_TEENSY_40,
238 | DEVBOARD_TEENSY_41,
239 |
240 | DEVBOARD_COUNT
241 | } ct_devboards_t;
242 |
243 | typedef struct ct_devicetypes_s
244 | {
245 | ct_devboards_t devboard;
246 | } ct_devicetypes_t;
247 |
248 | typedef struct ct_devices_s
249 | {
250 | ct_devicetypes_t type;
251 | } ct_devices_t;
252 |
253 | ct_devices_t device;
254 |
255 | const char *deviceNames[DEVBOARD_COUNT] = {
256 | "Incompatible device",
257 | "Permissively incompatible device (unknown board)",
258 | "Permissively incompatible device (unknown board and chip)",
259 | "Adafruit Feather ESP32",
260 | "Adafruit Feather ESP32-S2",
261 | "Adafruit Feather ESP32-S3",
262 | "Adafruit Feather ESP32-S3 (no PSRAM)",
263 | "Adafruit ItsyBitsy ESP32",
264 | "Adafruit Metro ESP32-S2",
265 | "Adafruit QT Py ESP32-C3",
266 | "Adafruit QT Py ESP32 Pico",
267 | "Adafruit QT Py ESP32-S2",
268 | "Adafruit QT Py ESP32-S3",
269 | "Adafruit Feather M0",
270 | "Adafruit Feather M0 Express",
271 | "Adafruit ItsyBitsy M0 Express",
272 | "Adafruit Metro M0 Express",
273 | "Adafruit QT Py M0",
274 | "Adafruit Trinket M0",
275 | "Adafruit Feather M4 Express",
276 | "Adafruit Grand Central M4",
277 | "Adafruit ItsyBitsy M4 Express",
278 | "Adafruit Metro M4 AirLift Lite",
279 | "Adafruit Metro M4 Express",
280 | "Adafruit Feather M4 CAN",
281 | "Arduino Nano ESP32",
282 | "Arduino Nano RP2040 Connect",
283 | "Arduino MKR1000",
284 | "Arduino MKRFOX1200",
285 | "Arduino MKRGSM1400",
286 | "Arduino MKRNB1500",
287 | "Arduino MKRVIDOR4000",
288 | "Arduino MKRWAN1300",
289 | "Arduino MKRWAN1310",
290 | "Arduino MKRWIFI1010",
291 | "Arduino MKRZERO",
292 | "Arduino Nano 33 IoT",
293 | "Arduino Zero",
294 | "Arduino Nicla Vision",
295 | "Arduino Opta",
296 | "Arduino Portenta H7",
297 | "Arduino Portenta H7 (M4 Core)",
298 | "Espressif ESP32-C3 DevKit",
299 | "Espressif ESP32-S3 DevKit",
300 | "Raspberry Pi Pico",
301 | "Seeed Studio Xiao ESP32-C3",
302 | "Seeed Studio Xiao ESP32-S3",
303 | "Seeed Studio Xiao SAMD21",
304 | "SparkFun MicroMod F405",
305 | "SparkFun RedBoard ESP32 IoT",
306 | "SparkFun Thing ESP32",
307 | "SparkFun Thing Plus ESP32",
308 | "SparkFun Thing Plus ESP32-S2",
309 | "Adafruit Feather F405",
310 | "ST Black F407VE",
311 | "ST Black F407VG",
312 | "ST Black F407ZE",
313 | "ST Black F407ZG",
314 | "ST Blue F407VE Mini",
315 | "ST Discovery F413ZH",
316 | "ST Discovery F746NG",
317 | "ST Nucleo F401RE",
318 | "ST Nucleo F411RE",
319 | "ST Nucleo F429ZI",
320 | "ST Nucleo F446RE",
321 | "ST Nucleo F722ZE",
322 | "ST Nucleo F746ZG",
323 | "ST Nucleo F756ZG",
324 | "ST Nucleo F767ZI",
325 | "ST Nucleo H723ZG",
326 | "ST Nucleo H743ZI",
327 | "STM32 BlackPill STM32F103C8",
328 | "STM32 BlackPill STM32F401CC",
329 | "STM32 BlackPill STM32F411CE",
330 | "STM32 BluePill STM32F103C6",
331 | "STM32 BluePill STM32F103C8",
332 | "STM32F103C6",
333 | "STM32F103C8",
334 | "STM32F103CB",
335 | "STM32F103R6",
336 | "STM32F103R8",
337 | "STM32F103RB",
338 | "STM32F103RC",
339 | "STM32F103RD",
340 | "STM32F103RE",
341 | "STM32F103RF",
342 | "STM32F103RG",
343 | "STM32F103T6",
344 | "STM32F103T8",
345 | "STM32F103TB",
346 | "STM32F103V8",
347 | "STM32F103VB",
348 | "STM32F103VC",
349 | "STM32F103VD",
350 | "STM32F103VE",
351 | "STM32F103VF",
352 | "STM32F103VG",
353 | "STM32F103ZC",
354 | "STM32F103ZD",
355 | "STM32F103ZE",
356 | "STM32F103ZF",
357 | "STM32F103ZG",
358 | "STM32F401CB",
359 | "STM32F401CC",
360 | "STM32F401CD",
361 | "STM32F401CE",
362 | "STM32F401RB",
363 | "STM32F401RC",
364 | "STM32F401RD",
365 | "STM32F401RE",
366 | "STM32F405RG",
367 | "STM32F407VE",
368 | "STM32F407VG",
369 | "STM32F410C8",
370 | "STM32F410CB",
371 | "STM32F410R8",
372 | "STM32F410RB",
373 | "STM32F411CE",
374 | "STM32F411RC",
375 | "STM32F411RE",
376 | "STM32F412CE",
377 | "STM32F412CG",
378 | "STM32F412RE",
379 | "STM32F412RG",
380 | "STM32F413CG",
381 | "STM32F413CH",
382 | "STM32F413RG",
383 | "STM32F413RH",
384 | "STM32F415RG",
385 | "STM32F417VE",
386 | "STM32F417VG",
387 | "STM32F423CH",
388 | "STM32F423RH",
389 | "STM32F446RC",
390 | "STM32F446RE",
391 | "STM32H750BT",
392 | "STM32F405OE",
393 | "STM32F405OG",
394 | "STM32F405VG",
395 | "STM32F405ZG",
396 | "STM32F722IC",
397 | "STM32F722IE",
398 | "STM32F722RC",
399 | "STM32F722RE",
400 | "STM32F722VC",
401 | "STM32F722VE",
402 | "STM32F722ZC",
403 | "STM32H745BG",
404 | "STM32H745BI",
405 | "STM32H745IG",
406 | "STM32H745II",
407 | "STM32H745ZG",
408 | "STM32H745ZI",
409 | "Teensy 3.0",
410 | "Teensy 3.1/3.2",
411 | "Teensy 3.5",
412 | "Teensy 3.6",
413 | "Teensy 4.0",
414 | "Teensy 4.1"};
415 | };
416 | } // namespace hal
417 |
--------------------------------------------------------------------------------