Fix WS2812 led definition
[inav.git] / src / main / common / log.c
blob20faa4a53db7068bf9b36c149134474617387a4b
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stdarg.h>
21 #include <ctype.h>
23 #if defined(SEMIHOSTING)
24 #include <stdio.h>
25 #endif
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"
44 #include "msp/msp.h"
45 #include "msp/msp_serial.h"
46 #include "msp/msp_protocol.h"
48 #if defined(USE_LOG)
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
63 void logInit(void)
65 const serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_LOG);
66 if (!portConfig) {
67 return;
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)) {
75 return;
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);
83 if (!logAndMspPort) {
84 return;
87 mspLogPort = mspSerialPortFind(logAndMspPort);
88 if (!mspLogPort) {
89 return;
92 } else {
93 logPort = openSerialPort(portConfig->identifier, FUNCTION_LOG, NULL, NULL, baudRates[BAUD_921600], MODE_TX, SERIAL_NOT_INVERTED);
94 if (!logPort) {
95 return;
98 // Initialization done
99 LOG_INFO(SYSTEM, "%s/%s %s %s / %s (%s)",
100 FC_FIRMWARE_NAME,
101 targetName,
102 FC_VERSION_STRING,
103 buildDate,
104 buildTime,
105 shortGitRevision
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);
127 #endif
128 if (logPort) {
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)
140 // Write timestamp
141 return tfp_sprintf(buf, LOG_PREFIX, (int)(timeMs / 1000), (int)(timeMs % 1000));
144 static bool logHasOutput(void)
146 #if defined(SEMIHOSTING)
147 return true;
148 #else
149 return logPort || mspLogPort;
150 #endif
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, ...)
160 char buf[128];
161 char *bufPtr;
162 int charCount;
164 STATIC_ASSERT(MSP_PORT_OUTBUF_SIZE >= sizeof(buf), MSP_PORT_OUTBUF_SIZE_not_big_enough_for_log);
166 if (!logIsEnabled(topic, level)) {
167 return;
170 charCount = logFormatPrefix(buf, millis());
171 bufPtr = &buf[charCount];
173 // Write message
174 va_list va;
175 va_start(va, fmt);
176 charCount += tfp_format(&bufPtr, logPutcp, fmt, va);
177 logPutcp(&bufPtr, '\n');
178 logPutcp(&bufPtr, 0);
179 charCount += 2;
180 va_end(va);
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
188 // 0xAB[space|\n]
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)) {
196 return;
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';
206 buf[bufPos] = '\0';
207 logPrint(buf, bufPos + 1);
208 bufPos = LOG_PREFIX_FORMATTED_SIZE;
212 if (bufPos > LOG_PREFIX_FORMATTED_SIZE) {
213 buf[bufPos-1] = '\n';
214 buf[bufPos] = '\0';
215 logPrint(buf, bufPos + 1);
219 #endif