2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "build_config.h"
27 #include "common/utils.h"
29 #include "drivers/system.h"
30 #include "drivers/serial.h"
31 #if defined(USE_SOFTSERIAL1) || defined(USE_SOFTSERIAL2)
32 #include "drivers/serial_softserial.h"
35 #if defined(USE_USART1) || defined(USE_USART2) || defined(USE_USART3)
36 #include "drivers/serial_uart.h"
40 #include "drivers/serial_usb_vcp.h"
43 #include "io/serial.h"
44 #include "serial_cli.h"
45 #include "serial_msp.h"
47 #include "config/config.h"
50 #include "telemetry/telemetry.h"
53 static serialConfig_t
*serialConfig
;
54 static serialPortUsage_t serialPortUsageList
[SERIAL_PORT_COUNT
];
56 const serialPortIdentifier_e serialPortIdentifiers
[SERIAL_PORT_COUNT
] = {
69 #ifdef USE_SOFTSERIAL1
70 SERIAL_PORT_SOFTSERIAL1
,
72 #ifdef USE_SOFTSERIAL2
73 SERIAL_PORT_SOFTSERIAL2
,
77 static uint8_t serialPortCount
;
79 const uint32_t baudRates
[] = {0, 9600, 19200, 38400, 57600, 115200, 230400, 250000}; // see baudRate_e
81 #define BAUD_RATE_COUNT (sizeof(baudRates) / sizeof(baudRates[0]))
83 baudRate_e
lookupBaudRateIndex(uint32_t baudRate
)
87 for (index
= 0; index
< BAUD_RATE_COUNT
; index
++) {
88 if (baudRates
[index
] == baudRate
) {
95 static serialPortUsage_t
*findSerialPortUsageByIdentifier(serialPortIdentifier_e identifier
)
98 for (index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
99 serialPortUsage_t
*candidate
= &serialPortUsageList
[index
];
100 if (candidate
->identifier
== identifier
) {
107 serialPortUsage_t
*findSerialPortUsageByPort(serialPort_t
*serialPort
) {
109 for (index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
110 serialPortUsage_t
*candidate
= &serialPortUsageList
[index
];
111 if (candidate
->serialPort
== serialPort
) {
118 typedef struct findSerialPortConfigState_s
{
120 } findSerialPortConfigState_t
;
122 static findSerialPortConfigState_t findSerialPortConfigState
;
124 serialPortConfig_t
*findSerialPortConfig(serialPortFunction_e function
)
126 memset(&findSerialPortConfigState
, 0, sizeof(findSerialPortConfigState
));
128 return findNextSerialPortConfig(function
);
131 serialPortConfig_t
*findNextSerialPortConfig(serialPortFunction_e function
)
133 while (findSerialPortConfigState
.lastIndex
< SERIAL_PORT_COUNT
) {
134 serialPortConfig_t
*candidate
= &serialConfig
->portConfigs
[findSerialPortConfigState
.lastIndex
++];
136 if (candidate
->functionMask
& function
) {
143 typedef struct findSharedSerialPortState_s
{
145 } findSharedSerialPortState_t
;
147 portSharing_e
determinePortSharing(serialPortConfig_t
*portConfig
, serialPortFunction_e function
)
149 if (!portConfig
|| (portConfig
->functionMask
& function
) == 0) {
150 return PORTSHARING_UNUSED
;
152 return portConfig
->functionMask
== function
? PORTSHARING_NOT_SHARED
: PORTSHARING_SHARED
;
155 bool isSerialPortShared(serialPortConfig_t
*portConfig
, uint16_t functionMask
, serialPortFunction_e sharedWithFunction
)
157 return (portConfig
) && (portConfig
->functionMask
& sharedWithFunction
) && (portConfig
->functionMask
& functionMask
);
160 static findSharedSerialPortState_t findSharedSerialPortState
;
162 serialPort_t
*findSharedSerialPort(uint16_t functionMask
, serialPortFunction_e sharedWithFunction
)
164 memset(&findSharedSerialPortState
, 0, sizeof(findSharedSerialPortState
));
166 return findNextSharedSerialPort(functionMask
, sharedWithFunction
);
169 serialPort_t
*findNextSharedSerialPort(uint16_t functionMask
, serialPortFunction_e sharedWithFunction
)
171 while (findSharedSerialPortState
.lastIndex
< SERIAL_PORT_COUNT
) {
172 serialPortConfig_t
*candidate
= &serialConfig
->portConfigs
[findSharedSerialPortState
.lastIndex
++];
174 if (isSerialPortShared(candidate
, functionMask
, sharedWithFunction
)) {
175 serialPortUsage_t
*serialPortUsage
= findSerialPortUsageByIdentifier(candidate
->identifier
);
176 if (!serialPortUsage
) {
179 return serialPortUsage
->serialPort
;
185 #define ALL_TELEMETRY_FUNCTIONS_MASK (FUNCTION_TELEMETRY_FRSKY | FUNCTION_TELEMETRY_HOTT | FUNCTION_TELEMETRY_SMARTPORT | FUNCTION_TELEMETRY_LTM)
186 #define ALL_FUNCTIONS_SHARABLE_WITH_MSP (FUNCTION_BLACKBOX | ALL_TELEMETRY_FUNCTIONS_MASK)
188 bool isSerialConfigValid(serialConfig_t
*serialConfigToCheck
)
190 UNUSED(serialConfigToCheck
);
193 * - 1 MSP port minimum, max MSP ports is defined and must be adhered to.
194 * - Only MSP is allowed to be shared with EITHER any telemetry OR blackbox.
195 * - No other sharing combinations are valid.
197 uint8_t mspPortCount
= 0;
200 for (index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
201 serialPortConfig_t
*portConfig
= &serialConfigToCheck
->portConfigs
[index
];
203 if (portConfig
->functionMask
& FUNCTION_MSP
) {
207 uint8_t bitCount
= BITCOUNT(portConfig
->functionMask
);
214 if (!(portConfig
->functionMask
& FUNCTION_MSP
)) {
218 if (!(portConfig
->functionMask
& ALL_FUNCTIONS_SHARABLE_WITH_MSP
)) {
219 // some other bit must have been set.
225 if (mspPortCount
== 0 || mspPortCount
> MAX_MSP_PORT_COUNT
) {
231 serialPortConfig_t
*serialFindPortConfiguration(serialPortIdentifier_e identifier
)
234 for (index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
235 serialPortConfig_t
*candidate
= &serialConfig
->portConfigs
[index
];
236 if (candidate
->identifier
== identifier
) {
243 bool doesConfigurationUsePort(serialPortIdentifier_e identifier
)
245 serialPortConfig_t
*candidate
= serialFindPortConfiguration(identifier
);
246 return candidate
!= NULL
&& candidate
->functionMask
;
249 serialPort_t
*openSerialPort(
250 serialPortIdentifier_e identifier
,
251 serialPortFunction_e function
,
252 serialReceiveCallbackPtr callback
,
255 portOptions_t options
)
257 #if (!defined(USE_VCP) && !defined(USE_USART1) && !defined(USE_USART2) && !defined(USE_USART3) && !defined(USE_SOFTSERIAL1) && !defined(USE_SOFTSERIAL1))
264 serialPortUsage_t
*serialPortUsage
= findSerialPortUsageByIdentifier(identifier
);
265 if (!serialPortUsage
|| serialPortUsage
->function
!= FUNCTION_NONE
) {
266 // not available / already in use
270 serialPort_t
*serialPort
= NULL
;
274 case SERIAL_PORT_USB_VCP
:
275 serialPort
= usbVcpOpen();
279 case SERIAL_PORT_USART1
:
280 serialPort
= uartOpen(USART1
, callback
, baudRate
, mode
, options
);
284 case SERIAL_PORT_USART2
:
285 serialPort
= uartOpen(USART2
, callback
, baudRate
, mode
, options
);
289 case SERIAL_PORT_USART3
:
290 serialPort
= uartOpen(USART3
, callback
, baudRate
, mode
, options
);
293 #ifdef USE_SOFTSERIAL1
294 case SERIAL_PORT_SOFTSERIAL1
:
295 serialPort
= openSoftSerial(SOFTSERIAL1
, callback
, baudRate
, options
);
296 serialSetMode(serialPort
, mode
);
299 #ifdef USE_SOFTSERIAL2
300 case SERIAL_PORT_SOFTSERIAL2
:
301 serialPort
= openSoftSerial(SOFTSERIAL2
, callback
, baudRate
, options
);
302 serialSetMode(serialPort
, mode
);
313 serialPort
->identifier
= identifier
;
315 serialPortUsage
->function
= function
;
316 serialPortUsage
->serialPort
= serialPort
;
321 void closeSerialPort(serialPort_t
*serialPort
) {
322 serialPortUsage_t
*serialPortUsage
= findSerialPortUsageByPort(serialPort
);
323 if (!serialPortUsage
) {
328 // TODO wait until data has been transmitted.
330 serialPort
->callback
= NULL
;
332 serialPortUsage
->function
= FUNCTION_NONE
;
333 serialPortUsage
->serialPort
= NULL
;
336 void serialInit(serialConfig_t
*initialSerialConfig
, bool softserialEnabled
)
340 serialConfig
= initialSerialConfig
;
342 serialPortCount
= SERIAL_PORT_COUNT
;
343 memset(&serialPortUsageList
, 0, sizeof(serialPortUsageList
));
345 for (index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
346 serialPortUsageList
[index
].identifier
= serialPortIdentifiers
[index
];
348 if (!softserialEnabled
) {
350 #ifdef USE_SOFTSERIAL1
351 || serialPortUsageList
[index
].identifier
== SERIAL_PORT_SOFTSERIAL1
353 #ifdef USE_SOFTSERIAL2
354 || serialPortUsageList
[index
].identifier
== SERIAL_PORT_SOFTSERIAL2
357 serialPortUsageList
[index
].identifier
= SERIAL_PORT_NONE
;
364 void serialRemovePort(serialPortIdentifier_e identifier
)
366 for (uint8_t index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
367 if (serialPortUsageList
[index
].identifier
== identifier
) {
368 serialPortUsageList
[index
].identifier
= SERIAL_PORT_NONE
;
374 uint8_t serialGetAvailablePortCount(void)
376 return serialPortCount
;
379 bool serialIsPortAvailable(serialPortIdentifier_e identifier
)
381 for (uint8_t index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
382 if (serialPortUsageList
[index
].identifier
== identifier
) {
389 void handleSerial(void)
392 // in cli mode, all serial stuff goes to here. enter cli mode by sending #
402 void waitForSerialPortToFinishTransmitting(serialPort_t
*serialPort
)
404 while (!isSerialTransmitBufferEmpty(serialPort
)) {
409 void cliEnter(serialPort_t
*serialPort
);
411 void evaluateOtherData(serialPort_t
*serialPort
, uint8_t receivedChar
)
416 if (receivedChar
== '#') {
417 cliEnter(serialPort
);
420 if (receivedChar
== serialConfig
->reboot_character
) {
421 systemResetToBootloader();