Merge branch 'master' into tft-gui-work

This commit is contained in:
Manuel 2024-07-01 12:40:40 +02:00 committed by GitHub
commit 08c77a9c29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 208 additions and 141 deletions

View File

@ -77,6 +77,7 @@ build_flags = -Wno-missing-field-initializers
-DMESHTASTIC_EXCLUDE_DROPZONE=1 -DMESHTASTIC_EXCLUDE_DROPZONE=1
monitor_speed = 115200 monitor_speed = 115200
monitor_filters = direct
lib_deps = lib_deps =
jgromes/RadioLib@~6.6.0 jgromes/RadioLib@~6.6.0

View File

@ -15,11 +15,6 @@
#include "platform/portduino/PortduinoGlue.h" #include "platform/portduino/PortduinoGlue.h"
#endif #endif
/**
* A printer that doesn't go anywhere
*/
NoopPrint noopPrint;
#if HAS_WIFI || HAS_ETHERNET #if HAS_WIFI || HAS_ETHERNET
extern Syslog syslog; extern Syslog syslog;
#endif #endif
@ -39,7 +34,7 @@ void RedirectablePrint::setDestination(Print *_dest)
size_t RedirectablePrint::write(uint8_t c) size_t RedirectablePrint::write(uint8_t c)
{ {
// Always send the characters to our segger JTAG debugger // Always send the characters to our segger JTAG debugger
#ifdef SEGGER_STDOUT_CH #ifdef USE_SEGGER
SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c); SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c);
#endif #endif
@ -85,6 +80,134 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l
return len; return len;
} }
void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, va_list arg)
{
size_t r = 0;
// Cope with 0 len format strings, but look for new line terminator
bool hasNewline = *format && format[strlen(format) - 1] == '\n';
// If we are the first message on a report, include the header
if (!isContinuationMessage) {
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
Print::write("\u001b[34m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
Print::write("\u001b[32m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
Print::write("\u001b[33m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0)
Print::write("\u001b[31m", 6);
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile
if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR;
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
// Tear apart hms into h:m:s
int hour = hms / SEC_PER_HOUR;
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
#ifdef ARCH_PORTDUINO
::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000);
#else
printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000);
#endif
} else
#ifdef ARCH_PORTDUINO
::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000);
#else
printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000);
#endif
auto thread = concurrency::OSThread::currentThread;
if (thread) {
print("[");
// printf("%p ", thread);
// assert(thread->ThreadName.length());
print(thread->ThreadName);
print("] ");
}
}
r += vprintf(logLevel, format, arg);
isContinuationMessage = !hasNewline;
}
void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, va_list arg)
{
#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO)
// if syslog is in use, collect the log messages and send them to syslog
if (syslog.isEnabled()) {
int ll = 0;
switch (logLevel[0]) {
case 'D':
ll = SYSLOG_DEBUG;
break;
case 'I':
ll = SYSLOG_INFO;
break;
case 'W':
ll = SYSLOG_WARN;
break;
case 'E':
ll = SYSLOG_ERR;
break;
case 'C':
ll = SYSLOG_CRIT;
break;
default:
ll = 0;
}
auto thread = concurrency::OSThread::currentThread;
if (thread) {
syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg);
} else {
syslog.vlogf(ll, format, arg);
}
}
#endif
}
void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_list arg)
{
if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) {
bool isBleConnected = false;
#ifdef ARCH_ESP32
isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected();
#elif defined(ARCH_NRF52)
isBleConnected = nrf52Bluetooth != nullptr && nrf52Bluetooth->isConnected();
#endif
if (isBleConnected) {
char *message;
size_t initialLen;
size_t len;
initialLen = strlen(format);
message = new char[initialLen + 1];
len = vsnprintf(message, initialLen + 1, format, arg);
if (len > initialLen) {
delete[] message;
message = new char[len + 1];
vsnprintf(message, len + 1, format, arg);
}
auto thread = concurrency::OSThread::currentThread;
#ifdef ARCH_ESP32
if (thread)
nimbleBluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str());
else
nimbleBluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str());
#elif defined(ARCH_NRF52)
if (thread)
nrf52Bluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str());
else
nrf52Bluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str());
#endif
delete[] message;
}
}
}
void RedirectablePrint::log(const char *logLevel, const char *format, ...) void RedirectablePrint::log(const char *logLevel, const char *format, ...)
{ {
#ifdef ARCH_PORTDUINO #ifdef ARCH_PORTDUINO
@ -109,122 +232,10 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
va_list arg; va_list arg;
va_start(arg, format); va_start(arg, format);
// Cope with 0 len format strings, but look for new line terminator log_to_serial(logLevel, format, arg);
bool hasNewline = *format && format[strlen(format) - 1] == '\n'; log_to_syslog(logLevel, format, arg);
log_to_ble(logLevel, format, arg);
// If we are the first message on a report, include the header
if (!isContinuationMessage) {
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
Print::write("\u001b[34m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
Print::write("\u001b[32m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
Print::write("\u001b[33m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0)
Print::write("\u001b[31m", 6);
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile
if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR;
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
// Tear apart hms into h:m:s
int hour = hms / SEC_PER_HOUR;
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
#ifdef ARCH_PORTDUINO
::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000);
#else
printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000);
#endif
} else
#ifdef ARCH_PORTDUINO
::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000);
#else
printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000);
#endif
auto thread = concurrency::OSThread::currentThread;
if (thread) {
print("[");
// printf("%p ", thread);
// assert(thread->ThreadName.length());
print(thread->ThreadName);
print("] ");
}
}
vprintf(logLevel, format, arg);
#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO)
// if syslog is in use, collect the log messages and send them to syslog
if (syslog.isEnabled()) {
int ll = 0;
switch (logLevel[0]) {
case 'D':
ll = SYSLOG_DEBUG;
break;
case 'I':
ll = SYSLOG_INFO;
break;
case 'W':
ll = SYSLOG_WARN;
break;
case 'E':
ll = SYSLOG_ERR;
break;
case 'C':
ll = SYSLOG_CRIT;
break;
default:
ll = 0;
}
auto thread = concurrency::OSThread::currentThread;
if (thread) {
syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg);
} else {
syslog.vlogf(ll, format, arg);
}
}
#endif
isContinuationMessage = !hasNewline;
if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) {
bool isBleConnected = false;
#ifdef ARCH_ESP32
isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected();
#elif defined(ARCH_NRF52)
isBleConnected = nrf52Bluetooth != nullptr && nrf52Bluetooth->isConnected();
#endif
if (isBleConnected) {
char *message;
size_t initialLen;
size_t len;
initialLen = strlen(format);
message = new char[initialLen + 1];
len = vsnprintf(message, initialLen + 1, format, arg);
if (len > initialLen) {
delete[] message;
message = new char[len + 1];
vsnprintf(message, len + 1, format, arg);
}
auto thread = concurrency::OSThread::currentThread;
#ifdef ARCH_ESP32
if (thread)
nimbleBluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str());
else
nimbleBluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str());
#elif defined(ARCH_NRF52)
if (thread)
nrf52Bluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str());
else
nrf52Bluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str());
#endif
delete[] message;
}
}
va_end(arg); va_end(arg);
#ifdef HAS_FREE_RTOS #ifdef HAS_FREE_RTOS
xSemaphoreGive(inDebugPrint); xSemaphoreGive(inDebugPrint);

View File

@ -49,15 +49,12 @@ class RedirectablePrint : public Print
void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); void hexDump(const char *logLevel, unsigned char *buf, uint16_t len);
std::string mt_sprintf(const std::string fmt_str, ...); std::string mt_sprintf(const std::string fmt_str, ...);
};
class NoopPrint : public Print protected:
{ /// Subclasses can override if they need to change how we format over the serial port
public: virtual void log_to_serial(const char *logLevel, const char *format, va_list arg);
virtual size_t write(uint8_t c) { return 1; }
};
/** private:
* A printer that doesn't go anywhere void log_to_syslog(const char *logLevel, const char *format, va_list arg);
*/ void log_to_ble(const char *logLevel, const char *format, va_list arg);
extern NoopPrint noopPrint; };

View File

@ -34,7 +34,6 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
assert(!console); assert(!console);
console = this; console = this;
canWrite = false; // We don't send packets to our port until it has talked to us first canWrite = false; // We don't send packets to our port until it has talked to us first
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
#ifdef RP2040_SLOW_CLOCK #ifdef RP2040_SLOW_CLOCK
Port.setTX(SERIAL2_TX); Port.setTX(SERIAL2_TX);
@ -81,9 +80,8 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
{ {
// only talk to the API once the configuration has been loaded and we're sure the serial port is not disabled. // only talk to the API once the configuration has been loaded and we're sure the serial port is not disabled.
if (config.has_lora && config.device.serial_enabled) { if (config.has_lora && config.device.serial_enabled) {
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets // Switch to protobufs for log messages
if (!config.device.debug_log_enabled) usingProtobufs = true;
setDestination(&noopPrint);
canWrite = true; canWrite = true;
return StreamAPI::handleToRadio(buf, len); return StreamAPI::handleToRadio(buf, len);
@ -91,3 +89,31 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
return false; return false;
} }
} }
void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_list arg)
{
if (usingProtobufs) {
meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset
switch (logLevel[0]) {
case 'D':
ll = meshtastic_LogRecord_Level_DEBUG;
break;
case 'I':
ll = meshtastic_LogRecord_Level_INFO;
break;
case 'W':
ll = meshtastic_LogRecord_Level_WARNING;
break;
case 'E':
ll = meshtastic_LogRecord_Level_ERROR;
break;
case 'C':
ll = meshtastic_LogRecord_Level_CRITICAL;
break;
}
auto thread = concurrency::OSThread::currentThread;
emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg);
} else
RedirectablePrint::log_to_serial(logLevel, format, arg);
}

View File

@ -8,6 +8,11 @@
*/ */
class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread
{ {
/**
* If true we are talking to a smart host and all messages (including log messages) must be framed as protobufs.
*/
bool usingProtobufs = false;
public: public:
SerialConsole(); SerialConsole();
@ -31,6 +36,9 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur
protected: protected:
/// Check the current underlying physical link to see if the client is currently connected /// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override; virtual bool checkIsConnected() override;
/// Possibly switch to protobufs if we see a valid protobuf message
virtual void log_to_serial(const char *logLevel, const char *format, va_list arg);
}; };
// A simple wrapper to allow non class aware code write to the console // A simple wrapper to allow non class aware code write to the console

View File

@ -236,7 +236,7 @@ void setup()
meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO; meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO;
OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64; OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64;
#ifdef SEGGER_STDOUT_CH #ifdef USE_SEGGER
auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM;
#ifdef NRF52840_XXAA #ifdef NRF52840_XXAA
auto buflen = 4096; // this board has a fair amount of ram auto buflen = 4096; // this board has a fair amount of ram

View File

@ -407,7 +407,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// Encapsulate as a FromRadio packet // Encapsulate as a FromRadio packet
size_t numbytes = pb_encode_to_bytes(buf, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch); size_t numbytes = pb_encode_to_bytes(buf, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch);
LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes); // VERY IMPORTANT to not print debug messages while writing to fromRadioScratch - because we use that same buffer
// for logging (when we are encapsulating with protobufs)
// LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes);
return numbytes; return numbytes;
} }

View File

@ -1,5 +1,6 @@
#include "StreamAPI.h" #include "StreamAPI.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "RTC.h"
#include "configuration.h" #include "configuration.h"
#define START1 0x94 #define START1 0x94
@ -96,7 +97,6 @@ void StreamAPI::writeStream()
void StreamAPI::emitTxBuffer(size_t len) void StreamAPI::emitTxBuffer(size_t len)
{ {
if (len != 0) { if (len != 0) {
// LOG_DEBUG("emit tx %d\n", len);
txBuf[0] = START1; txBuf[0] = START1;
txBuf[1] = START2; txBuf[1] = START2;
txBuf[2] = (len >> 8) & 0xff; txBuf[2] = (len >> 8) & 0xff;
@ -119,6 +119,25 @@ void StreamAPI::emitRebooted()
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch)); emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch));
} }
void StreamAPI::emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg)
{
// In case we send a FromRadio packet
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_log_record_tag;
fromRadioScratch.log_record.level = level;
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
fromRadioScratch.log_record.time = rtc_sec;
strncpy(fromRadioScratch.log_record.source, src, sizeof(fromRadioScratch.log_record.source) - 1);
auto num_printed =
vsnprintf(fromRadioScratch.log_record.message, sizeof(fromRadioScratch.log_record.message) - 1, format, arg);
if (num_printed > 0 && fromRadioScratch.log_record.message[num_printed - 1] ==
'\n') // Strip any ending newline, because we have records for framing instead.
fromRadioScratch.log_record.message[num_printed - 1] = '\0';
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch));
}
/// Hookable to find out when connection changes /// Hookable to find out when connection changes
void StreamAPI::onConnectionChanged(bool connected) void StreamAPI::onConnectionChanged(bool connected)
{ {

View File

@ -82,4 +82,7 @@ class StreamAPI : public PhoneAPI
/// Subclasses can use this scratch buffer if they wish /// Subclasses can use this scratch buffer if they wish
uint8_t txBuf[MAX_STREAM_BUF_SIZE] = {0}; uint8_t txBuf[MAX_STREAM_BUF_SIZE] = {0};
/// Low level function to emit a protobuf encapsulated log record
void emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg);
}; };