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 "drivers/system.h"
28 #include "drivers/gpio.h"
29 #include "drivers/timer.h"
30 #include "drivers/serial.h"
31 #include "drivers/serial_softserial.h"
32 #include "drivers/serial_uart.h"
33 #include "drivers/serial_usb_vcp.h"
35 #include "io/serial.h"
36 #include "serial_cli.h"
37 #include "serial_msp.h"
39 #include "config/config.h"
42 #include "telemetry/telemetry.h"
45 void updateSerialRxFunctionConstraint(functionConstraint_t
*functionConstraintToUpdate
);
47 void mspInit(serialConfig_t
*serialConfig
);
48 void cliInit(serialConfig_t
*serialConfig
);
50 // this exists so the user can reference scenarios by a number in the CLI instead of an unuser-friendly bitmask.
51 const serialPortFunctionScenario_e serialPortScenarios
[SERIAL_PORT_SCENARIO_COUNT
] = {
54 // common scenarios in order of importance
55 SCENARIO_MSP_CLI_TELEMETRY_GPS_PASTHROUGH
,
57 SCENARIO_SERIAL_RX_ONLY
,
58 SCENARIO_TELEMETRY_ONLY
,
61 SCENARIO_MSP_CLI_GPS_PASTHROUGH
,
63 SCENARIO_GPS_PASSTHROUGH_ONLY
,
65 SCENARIO_SMARTPORT_TELEMETRY_ONLY
,
67 SCENARIO_BLACKBOX_ONLY
,
68 SCENARIO_MSP_CLI_BLACKBOX_GPS_PASTHROUGH
71 static serialConfig_t
*serialConfig
;
72 static serialPort_t
*serialPorts
[SERIAL_PORT_COUNT
];
75 static serialPortFunction_t serialPortFunctions
[SERIAL_PORT_COUNT
] = {
77 {SERIAL_PORT_USB_VCP
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
80 {SERIAL_PORT_USART1
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
83 {SERIAL_PORT_USART2
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
86 {SERIAL_PORT_USART3
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
90 const serialPortConstraint_t serialPortConstraints
[SERIAL_PORT_COUNT
] = {
92 {SERIAL_PORT_USB_VCP
, 9600, 115200, SPF_NONE
},
95 {SERIAL_PORT_USART1
, 9600, 115200, SPF_NONE
| SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_BIDIR_MODE
},
98 {SERIAL_PORT_USART2
, 9600, 115200, SPF_SUPPORTS_CALLBACK
| SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_BIDIR_MODE
},
101 {SERIAL_PORT_USART3
, 9600, 115200, SPF_SUPPORTS_CALLBACK
| SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_BIDIR_MODE
},
108 static serialPortFunction_t serialPortFunctions
[SERIAL_PORT_COUNT
] = {
110 {SERIAL_PORT_USB_VCP
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
112 {SERIAL_PORT_USART1
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
113 {SERIAL_PORT_USART3
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
114 {SERIAL_PORT_SOFTSERIAL1
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
}
117 const serialPortConstraint_t serialPortConstraints
[SERIAL_PORT_COUNT
] = {
119 {SERIAL_PORT_USB_VCP
, 9600, 115200, SPF_NONE
},
121 {SERIAL_PORT_USART1
, 9600, 115200, SPF_NONE
| SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_BIDIR_MODE
},
122 {SERIAL_PORT_USART3
, 9600, 115200, SPF_SUPPORTS_CALLBACK
| SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_BIDIR_MODE
},
123 {SERIAL_PORT_SOFTSERIAL1
, 9600, 19200, SPF_SUPPORTS_CALLBACK
| SPF_IS_SOFTWARE_INVERTABLE
}
127 static serialPortFunction_t serialPortFunctions
[SERIAL_PORT_COUNT
] = {
128 {SERIAL_PORT_USART1
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
129 {SERIAL_PORT_USART2
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
130 #if (SERIAL_PORT_COUNT > 2)
131 {SERIAL_PORT_SOFTSERIAL1
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
},
132 {SERIAL_PORT_SOFTSERIAL2
, NULL
, SCENARIO_UNUSED
, FUNCTION_NONE
}
136 const serialPortConstraint_t serialPortConstraints
[SERIAL_PORT_COUNT
] = {
137 {SERIAL_PORT_USART1
, 9600, 250000, SPF_NONE
| SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_BIDIR_MODE
},
138 {SERIAL_PORT_USART2
, 9600, 250000, SPF_SUPPORTS_CALLBACK
| SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_BIDIR_MODE
},
139 #if (SERIAL_PORT_COUNT > 2)
140 {SERIAL_PORT_SOFTSERIAL1
, 9600, 19200, SPF_SUPPORTS_CALLBACK
| SPF_IS_SOFTWARE_INVERTABLE
},
141 {SERIAL_PORT_SOFTSERIAL2
, 9600, 19200, SPF_SUPPORTS_CALLBACK
| SPF_IS_SOFTWARE_INVERTABLE
}
147 const functionConstraint_t functionConstraints
[] = {
148 { FUNCTION_CLI
, 9600, 115200, NO_AUTOBAUD
, SPF_NONE
},
149 { FUNCTION_GPS
, 9600, 115200, AUTOBAUD
, SPF_NONE
},
150 { FUNCTION_GPS_PASSTHROUGH
, 9600, 115200, NO_AUTOBAUD
, SPF_NONE
},
151 { FUNCTION_MSP
, 9600, 115200, NO_AUTOBAUD
, SPF_NONE
},
152 { FUNCTION_SERIAL_RX
, 9600, 250000, NO_AUTOBAUD
, SPF_SUPPORTS_SBUS_MODE
| SPF_SUPPORTS_CALLBACK
},
153 { FUNCTION_TELEMETRY
, 9600, 19200, NO_AUTOBAUD
, SPF_NONE
},
154 { FUNCTION_SMARTPORT_TELEMETRY
, 57600, 57600, NO_AUTOBAUD
, SPF_SUPPORTS_BIDIR_MODE
},
155 { FUNCTION_BLACKBOX
, 115200,115200, NO_AUTOBAUD
, SPF_NONE
}
158 #define FUNCTION_CONSTRAINT_COUNT (sizeof(functionConstraints) / sizeof(functionConstraint_t))
160 typedef struct serialPortSearchResult_s
{
161 serialPortIndex_e portIndex
;
162 serialPortFunction_t
*portFunction
;
163 const serialPortConstraint_t
*portConstraint
;
164 const functionConstraint_t
*functionConstraint
;
167 uint8_t startSerialPortFunctionIndex
; // used by findNextSerialPort
168 } serialPortSearchResult_t
;
170 static const serialPortFunctionList_t serialPortFunctionList
= {
175 const serialPortFunctionList_t
*getSerialPortFunctionList(void)
177 return &serialPortFunctionList
;
180 uint8_t lookupScenarioIndex(serialPortFunctionScenario_e scenario
) {
182 for (index
= 0; index
< SERIAL_PORT_SCENARIO_COUNT
; index
++) {
183 if (serialPortScenarios
[index
] == scenario
) {
190 static serialPortIndex_e
lookupSerialPortIndexByIdentifier(serialPortIdentifier_e identifier
)
192 serialPortIndex_e portIndex
;
193 for (portIndex
= 0; portIndex
< SERIAL_PORT_COUNT
; portIndex
++) {
194 if (serialPortConstraints
[portIndex
].identifier
== identifier
) {
201 #define IDENTIFIER_NOT_FOUND 0xFF
203 static uint8_t lookupSerialPortFunctionIndexByIdentifier(serialPortIdentifier_e identifier
)
206 for (index
= 0; index
< SERIAL_PORT_COUNT
; index
++) {
207 if (serialPortFunctions
[index
].identifier
== identifier
) {
211 return IDENTIFIER_NOT_FOUND
;
214 static const functionConstraint_t
*findFunctionConstraint(serialPortFunction_e function
)
216 const functionConstraint_t
*functionConstraint
= NULL
;
217 uint8_t functionConstraintIndex
;
219 for (functionConstraintIndex
= 0; functionConstraintIndex
< FUNCTION_CONSTRAINT_COUNT
; functionConstraintIndex
++) {
220 functionConstraint
= &functionConstraints
[functionConstraintIndex
];
221 if (functionConstraint
->function
== function
) {
222 return functionConstraint
;
228 static uint8_t countBits_uint32(uint32_t n
) {
229 uint8_t c
; // c accumulates the total bits set in n
231 n
&= n
- 1; // clear the least significant bit set
234 static int serialPortFunctionMostSpecificFirstComparator(const void *aPtr
, const void *bPtr
)
236 serialPortFunction_t
*a
= (serialPortFunction_t
*)aPtr
;
237 serialPortFunction_t
*b
= (serialPortFunction_t
*)bPtr
;
239 return countBits_uint32(a
->scenario
) - countBits_uint32(b
->scenario
);
242 static void sortSerialPortFunctions(serialPortFunction_t
*serialPortFunctions
, uint8_t elements
)
244 serialPortFunction_t swap
;
249 // bubble-sort array (TODO - port selection can be implemented as repeated minimum search with bitmask marking used elements)
250 for (index1
= 0; index1
< (elements
- 1); index1
++) {
251 for (index2
= 0; index2
< elements
- index1
- 1; index2
++) {
252 if(serialPortFunctionMostSpecificFirstComparator(&serialPortFunctions
[index2
], &serialPortFunctions
[index2
+ 1]) > 0) {
253 swap
= serialPortFunctions
[index2
];
254 serialPortFunctions
[index2
] = serialPortFunctions
[index2
+ 1];
255 serialPortFunctions
[index2
+ 1] = swap
;
261 serialPortSearchResult_t
*findNextSerialPort(serialPortFunction_e function
, const functionConstraint_t
*functionConstraint
, serialPortSearchResult_t
*resultBuffer
)
263 uint8_t serialPortFunctionIndex
;
264 serialPortFunction_t
*serialPortFunction
;
265 for (serialPortFunctionIndex
= resultBuffer
->startSerialPortFunctionIndex
; serialPortFunctionIndex
< SERIAL_PORT_COUNT
; serialPortFunctionIndex
++) {
266 serialPortFunction
= &serialPortFunctions
[serialPortFunctionIndex
];
268 if (!(serialPortFunction
->scenario
& function
)) {
272 uint8_t serialPortIndex
= lookupSerialPortIndexByIdentifier(serialPortFunction
->identifier
);
273 const serialPortConstraint_t
*serialPortConstraint
= &serialPortConstraints
[serialPortIndex
];
276 if (!feature(FEATURE_SOFTSERIAL
) && (
277 serialPortConstraint
->identifier
== SERIAL_PORT_SOFTSERIAL1
)) {
281 #if defined(USE_SOFTSERIAL1) ||(defined(USE_SOFTSERIAL2))
282 if (!feature(FEATURE_SOFTSERIAL
) && (
283 serialPortConstraint
->identifier
== SERIAL_PORT_SOFTSERIAL1
||
284 serialPortConstraint
->identifier
== SERIAL_PORT_SOFTSERIAL2
289 #if (defined(NAZE) || defined(OLIMEXINO)) && defined(SONAR)
290 if (feature(FEATURE_SONAR
) && !feature(FEATURE_RX_PARALLEL_PWM
) && (serialPortConstraint
->identifier
== SERIAL_PORT_SOFTSERIAL2
)) {
296 if ((serialPortConstraint
->feature
& functionConstraint
->requiredSerialPortFeatures
) != functionConstraint
->requiredSerialPortFeatures
) {
300 if (functionConstraint
->minBaudRate
< serialPortConstraint
->minBaudRate
|| functionConstraint
->maxBaudRate
> serialPortConstraint
->maxBaudRate
) {
304 resultBuffer
->portIndex
= serialPortIndex
;
305 resultBuffer
->portConstraint
= serialPortConstraint
;
306 resultBuffer
->portFunction
= serialPortFunction
;
307 resultBuffer
->functionConstraint
= functionConstraint
;
309 uint8_t nextStartIndex
= serialPortFunctionIndex
+ 1;
310 resultBuffer
->startSerialPortFunctionIndex
= nextStartIndex
;
319 * since this method, and other methods that use it, use a single instance of
320 * searchPortSearchResult be sure to copy the data out of it before it gets overwritten by another caller.
321 * If this becomes a problem perhaps change the implementation to use a destination argument.
323 static serialPortSearchResult_t
*findSerialPort(serialPortFunction_e function
, const functionConstraint_t
*functionConstraint
)
325 static serialPortSearchResult_t serialPortSearchResult
;
327 memset(&serialPortSearchResult
, 0, sizeof(serialPortSearchResult
));
329 // FIXME this only needs to be done once, after the config has been loaded.
330 sortSerialPortFunctions(serialPortFunctions
, SERIAL_PORT_COUNT
);
332 return findNextSerialPort(function
, functionConstraint
, &serialPortSearchResult
);
336 static serialPortFunction_t
*findSerialPortFunction(uint16_t functionMask
)
338 serialPortIndex_e portIndex
;
340 // find exact match first
341 for (portIndex
= 0; portIndex
< SERIAL_PORT_COUNT
; portIndex
++) {
342 serialPortFunction_t
*serialPortFunction
= &serialPortFunctions
[portIndex
];
343 if (serialPortFunction
->scenario
== functionMask
) {
344 return serialPortFunction
;
348 // find the first port that supports the function requested
349 for (portIndex
= 0; portIndex
< SERIAL_PORT_COUNT
; portIndex
++) {
350 serialPortFunction_t
*serialPortFunction
= &serialPortFunctions
[portIndex
];
351 if (serialPortFunction
->scenario
& functionMask
) {
352 return serialPortFunction
;
360 * find a serial port that is:
362 * b) matches the function mask exactly, or if an exact match is not found the first port that supports the function
364 serialPort_t
*findOpenSerialPort(uint16_t functionMask
)
366 serialPortFunction_t
*function
= findSerialPortFunction(functionMask
);
370 return function
->port
;
375 static serialPortFunction_t
* findSerialPortFunctionByPort(serialPort_t
*port
)
377 serialPortFunction_t
*serialPortFunction
;
378 uint8_t functionIndex
;
380 for (functionIndex
= 0; functionIndex
< SERIAL_PORT_COUNT
; functionIndex
++) {
381 serialPortFunction
= &serialPortFunctions
[functionIndex
];
382 if (serialPortFunction
->port
== port
) {
383 return serialPortFunction
;
390 void beginSerialPortFunction(serialPort_t
*port
, serialPortFunction_e function
)
392 serialPortFunction_t
*serialPortFunction
= findSerialPortFunctionByPort(port
);
394 serialPortFunction
->currentFunction
= function
;
397 void endSerialPortFunction(serialPort_t
*port
, serialPortFunction_e function
)
400 serialPortFunction_t
*serialPortFunction
= findSerialPortFunctionByPort(port
);
402 serialPortFunction
->currentFunction
= FUNCTION_NONE
;
403 serialPortFunction
->port
= NULL
;
406 functionConstraint_t
*getConfiguredFunctionConstraint(serialPortFunction_e function
)
408 static functionConstraint_t configuredFunctionConstraint
;
409 const functionConstraint_t
*functionConstraint
;
411 functionConstraint
= findFunctionConstraint(function
);
412 if (!functionConstraint
) {
415 memcpy(&configuredFunctionConstraint
, functionConstraint
, sizeof(functionConstraint_t
));
419 configuredFunctionConstraint
.maxBaudRate
= serialConfig
->msp_baudrate
;
423 configuredFunctionConstraint
.minBaudRate
= serialConfig
->cli_baudrate
;
424 configuredFunctionConstraint
.maxBaudRate
= configuredFunctionConstraint
.minBaudRate
;
427 case FUNCTION_GPS_PASSTHROUGH
:
428 configuredFunctionConstraint
.minBaudRate
= serialConfig
->gps_passthrough_baudrate
;
429 configuredFunctionConstraint
.maxBaudRate
= configuredFunctionConstraint
.minBaudRate
;
433 case FUNCTION_TELEMETRY
:
434 case FUNCTION_SMARTPORT_TELEMETRY
:
435 configuredFunctionConstraint
.minBaudRate
= getTelemetryProviderBaudRate();
436 configuredFunctionConstraint
.maxBaudRate
= configuredFunctionConstraint
.minBaudRate
;
440 case FUNCTION_SERIAL_RX
:
441 updateSerialRxFunctionConstraint(&configuredFunctionConstraint
);
445 configuredFunctionConstraint
.maxBaudRate
= serialConfig
->gps_baudrate
;
450 return &configuredFunctionConstraint
;
453 bool isSerialConfigValid(serialConfig_t
*serialConfigToCheck
)
455 serialPortSearchResult_t
*searchResult
;
456 functionConstraint_t
*functionConstraint
;
458 serialConfig
= serialConfigToCheck
;
460 functionConstraint
= getConfiguredFunctionConstraint(FUNCTION_MSP
);
461 searchResult
= findSerialPort(FUNCTION_MSP
, functionConstraint
);
466 functionConstraint
= getConfiguredFunctionConstraint(FUNCTION_CLI
);
467 searchResult
= findSerialPort(FUNCTION_CLI
, functionConstraint
);
472 functionConstraint
= getConfiguredFunctionConstraint(FUNCTION_GPS
);
473 searchResult
= findSerialPort(FUNCTION_GPS
, functionConstraint
);
474 if (feature(FEATURE_GPS
) && !searchResult
) {
478 functionConstraint
= getConfiguredFunctionConstraint(FUNCTION_SERIAL_RX
);
479 searchResult
= findSerialPort(FUNCTION_SERIAL_RX
, functionConstraint
);
480 if (feature(FEATURE_RX_SERIAL
) && !searchResult
) {
484 functionConstraint
= getConfiguredFunctionConstraint(FUNCTION_TELEMETRY
);
485 searchResult
= findSerialPort(FUNCTION_TELEMETRY
, functionConstraint
);
486 // TODO check explicitly for SmartPort config
488 functionConstraint
= getConfiguredFunctionConstraint(FUNCTION_SMARTPORT_TELEMETRY
);
489 searchResult
= findSerialPort(FUNCTION_SMARTPORT_TELEMETRY
, functionConstraint
);
491 if (feature(FEATURE_TELEMETRY
) && !searchResult
) {
495 uint8_t functionIndex
;
496 uint8_t cliPortCount
= 0;
497 uint8_t mspPortCount
= 0;
498 for (functionIndex
= 0; functionIndex
< SERIAL_PORT_COUNT
; functionIndex
++) {
499 if (serialPortFunctions
[functionIndex
].scenario
& FUNCTION_CLI
) {
500 if (++cliPortCount
> 1) {
504 if (serialPortFunctions
[functionIndex
].scenario
& FUNCTION_MSP
) {
505 if (++mspPortCount
> MAX_MSP_PORT_COUNT
) {
513 bool doesConfigurationUsePort(serialPortIdentifier_e portIdentifier
)
515 serialPortSearchResult_t
*searchResult
;
516 const functionConstraint_t
*functionConstraint
;
517 serialPortFunction_e function
;
520 for (index
= 0; index
< FUNCTION_CONSTRAINT_COUNT
; index
++) {
521 function
= functionConstraints
[index
].function
;
522 functionConstraint
= findFunctionConstraint(function
);
523 searchResult
= findSerialPort(function
, functionConstraint
);
524 if (searchResult
->portConstraint
->identifier
== portIdentifier
) {
531 bool canOpenSerialPort(serialPortFunction_e function
)
533 functionConstraint_t
*functionConstraint
= getConfiguredFunctionConstraint(function
);
535 serialPortSearchResult_t
*result
= findSerialPort(function
, functionConstraint
);
536 return result
!= NULL
;
539 bool isSerialPortFunctionShared(serialPortFunction_e functionToUse
, uint16_t functionMask
)
541 functionConstraint_t
*functionConstraint
= getConfiguredFunctionConstraint(functionToUse
);
542 serialPortSearchResult_t
*result
= findSerialPort(functionToUse
, functionConstraint
);
547 return result
->portFunction
->scenario
& functionMask
;
550 serialPort_t
*findSharedSerialPort(serialPortFunction_e functionToUse
, uint16_t functionMask
)
552 functionConstraint_t
*functionConstraint
= getConfiguredFunctionConstraint(functionToUse
);
553 serialPortSearchResult_t
*result
= findSerialPort(functionToUse
, functionConstraint
);
555 if (result
->portFunction
->scenario
& functionMask
) {
556 return result
->portFunction
->port
;
561 void applySerialConfigToPortFunctions(serialConfig_t
*serialConfig
)
563 uint32_t portIndex
= 0, serialPortIdentifier
, constraintIndex
;
565 for (constraintIndex
= 0; constraintIndex
< SERIAL_PORT_COUNT
&& portIndex
< SERIAL_PORT_COUNT
; constraintIndex
++) {
566 serialPortIdentifier
= serialPortConstraints
[constraintIndex
].identifier
;
567 uint32_t functionIndex
= lookupSerialPortFunctionIndexByIdentifier(serialPortIdentifier
);
568 if (functionIndex
== IDENTIFIER_NOT_FOUND
) {
571 serialPortFunctions
[functionIndex
].scenario
= serialPortScenarios
[serialConfig
->serial_port_scenario
[portIndex
++]];
575 serialPort_t
*openSerialPort(serialPortFunction_e function
, serialReceiveCallbackPtr callback
, uint32_t baudRate
, portMode_t mode
, serialInversion_e inversion
)
577 serialPort_t
*serialPort
= NULL
;
579 functionConstraint_t
*initialFunctionConstraint
= getConfiguredFunctionConstraint(function
);
581 functionConstraint_t updatedFunctionConstraint
;
582 memcpy(&updatedFunctionConstraint
, initialFunctionConstraint
, sizeof(updatedFunctionConstraint
));
583 if (initialFunctionConstraint
->autoBaud
== NO_AUTOBAUD
) {
584 updatedFunctionConstraint
.minBaudRate
= baudRate
;
585 updatedFunctionConstraint
.maxBaudRate
= baudRate
;
587 functionConstraint_t
*functionConstraint
= &updatedFunctionConstraint
;
589 serialPortSearchResult_t
*searchResult
= findSerialPort(function
, functionConstraint
);
591 while(searchResult
&& searchResult
->portFunction
->port
) {
592 // port is already open, find the next one
593 searchResult
= findNextSerialPort(function
, functionConstraint
, searchResult
);
600 serialPortIndex_e portIndex
= searchResult
->portIndex
;
602 const serialPortConstraint_t
*serialPortConstraint
= searchResult
->portConstraint
;
604 serialPortIdentifier_e identifier
= serialPortConstraint
->identifier
;
607 case SERIAL_PORT_USB_VCP
:
608 serialPort
= usbVcpOpen();
612 case SERIAL_PORT_USART1
:
613 serialPort
= uartOpen(USART1
, callback
, baudRate
, mode
, inversion
);
617 case SERIAL_PORT_USART2
:
618 serialPort
= uartOpen(USART2
, callback
, baudRate
, mode
, inversion
);
622 case SERIAL_PORT_USART3
:
623 serialPort
= uartOpen(USART3
, callback
, baudRate
, mode
, inversion
);
626 #ifdef USE_SOFTSERIAL1
627 case SERIAL_PORT_SOFTSERIAL1
:
628 serialPort
= openSoftSerial(SOFTSERIAL1
, callback
, baudRate
, inversion
);
629 serialSetMode(serialPort
, mode
);
632 #ifdef USE_SOFTSERIAL2
633 case SERIAL_PORT_SOFTSERIAL2
:
634 serialPort
= openSoftSerial(SOFTSERIAL2
, callback
, baudRate
, inversion
);
635 serialSetMode(serialPort
, mode
);
646 serialPort
->identifier
= identifier
;
648 serialPorts
[portIndex
] = serialPort
;
650 serialPortFunction_t
*serialPortFunction
= searchResult
->portFunction
;
652 serialPortFunction
->port
= serialPort
;
653 //serialPortFunction->identifier = identifier;
655 beginSerialPortFunction(serialPort
, function
);
660 void serialInit(serialConfig_t
*initialSerialConfig
)
662 serialConfig
= initialSerialConfig
;
663 applySerialConfigToPortFunctions(serialConfig
);
666 if (telemetryAllowsOtherSerial(FUNCTION_MSP
))
668 mspInit(serialConfig
);
671 if (telemetryAllowsOtherSerial(FUNCTION_CLI
))
673 cliInit(serialConfig
);
676 void handleSerial(void)
678 // in cli mode, all serial stuff goes to here. enter cli mode by sending #
685 if (telemetryAllowsOtherSerial(FUNCTION_MSP
))
690 void waitForSerialPortToFinishTransmitting(serialPort_t
*serialPort
)
692 while (!isSerialTransmitBufferEmpty(serialPort
)) {
697 // evaluate all other incoming serial data
698 void evaluateOtherData(uint8_t sr
)
702 else if (sr
== serialConfig
->reboot_character
)
703 systemResetToBootloader();