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"
44 #include "msp/msp_serial.h"
45 #include "msp/msp_protocol.h"
49 #define LOG_PREFIX "[%6d.%03d] "
50 #define LOG_PREFIX_FORMATTED_SIZE 13
52 static serialPort_t
* logPort
= NULL
;
53 static mspPort_t
* mspLogPort
= NULL
;
55 PG_REGISTER(logConfig_t
, logConfig
, PG_LOG_CONFIG
, 0);
59 const serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_LOG
);
64 bool portIsSharedWithMSP
= false;
66 if (determinePortSharing(portConfig
, FUNCTION_LOG
) == PORTSHARING_SHARED
) {
67 // We support sharing a LOG port only with MSP
68 if (portConfig
->functionMask
!= (FUNCTION_LOG
| FUNCTION_MSP
)) {
71 portIsSharedWithMSP
= true;
74 // If the port is shared with MSP, reuse the port
75 if (portIsSharedWithMSP
) {
76 const serialPort_t
*logAndMspPort
= findSharedSerialPort(FUNCTION_LOG
, FUNCTION_MSP
);
81 mspLogPort
= mspSerialPortFind(logAndMspPort
);
87 logPort
= openSerialPort(portConfig
->identifier
, FUNCTION_LOG
, NULL
, NULL
, baudRates
[BAUD_921600
], MODE_TX
, SERIAL_NOT_INVERTED
);
92 // Initialization done
93 LOG_I(SYSTEM
, "%s/%s %s %s / %s (%s)",
103 static void logPutcp(void *p
, char ch
)
105 *(*((char **) p
))++ = ch
;
108 static void logPrint(const char *buf
, size_t size
)
110 #if defined(SEMIHOSTING)
111 static bool semihostingInitialized
= false;
112 extern void initialise_monitor_handles(void);
114 if (!semihostingInitialized
) {
115 initialise_monitor_handles();
116 semihostingInitialized
= true;
118 for (size_t ii
= 0; ii
< size
; ii
++) {
119 fputc(buf
[ii
], stdout
);
123 // Send data via UART (if configured & connected - a safeguard against zombie VCP)
124 if (serialIsConnected(logPort
)) {
125 serialPrint(logPort
, buf
);
127 } else if (mspLogPort
) {
128 mspSerialPushPort(MSP_DEBUGMSG
, (uint8_t*)buf
, size
, mspLogPort
, MSP_V2_NATIVE
);
132 static size_t logFormatPrefix(char *buf
, const timeMs_t timeMs
)
135 return tfp_sprintf(buf
, LOG_PREFIX
, (int)(timeMs
/ 1000), (int)(timeMs
% 1000));
138 static bool logHasOutput(void)
140 #if defined(SEMIHOSTING)
143 return logPort
|| mspLogPort
;
147 static bool logIsEnabled(logTopic_e topic
, unsigned level
)
149 return logHasOutput() && (level
<= logConfig()->level
|| (logConfig()->topics
& (1 << topic
)));
152 void _logf(logTopic_e topic
, unsigned level
, const char *fmt
, ...)
158 STATIC_ASSERT(MSP_PORT_OUTBUF_SIZE
>= sizeof(buf
), MSP_PORT_OUTBUF_SIZE_not_big_enough_for_log
);
160 if (!logIsEnabled(topic
, level
)) {
164 charCount
= logFormatPrefix(buf
, millis());
165 bufPtr
= &buf
[charCount
];
170 charCount
+= tfp_format(&bufPtr
, logPutcp
, fmt
, va
);
171 logPutcp(&bufPtr
, '\n');
172 logPutcp(&bufPtr
, 0);
176 logPrint(buf
, charCount
);
179 void _logBufferHex(logTopic_e topic
, unsigned level
, const void *buffer
, size_t size
)
181 // Print lines of up to maxBytes bytes. We need 5 characters per byte
183 const size_t charsPerByte
= 5;
184 const size_t maxBytes
= 8;
185 char buf
[LOG_PREFIX_FORMATTED_SIZE
+ charsPerByte
* maxBytes
+ 1]; // +1 for the null terminator
186 size_t bufPos
= LOG_PREFIX_FORMATTED_SIZE
;
187 const uint8_t *inputPtr
= buffer
;
189 if (!logIsEnabled(topic
, level
)) {
193 logFormatPrefix(buf
, millis());
195 for (size_t ii
= 0; ii
< size
; ii
++) {
196 tfp_sprintf(buf
+ bufPos
, "0x%02x ", inputPtr
[ii
]);
197 bufPos
+= charsPerByte
;
198 if (bufPos
== sizeof(buf
)-1) {
199 buf
[bufPos
-1] = '\n';
201 logPrint(buf
, bufPos
+ 1);
202 bufPos
= LOG_PREFIX_FORMATTED_SIZE
;
206 if (bufPos
> LOG_PREFIX_FORMATTED_SIZE
) {
207 buf
[bufPos
-1] = '\n';
209 logPrint(buf
, bufPos
+ 1);