Version 1.0 bump
[inav/snaewe.git] / src / main / io / serial.c
blob901f14d2d2515cf5ceb29212b2af33fba612c84c
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "platform.h"
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"
33 #endif
35 #if defined(USE_USART1) || defined(USE_USART2) || defined(USE_USART3)
36 #include "drivers/serial_uart.h"
37 #endif
39 #if defined(USE_VCP)
40 #include "drivers/serial_usb_vcp.h"
41 #endif
43 #include "io/serial.h"
44 #include "serial_cli.h"
45 #include "serial_msp.h"
47 #include "config/config.h"
49 #ifdef TELEMETRY
50 #include "telemetry/telemetry.h"
51 #endif
53 static serialConfig_t *serialConfig;
54 static serialPortUsage_t serialPortUsageList[SERIAL_PORT_COUNT];
56 const serialPortIdentifier_e serialPortIdentifiers[SERIAL_PORT_COUNT] = {
57 #ifdef USE_VCP
58 SERIAL_PORT_USB_VCP,
59 #endif
60 #ifdef USE_USART1
61 SERIAL_PORT_USART1,
62 #endif
63 #ifdef USE_USART2
64 SERIAL_PORT_USART2,
65 #endif
66 #ifdef USE_USART3
67 SERIAL_PORT_USART3,
68 #endif
69 #ifdef USE_SOFTSERIAL1
70 SERIAL_PORT_SOFTSERIAL1,
71 #endif
72 #ifdef USE_SOFTSERIAL2
73 SERIAL_PORT_SOFTSERIAL2,
74 #endif
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)
85 uint8_t index;
87 for (index = 0; index < BAUD_RATE_COUNT; index++) {
88 if (baudRates[index] == baudRate) {
89 return index;
92 return BAUD_AUTO;
95 static serialPortUsage_t *findSerialPortUsageByIdentifier(serialPortIdentifier_e identifier)
97 uint8_t index;
98 for (index = 0; index < SERIAL_PORT_COUNT; index++) {
99 serialPortUsage_t *candidate = &serialPortUsageList[index];
100 if (candidate->identifier == identifier) {
101 return candidate;
104 return NULL;
107 serialPortUsage_t *findSerialPortUsageByPort(serialPort_t *serialPort) {
108 uint8_t index;
109 for (index = 0; index < SERIAL_PORT_COUNT; index++) {
110 serialPortUsage_t *candidate = &serialPortUsageList[index];
111 if (candidate->serialPort == serialPort) {
112 return candidate;
115 return NULL;
118 typedef struct findSerialPortConfigState_s {
119 uint8_t lastIndex;
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) {
137 return candidate;
140 return NULL;
143 typedef struct findSharedSerialPortState_s {
144 uint8_t lastIndex;
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) {
177 continue;
179 return serialPortUsage->serialPort;
182 return NULL;
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);
192 * rules:
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;
199 uint8_t index;
200 for (index = 0; index < SERIAL_PORT_COUNT; index++) {
201 serialPortConfig_t *portConfig = &serialConfigToCheck->portConfigs[index];
203 if (portConfig->functionMask & FUNCTION_MSP) {
204 mspPortCount++;
207 uint8_t bitCount = BITCOUNT(portConfig->functionMask);
208 if (bitCount > 1) {
209 // shared
210 if (bitCount > 2) {
211 return false;
214 if (!(portConfig->functionMask & FUNCTION_MSP)) {
215 return false;
218 if (!(portConfig->functionMask & ALL_FUNCTIONS_SHARABLE_WITH_MSP)) {
219 // some other bit must have been set.
220 return false;
225 if (mspPortCount == 0 || mspPortCount > MAX_MSP_PORT_COUNT) {
226 return false;
228 return true;
231 serialPortConfig_t *serialFindPortConfiguration(serialPortIdentifier_e identifier)
233 uint8_t index;
234 for (index = 0; index < SERIAL_PORT_COUNT; index++) {
235 serialPortConfig_t *candidate = &serialConfig->portConfigs[index];
236 if (candidate->identifier == identifier) {
237 return candidate;
240 return NULL;
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,
253 uint32_t baudRate,
254 portMode_t mode,
255 portOptions_t options)
257 #if (!defined(USE_VCP) && !defined(USE_USART1) && !defined(USE_USART2) && !defined(USE_USART3) && !defined(USE_SOFTSERIAL1) && !defined(USE_SOFTSERIAL1))
258 UNUSED(callback);
259 UNUSED(baudRate);
260 UNUSED(mode);
261 UNUSED(options);
262 #endif
264 serialPortUsage_t *serialPortUsage = findSerialPortUsageByIdentifier(identifier);
265 if (!serialPortUsage || serialPortUsage->function != FUNCTION_NONE) {
266 // not available / already in use
267 return NULL;
270 serialPort_t *serialPort = NULL;
272 switch(identifier) {
273 #ifdef USE_VCP
274 case SERIAL_PORT_USB_VCP:
275 serialPort = usbVcpOpen();
276 break;
277 #endif
278 #ifdef USE_USART1
279 case SERIAL_PORT_USART1:
280 serialPort = uartOpen(USART1, callback, baudRate, mode, options);
281 break;
282 #endif
283 #ifdef USE_USART2
284 case SERIAL_PORT_USART2:
285 serialPort = uartOpen(USART2, callback, baudRate, mode, options);
286 break;
287 #endif
288 #ifdef USE_USART3
289 case SERIAL_PORT_USART3:
290 serialPort = uartOpen(USART3, callback, baudRate, mode, options);
291 break;
292 #endif
293 #ifdef USE_SOFTSERIAL1
294 case SERIAL_PORT_SOFTSERIAL1:
295 serialPort = openSoftSerial(SOFTSERIAL1, callback, baudRate, options);
296 serialSetMode(serialPort, mode);
297 break;
298 #endif
299 #ifdef USE_SOFTSERIAL2
300 case SERIAL_PORT_SOFTSERIAL2:
301 serialPort = openSoftSerial(SOFTSERIAL2, callback, baudRate, options);
302 serialSetMode(serialPort, mode);
303 break;
304 #endif
305 default:
306 break;
309 if (!serialPort) {
310 return NULL;
313 serialPort->identifier = identifier;
315 serialPortUsage->function = function;
316 serialPortUsage->serialPort = serialPort;
318 return serialPort;
321 void closeSerialPort(serialPort_t *serialPort) {
322 serialPortUsage_t *serialPortUsage = findSerialPortUsageByPort(serialPort);
323 if (!serialPortUsage) {
324 // already closed
325 return;
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)
338 uint8_t index;
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) {
349 if (0
350 #ifdef USE_SOFTSERIAL1
351 || serialPortUsageList[index].identifier == SERIAL_PORT_SOFTSERIAL1
352 #endif
353 #ifdef USE_SOFTSERIAL2
354 || serialPortUsageList[index].identifier == SERIAL_PORT_SOFTSERIAL2
355 #endif
357 serialPortUsageList[index].identifier = SERIAL_PORT_NONE;
358 serialPortCount--;
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;
369 serialPortCount--;
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) {
383 return true;
386 return false;
389 void handleSerial(void)
391 #ifdef USE_CLI
392 // in cli mode, all serial stuff goes to here. enter cli mode by sending #
393 if (cliMode) {
394 cliProcess();
395 return;
397 #endif
399 mspProcess();
402 void waitForSerialPortToFinishTransmitting(serialPort_t *serialPort)
404 while (!isSerialTransmitBufferEmpty(serialPort)) {
405 delay(10);
409 void cliEnter(serialPort_t *serialPort);
411 void evaluateOtherData(serialPort_t *serialPort, uint8_t receivedChar)
413 #ifndef USE_CLI
414 UNUSED(serialPort);
415 #else
416 if (receivedChar == '#') {
417 cliEnter(serialPort);
419 #endif
420 if (receivedChar == serialConfig->reboot_character) {
421 systemResetToBootloader();