2 * This file is part of INAV.
4 * INAV 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 * INAV 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 INAV. If not, see <http://www.gnu.org/licenses/>.
23 #if defined(SEMIHOSTING)
27 #include "build/version.h"
29 #include "drivers/serial.h"
30 #include "drivers/time.h"
32 #include "common/log.h"
33 #include "common/printf.h"
34 #include "common/utils.h"
36 #include "config/feature.h"
37 #include "config/parameter_group_ids.h"
39 #include "io/serial.h"
41 #include "fc/config.h"
42 #include "fc/settings.h"
45 #include "msp/msp_serial.h"
46 #include "msp/msp_protocol.h"
50 #define LOG_PREFIX "[%6d.%03d] "
51 #define LOG_PREFIX_FORMATTED_SIZE 13
53 static serialPort_t
* logPort
= NULL
;
54 static mspPort_t
* mspLogPort
= NULL
;
56 PG_REGISTER(logConfig_t
, logConfig
, PG_LOG_CONFIG
, 0);
58 PG_RESET_TEMPLATE(logConfig_t
, logConfig
,
59 .level
= SETTING_LOG_LEVEL_DEFAULT
,
60 .topics
= SETTING_LOG_TOPICS_DEFAULT
65 const serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_LOG
);
70 bool portIsSharedWithMSP
= false;
72 if (determinePortSharing(portConfig
, FUNCTION_LOG
) == PORTSHARING_SHARED
) {
73 // We support sharing a LOG port only with MSP
74 if (portConfig
->functionMask
!= (FUNCTION_LOG
| FUNCTION_MSP
)) {
77 portIsSharedWithMSP
= true;
80 // If the port is shared with MSP, reuse the port
81 if (portIsSharedWithMSP
) {
82 const serialPort_t
*logAndMspPort
= findSharedSerialPort(FUNCTION_LOG
, FUNCTION_MSP
);
87 mspLogPort
= mspSerialPortFind(logAndMspPort
);
93 logPort
= openSerialPort(portConfig
->identifier
, FUNCTION_LOG
, NULL
, NULL
, baudRates
[BAUD_921600
], MODE_TX
, SERIAL_NOT_INVERTED
);
98 // Initialization done
99 LOG_INFO(SYSTEM
, "%s/%s %s %s / %s (%s)",
109 static void logPutcp(void *p
, char ch
)
111 *(*((char **) p
))++ = ch
;
114 static void logPrint(const char *buf
, size_t size
)
116 #if defined(SEMIHOSTING)
117 static bool semihostingInitialized
= false;
118 extern void initialise_monitor_handles(void);
120 if (!semihostingInitialized
) {
121 initialise_monitor_handles();
122 semihostingInitialized
= true;
124 for (size_t ii
= 0; ii
< size
; ii
++) {
125 fputc(buf
[ii
], stdout
);
129 // Send data via UART (if configured & connected - a safeguard against zombie VCP)
130 if (serialIsConnected(logPort
)) {
131 serialPrint(logPort
, buf
);
133 } else if (mspLogPort
) {
134 mspSerialPushPort(MSP_DEBUGMSG
, (uint8_t*)buf
, size
, mspLogPort
, MSP_V2_NATIVE
);
138 static size_t logFormatPrefix(char *buf
, const timeMs_t timeMs
)
141 return tfp_sprintf(buf
, LOG_PREFIX
, (int)(timeMs
/ 1000), (int)(timeMs
% 1000));
144 static bool logHasOutput(void)
146 #if defined(SEMIHOSTING)
149 return logPort
|| mspLogPort
;
153 static bool logIsEnabled(logTopic_e topic
, unsigned level
)
155 return logHasOutput() && (level
<= logConfig()->level
|| (logConfig()->topics
& (1 << topic
)));
158 void _logf(logTopic_e topic
, unsigned level
, const char *fmt
, ...)
164 STATIC_ASSERT(MSP_PORT_OUTBUF_SIZE
>= sizeof(buf
), MSP_PORT_OUTBUF_SIZE_not_big_enough_for_log
);
166 if (!logIsEnabled(topic
, level
)) {
170 charCount
= logFormatPrefix(buf
, millis());
171 bufPtr
= &buf
[charCount
];
176 charCount
+= tfp_format(&bufPtr
, logPutcp
, fmt
, va
);
177 logPutcp(&bufPtr
, '\n');
178 logPutcp(&bufPtr
, 0);
182 logPrint(buf
, charCount
);
185 void _logBufferHex(logTopic_e topic
, unsigned level
, const void *buffer
, size_t size
)
187 // Print lines of up to maxBytes bytes. We need 5 characters per byte
189 const size_t charsPerByte
= 5;
190 const size_t maxBytes
= 8;
191 char buf
[LOG_PREFIX_FORMATTED_SIZE
+ charsPerByte
* maxBytes
+ 1]; // +1 for the null terminator
192 size_t bufPos
= LOG_PREFIX_FORMATTED_SIZE
;
193 const uint8_t *inputPtr
= buffer
;
195 if (!logIsEnabled(topic
, level
)) {
199 logFormatPrefix(buf
, millis());
201 for (size_t ii
= 0; ii
< size
; ii
++) {
202 tfp_sprintf(buf
+ bufPos
, "0x%02x ", inputPtr
[ii
]);
203 bufPos
+= charsPerByte
;
204 if (bufPos
== sizeof(buf
)-1) {
205 buf
[bufPos
-1] = '\n';
207 logPrint(buf
, bufPos
+ 1);
208 bufPos
= LOG_PREFIX_FORMATTED_SIZE
;
212 if (bufPos
> LOG_PREFIX_FORMATTED_SIZE
) {
213 buf
[bufPos
-1] = '\n';
215 logPrint(buf
, bufPos
+ 1);