mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-10 20:07:45 +00:00
Compare commits
10 Commits
bme680
...
v2.7.15.56
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d18f3f7a65 | ||
|
|
6c09cf9d3d | ||
|
|
79a91578b7 | ||
|
|
17cd83085b | ||
|
|
b7bdcbe43e | ||
|
|
df063f40ff | ||
|
|
84bb1e33a6 | ||
|
|
955347bf50 | ||
|
|
4284fc2aec | ||
|
|
034aaa376a |
@@ -33,8 +33,6 @@ lib_deps =
|
|||||||
adafruit/Adafruit seesaw Library@1.7.9
|
adafruit/Adafruit seesaw Library@1.7.9
|
||||||
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
|
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
|
||||||
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
|
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
|
||||||
# renovate: datasource=custom.pio depName=adafruit/Adafruit BME680 Library packageName=adafruit/library/Adafruit BME680
|
|
||||||
adafruit/Adafruit BME680 Library@^2.0.5
|
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${arduino_base.build_flags}
|
${arduino_base.build_flags}
|
||||||
|
|||||||
@@ -87,6 +87,9 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.7.15" date="2025-11-13">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.15</url>
|
||||||
|
</release>
|
||||||
<release version="2.7.14" date="2025-11-03">
|
<release version="2.7.14" date="2025-11-03">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.14</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.14</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
|||||||
|
meshtasticd (2.7.15.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Version 2.7.15
|
||||||
|
|
||||||
|
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Thu, 13 Nov 2025 12:31:57 +0000
|
||||||
|
|
||||||
meshtasticd (2.7.14.0) unstable; urgency=medium
|
meshtasticd (2.7.14.0) unstable; urgency=medium
|
||||||
|
|
||||||
* Version 2.7.14
|
* Version 2.7.14
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level se
|
|||||||
|
|
||||||
#ifdef BATTERY_PIN
|
#ifdef BATTERY_PIN
|
||||||
|
|
||||||
static void adcEnable()
|
void battery_adcEnable()
|
||||||
{
|
{
|
||||||
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
||||||
#ifdef ADC_USE_PULLUP
|
#ifdef ADC_USE_PULLUP
|
||||||
@@ -214,7 +214,7 @@ static void adcEnable()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adcDisable()
|
static void battery_adcDisable()
|
||||||
{
|
{
|
||||||
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
|
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
|
||||||
#ifdef ADC_USE_PULLUP
|
#ifdef ADC_USE_PULLUP
|
||||||
@@ -320,7 +320,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
uint32_t raw = 0;
|
uint32_t raw = 0;
|
||||||
float scaled = 0;
|
float scaled = 0;
|
||||||
|
|
||||||
adcEnable();
|
battery_adcEnable();
|
||||||
#ifdef ARCH_ESP32 // ADC block for espressif platforms
|
#ifdef ARCH_ESP32 // ADC block for espressif platforms
|
||||||
raw = espAdcRead();
|
raw = espAdcRead();
|
||||||
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
||||||
@@ -332,7 +332,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
raw = raw / BATTERY_SENSE_SAMPLES;
|
raw = raw / BATTERY_SENSE_SAMPLES;
|
||||||
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
|
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
|
||||||
#endif
|
#endif
|
||||||
adcDisable();
|
battery_adcDisable();
|
||||||
|
|
||||||
if (!initial_read_done) {
|
if (!initial_read_done) {
|
||||||
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
||||||
@@ -906,13 +906,8 @@ void Power::readPowerStatus()
|
|||||||
low_voltage_counter++;
|
low_voltage_counter++;
|
||||||
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
|
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
|
||||||
if (low_voltage_counter > 10) {
|
if (low_voltage_counter > 10) {
|
||||||
#ifdef ARCH_NRF52
|
|
||||||
// We can't trigger deep sleep on NRF52, it's freezing the board
|
|
||||||
LOG_DEBUG("Low voltage detected, but not trigger deep sleep");
|
|
||||||
#else
|
|
||||||
LOG_INFO("Low voltage detected, trigger deep sleep");
|
LOG_INFO("Low voltage detected, trigger deep sleep");
|
||||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
low_voltage_counter = 0;
|
low_voltage_counter = 0;
|
||||||
@@ -1552,4 +1547,4 @@ bool Power::meshSolarInit()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -410,18 +410,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BME680 BSEC2 support detection
|
|
||||||
#if !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
|
||||||
#if defined(RAK_4631) || defined(TBEAM_V10)
|
|
||||||
|
|
||||||
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 1
|
|
||||||
#define MESHTASTIC_BME680_HEADER <bsec2.h>
|
|
||||||
#else
|
|
||||||
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 0
|
|
||||||
#define MESHTASTIC_BME680_HEADER <Adafruit_BME680.h>
|
|
||||||
#endif // defined(RAK_4631)
|
|
||||||
#endif // !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Global switches to turn off features for a minimized build
|
// Global switches to turn off features for a minimized build
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -240,6 +240,9 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
buffer[bytesRead] = b;
|
buffer[bytesRead] = b;
|
||||||
bytesRead++;
|
bytesRead++;
|
||||||
if ((bytesRead == 767) || (b == '\r')) {
|
if ((bytesRead == 767) || (b == '\r')) {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(debugmsg.c_str());
|
||||||
|
#endif
|
||||||
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG("Found: %s", message); // Log the found message
|
LOG_DEBUG("Found: %s", message); // Log the found message
|
||||||
@@ -247,9 +250,6 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
return GNSS_RESPONSE_OK;
|
return GNSS_RESPONSE_OK;
|
||||||
} else {
|
} else {
|
||||||
bytesRead = 0;
|
bytesRead = 0;
|
||||||
#ifdef GPS_DEBUG
|
|
||||||
LOG_DEBUG(debugmsg.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1275,6 +1275,24 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
memset(&ublox_info, 0, sizeof(ublox_info));
|
memset(&ublox_info, 0, sizeof(ublox_info));
|
||||||
delay(100);
|
delay(100);
|
||||||
|
|
||||||
|
#if defined(PIN_GPS_RESET) && PIN_GPS_RESET != -1
|
||||||
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||||
|
delay(10);
|
||||||
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
|
|
||||||
|
// attempt to detect the chip based on boot messages
|
||||||
|
std::vector<ChipInfo> passive_detect = {
|
||||||
|
{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
|
||||||
|
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
|
||||||
|
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352},
|
||||||
|
{"UC6580", "UC6580", GNSS_MODEL_UC6580},
|
||||||
|
// as L76K is sort of a last ditch effort, we won't attempt to detect it by startup messages for now.
|
||||||
|
/*{"L76K", "SW=URANUS", GNSS_MODEL_MTK}*/};
|
||||||
|
GnssModel_t detectedDriver = getProbeResponse(500, passive_detect, serialSpeed);
|
||||||
|
if (detectedDriver != GNSS_MODEL_UNKNOWN) {
|
||||||
|
return detectedDriver;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
||||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||||
delay(20);
|
delay(20);
|
||||||
@@ -1473,12 +1491,12 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
||||||
#ifdef GPS_DEBUG
|
|
||||||
LOG_DEBUG(response);
|
|
||||||
#endif
|
|
||||||
// check if we can see our chips
|
// check if we can see our chips
|
||||||
for (const auto &chipInfo : responseMap) {
|
for (const auto &chipInfo : responseMap) {
|
||||||
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(response);
|
||||||
|
#endif
|
||||||
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
||||||
delete[] response; // Cleanup before return
|
delete[] response; // Cleanup before return
|
||||||
return chipInfo.driver;
|
return chipInfo.driver;
|
||||||
@@ -1486,6 +1504,9 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(response);
|
||||||
|
#endif
|
||||||
// Reset the response buffer for the next potential message
|
// Reset the response buffer for the next potential message
|
||||||
responseLen = 0;
|
responseLen = 0;
|
||||||
response[0] = '\0';
|
response[0] = '\0';
|
||||||
@@ -1572,8 +1593,6 @@ GPS *GPS::createGps()
|
|||||||
|
|
||||||
#ifdef PIN_GPS_RESET
|
#ifdef PIN_GPS_RESET
|
||||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
|
||||||
delay(10);
|
|
||||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
#ifdef BUILD_EPOCH
|
#ifdef BUILD_EPOCH
|
||||||
if (tv.tv_sec < BUILD_EPOCH) {
|
if (tv.tv_sec < BUILD_EPOCH) {
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
||||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
LOG_WARN("Ignore time (%lu) before build epoch (%lu)!", printableEpoch, BUILD_EPOCH);
|
||||||
lastTimeValidationWarning = millis();
|
lastTimeValidationWarning = millis();
|
||||||
}
|
}
|
||||||
return RTCSetResultInvalidTime;
|
return RTCSetResultInvalidTime;
|
||||||
@@ -319,7 +319,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
// Calculate max allowed time safely to avoid overflow in logging
|
// Calculate max allowed time safely to avoid overflow in logging
|
||||||
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
||||||
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
||||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
LOG_WARN("Ignore time (%lu) too far in the future (build epoch: %lu, max allowed: %lu)!", printableEpoch,
|
||||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
||||||
lastTimeValidationWarning = millis();
|
lastTimeValidationWarning = millis();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,17 +194,12 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
||||||
int line = 0;
|
int line = 0;
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
|
||||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
|
||||||
graphics::ClockRenderer::drawBluetoothConnectedIcon(display, display->getWidth() - 18, display->getHeight() - 14);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone
|
||||||
char timeString[16];
|
char timeString[16];
|
||||||
int hour = 0;
|
int hour = 0;
|
||||||
int minute = 0;
|
int minute = 0;
|
||||||
int second = 0;
|
int second = 0;
|
||||||
|
|
||||||
if (rtc_sec > 0) {
|
if (rtc_sec > 0) {
|
||||||
long hms = rtc_sec % SEC_PER_DAY;
|
long hms = rtc_sec % SEC_PER_DAY;
|
||||||
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||||||
@@ -215,11 +210,11 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isPM = hour >= 12;
|
bool isPM = hour >= 12;
|
||||||
// hour = hour > 12 ? hour - 12 : hour;
|
|
||||||
if (config.display.use_12h_clock) {
|
if (config.display.use_12h_clock) {
|
||||||
hour %= 12;
|
hour %= 12;
|
||||||
if (hour == 0)
|
if (hour == 0) {
|
||||||
hour = 12;
|
hour = 12;
|
||||||
|
}
|
||||||
snprintf(timeString, sizeof(timeString), "%d:%02d", hour, minute);
|
snprintf(timeString, sizeof(timeString), "%d:%02d", hour, minute);
|
||||||
} else {
|
} else {
|
||||||
snprintf(timeString, sizeof(timeString), "%02d:%02d", hour, minute);
|
snprintf(timeString, sizeof(timeString), "%02d:%02d", hour, minute);
|
||||||
@@ -229,24 +224,56 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
char secondString[8];
|
char secondString[8];
|
||||||
snprintf(secondString, sizeof(secondString), "%02d", second);
|
snprintf(secondString, sizeof(secondString), "%02d", second);
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
static bool scaleInitialized = false;
|
||||||
float scale = 1.5;
|
static float scale = 0.75f;
|
||||||
#elif defined(CHATTER_2)
|
static float segmentWidth = SEGMENT_WIDTH * 0.75f;
|
||||||
float scale = 1.1;
|
static float segmentHeight = SEGMENT_HEIGHT * 0.75f;
|
||||||
#else
|
|
||||||
float scale = 0.75;
|
|
||||||
if (isHighResolution) {
|
|
||||||
scale = 1.5;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint16_t segmentWidth = SEGMENT_WIDTH * scale;
|
if (!scaleInitialized) {
|
||||||
uint16_t segmentHeight = SEGMENT_HEIGHT * scale;
|
float screenwidth_target_ratio = 0.80f; // Target 80% of display width (adjustable)
|
||||||
|
float max_scale = 3.5f; // Safety limit to avoid runaway scaling
|
||||||
|
float step = 0.05f; // Step increment per iteration
|
||||||
|
|
||||||
|
float target_width = display->getWidth() * screenwidth_target_ratio;
|
||||||
|
float target_height =
|
||||||
|
display->getHeight() -
|
||||||
|
(isHighResolution
|
||||||
|
? 46
|
||||||
|
: 33); // Be careful adjusting this number, we have to account for header and the text under the time
|
||||||
|
|
||||||
|
float calculated_width_size = 0.0f;
|
||||||
|
float calculated_height_size = 0.0f;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
segmentWidth = SEGMENT_WIDTH * scale;
|
||||||
|
segmentHeight = SEGMENT_HEIGHT * scale;
|
||||||
|
|
||||||
|
calculated_width_size = segmentHeight + ((segmentWidth + (segmentHeight * 2) + 4) * 4);
|
||||||
|
calculated_height_size = segmentHeight + ((segmentHeight + (segmentHeight * 2) + 4) * 2);
|
||||||
|
|
||||||
|
if (calculated_width_size >= target_width || calculated_height_size >= target_height || scale >= max_scale) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale += step;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we overshot width, back off one step and recompute segment sizes
|
||||||
|
if (calculated_width_size > target_width || calculated_height_size > target_height) {
|
||||||
|
scale -= step;
|
||||||
|
segmentWidth = SEGMENT_WIDTH * scale;
|
||||||
|
segmentHeight = SEGMENT_HEIGHT * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(timeString);
|
||||||
|
|
||||||
// calculate hours:minutes string width
|
// calculate hours:minutes string width
|
||||||
uint16_t timeStringWidth = strlen(timeString) * 5;
|
uint16_t timeStringWidth = len * 5; // base spacing between characters
|
||||||
|
|
||||||
for (uint8_t i = 0; i < strlen(timeString); i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
char character = timeString[i];
|
char character = timeString[i];
|
||||||
|
|
||||||
if (character == ':') {
|
if (character == ':') {
|
||||||
@@ -257,19 +284,21 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t hourMinuteTextX = (display->getWidth() / 2) - (timeStringWidth / 2);
|
uint16_t hourMinuteTextX = (display->getWidth() / 2) - (timeStringWidth / 2);
|
||||||
|
|
||||||
uint16_t startingHourMinuteTextX = hourMinuteTextX;
|
uint16_t startingHourMinuteTextX = hourMinuteTextX;
|
||||||
|
|
||||||
uint16_t hourMinuteTextY = (display->getHeight() / 2) - (((segmentWidth * 2) + (segmentHeight * 3) + 8) / 2);
|
uint16_t hourMinuteTextY = (display->getHeight() / 2) - (((segmentWidth * 2) + (segmentHeight * 3) + 8) / 2) + 2;
|
||||||
|
|
||||||
// iterate over characters in hours:minutes string and draw segmented characters
|
// iterate over characters in hours:minutes string and draw segmented characters
|
||||||
for (uint8_t i = 0; i < strlen(timeString); i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
char character = timeString[i];
|
char character = timeString[i];
|
||||||
|
|
||||||
if (character == ':') {
|
if (character == ':') {
|
||||||
drawSegmentedDisplayColon(display, hourMinuteTextX, hourMinuteTextY, scale);
|
drawSegmentedDisplayColon(display, hourMinuteTextX, hourMinuteTextY, scale);
|
||||||
|
|
||||||
hourMinuteTextX += segmentHeight + 6;
|
hourMinuteTextX += segmentHeight + 6;
|
||||||
|
if (scale >= 2.0f) {
|
||||||
|
hourMinuteTextX += (uint16_t)(4.5f * scale);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
drawSegmentedDisplayCharacter(display, hourMinuteTextX, hourMinuteTextY, character - '0', scale);
|
drawSegmentedDisplayCharacter(display, hourMinuteTextX, hourMinuteTextY, character - '0', scale);
|
||||||
|
|
||||||
@@ -279,38 +308,29 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
hourMinuteTextX += 5;
|
hourMinuteTextX += 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw seconds string
|
// draw seconds string + AM/PM
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
int xOffset = (isHighResolution) ? 0 : -1;
|
int xOffset = (isHighResolution) ? 0 : -1;
|
||||||
if (hour >= 10) {
|
if (hour >= 10) {
|
||||||
xOffset += (isHighResolution) ? 32 : 18;
|
xOffset += (isHighResolution) ? 32 : 18;
|
||||||
}
|
}
|
||||||
int yOffset = (isHighResolution) ? 3 : 1;
|
|
||||||
#ifdef SENSECAP_INDICATOR
|
|
||||||
yOffset -= 3;
|
|
||||||
#endif
|
|
||||||
#ifdef T_DECK
|
|
||||||
yOffset -= 5;
|
|
||||||
#endif
|
|
||||||
if (config.display.use_12h_clock) {
|
if (config.display.use_12h_clock) {
|
||||||
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2,
|
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - 1, isPM ? "pm" : "am");
|
||||||
isPM ? "pm" : "am");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USE_EINK
|
#ifndef USE_EINK
|
||||||
xOffset = (isHighResolution) ? 18 : 10;
|
xOffset = (isHighResolution) ? 18 : 10;
|
||||||
display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - yOffset,
|
if (scale >= 2.0f) {
|
||||||
|
xOffset -= (int)(4.5f * scale);
|
||||||
|
}
|
||||||
|
display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - 1,
|
||||||
secondString);
|
secondString);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
graphics::drawCommonFooter(display, x, y);
|
graphics::drawCommonFooter(display, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y)
|
|
||||||
{
|
|
||||||
display->drawFastImage(x, y, 18, 14, bluetoothConnectedIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw an analog clock
|
// Draw an analog clock
|
||||||
void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
@@ -321,11 +341,6 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
||||||
int line = 0;
|
int line = 0;
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
|
||||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
|
||||||
drawBluetoothConnectedIcon(display, display->getWidth() - 18, display->getHeight() - 14);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// clock face center coordinates
|
// clock face center coordinates
|
||||||
int16_t centerX = display->getWidth() / 2;
|
int16_t centerX = display->getWidth() / 2;
|
||||||
int16_t centerY = display->getHeight() / 2;
|
int16_t centerY = display->getHeight() / 2;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ void drawVerticalSegment(OLEDDisplay *display, int x, int y, int width, int heig
|
|||||||
|
|
||||||
// UI elements for clock displays
|
// UI elements for clock displays
|
||||||
// void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode = true, float scale = 1);
|
// void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode = true, float scale = 1);
|
||||||
void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y);
|
|
||||||
|
|
||||||
} // namespace ClockRenderer
|
} // namespace ClockRenderer
|
||||||
|
|
||||||
|
|||||||
@@ -581,11 +581,8 @@ void menuHandler::systemBaseMenu()
|
|||||||
|
|
||||||
optionsArray[options] = "Notifications";
|
optionsArray[options] = "Notifications";
|
||||||
optionsEnumArray[options++] = Notifications;
|
optionsEnumArray[options++] = Notifications;
|
||||||
#if defined(ST7789_CS) || defined(ST7796_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || \
|
|
||||||
defined(USE_SH1107) || defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
|
||||||
optionsArray[options] = "Display Options";
|
optionsArray[options] = "Display Options";
|
||||||
optionsEnumArray[options++] = ScreenOptions;
|
optionsEnumArray[options++] = ScreenOptions;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
optionsArray[options] = "Bluetooth";
|
optionsArray[options] = "Bluetooth";
|
||||||
@@ -785,17 +782,24 @@ void menuHandler::nodeNameLengthMenu()
|
|||||||
|
|
||||||
void menuHandler::resetNodeDBMenu()
|
void menuHandler::resetNodeDBMenu()
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
static const char *optionsArray[] = {"Back", "Reset All", "Preserve Favorites"};
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Confirm Reset NodeDB";
|
bannerOptions.message = "Confirm Reset NodeDB";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 2;
|
bannerOptions.optionsCount = 3;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
if (selected == 1) {
|
if (selected == 1 || selected == 2) {
|
||||||
disableBluetooth();
|
disableBluetooth();
|
||||||
|
screen->setFrames(Screen::FOCUS_DEFAULT);
|
||||||
|
}
|
||||||
|
if (selected == 1) {
|
||||||
LOG_INFO("Initiate node-db reset");
|
LOG_INFO("Initiate node-db reset");
|
||||||
nodeDB->resetNodes();
|
nodeDB->resetNodes();
|
||||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||||
|
} else if (selected == 2) {
|
||||||
|
LOG_INFO("Initiate node-db reset but keeping favorites");
|
||||||
|
nodeDB->resetNodes(1);
|
||||||
|
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ void NeighborInfoModule::printNodeDBNeighbors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
|
/* Send our initial owner announcement 35 seconds after we start (to give
|
||||||
|
* network time to setup) */
|
||||||
NeighborInfoModule::NeighborInfoModule()
|
NeighborInfoModule::NeighborInfoModule()
|
||||||
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
||||||
concurrency::OSThread("NeighborInfo")
|
concurrency::OSThread("NeighborInfo")
|
||||||
@@ -53,8 +54,8 @@ NeighborInfoModule::NeighborInfoModule()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
Collect neighbor info from the nodeDB's history, capping at a maximum number of
|
||||||
Assumes that the neighborInfo packet has been allocated
|
entries and max time Assumes that the neighborInfo packet has been allocated
|
||||||
@returns the number of entries collected
|
@returns the number of entries collected
|
||||||
*/
|
*/
|
||||||
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
||||||
@@ -71,8 +72,8 @@ uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighb
|
|||||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (nbr.node_id != my_node_id)) {
|
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (nbr.node_id != my_node_id)) {
|
||||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = nbr.node_id;
|
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = nbr.node_id;
|
||||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = nbr.snr;
|
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = nbr.snr;
|
||||||
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
|
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs
|
||||||
// the mesh
|
// here, because we don't want to send this over the mesh
|
||||||
neighborInfo->neighbors_count++;
|
neighborInfo->neighbors_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,8 +89,9 @@ void NeighborInfoModule::cleanUpNeighbors()
|
|||||||
uint32_t now = getTime();
|
uint32_t now = getTime();
|
||||||
NodeNum my_node_id = nodeDB->getNodeNum();
|
NodeNum my_node_id = nodeDB->getNodeNum();
|
||||||
for (auto it = neighbors.rbegin(); it != neighbors.rend();) {
|
for (auto it = neighbors.rbegin(); it != neighbors.rend();) {
|
||||||
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
// We will remove a neighbor if we haven't heard from them in twice the
|
||||||
// cannot use isWithinTimespanMs() as it->last_rx_time is seconds since 1970
|
// broadcast interval cannot use isWithinTimespanMs() as it->last_rx_time is
|
||||||
|
// seconds since 1970
|
||||||
if ((now - it->last_rx_time > it->node_broadcast_interval_secs * 2) && (it->node_id != my_node_id)) {
|
if ((now - it->last_rx_time > it->node_broadcast_interval_secs * 2) && (it->node_id != my_node_id)) {
|
||||||
LOG_DEBUG("Remove neighbor with node ID 0x%x", it->node_id);
|
LOG_DEBUG("Remove neighbor with node ID 0x%x", it->node_id);
|
||||||
it = std::vector<meshtastic_Neighbor>::reverse_iterator(
|
it = std::vector<meshtastic_Neighbor>::reverse_iterator(
|
||||||
@@ -132,25 +134,55 @@ int32_t NeighborInfoModule::runOnce()
|
|||||||
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_neighbor_info_broadcast_secs);
|
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_neighbor_info_broadcast_secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *NeighborInfoModule::allocReply()
|
||||||
|
{
|
||||||
|
LOG_INFO("NeighborInfoRequested.");
|
||||||
|
if (lastSentReply && Throttle::isWithinTimespanMs(lastSentReply, 3 * 60 * 1000)) {
|
||||||
|
LOG_DEBUG("Skip Neighbors reply since we sent a reply <3min ago");
|
||||||
|
ignoreRequest = true; // Mark it as ignored for MeshModule
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
meshtastic_NeighborInfo neighborInfo = meshtastic_NeighborInfo_init_zero;
|
||||||
|
collectNeighborInfo(&neighborInfo);
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *reply = allocDataProtobuf(neighborInfo);
|
||||||
|
|
||||||
|
if (reply) {
|
||||||
|
lastSentReply = millis(); // Track when we sent this reply
|
||||||
|
}
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect a received neighbor info packet from another node
|
Collect a received neighbor info packet from another node
|
||||||
Pass it to an upper client; do not persist this data on the mesh
|
Pass it to an upper client; do not persist this data on the mesh
|
||||||
*/
|
*/
|
||||||
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
|
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
|
||||||
{
|
{
|
||||||
|
LOG_DEBUG("NeighborInfo: handleReceivedProtobuf");
|
||||||
if (np) {
|
if (np) {
|
||||||
printNeighborInfo("RECEIVED", np);
|
printNeighborInfo("RECEIVED", np);
|
||||||
updateNeighbors(mp, np);
|
// Ignore dummy/interceptable packets: single neighbor with nodeId 0 and snr 0
|
||||||
|
if (np->neighbors_count != 1 || np->neighbors[0].node_id != 0 || np->neighbors[0].snr != 0.0f) {
|
||||||
|
LOG_DEBUG(" Updating neighbours");
|
||||||
|
updateNeighbors(mp, np);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(" Ignoring dummy neighbor info packet (single neighbor with nodeId 0, snr 0)");
|
||||||
|
}
|
||||||
} else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
|
} else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
|
||||||
|
LOG_DEBUG("Get or create neighbor: %u with snr %f", mp.from, mp.rx_snr);
|
||||||
// If the hopLimit is the same as hopStart, then it is a neighbor
|
// If the hopLimit is the same as hopStart, then it is a neighbor
|
||||||
getOrCreateNeighbor(mp.from, mp.from, 0, mp.rx_snr); // Set the broadcast interval to 0, as we don't know it
|
getOrCreateNeighbor(mp.from, mp.from, 0,
|
||||||
|
mp.rx_snr); // Set the broadcast interval to 0, as we don't know it
|
||||||
}
|
}
|
||||||
// Allow others to handle this packet
|
// Allow others to handle this packet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copy the content of a current NeighborInfo packet into a new one and update the last_sent_by_id to our NodeNum
|
Copy the content of a current NeighborInfo packet into a new one and update the
|
||||||
|
last_sent_by_id to our NodeNum
|
||||||
*/
|
*/
|
||||||
void NeighborInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_NeighborInfo *n)
|
void NeighborInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_NeighborInfo *n)
|
||||||
{
|
{
|
||||||
@@ -168,8 +200,10 @@ void NeighborInfoModule::resetNeighbors()
|
|||||||
|
|
||||||
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
||||||
{
|
{
|
||||||
// The last sent ID will be 0 if the packet is from the phone, which we don't count as
|
LOG_DEBUG("updateNeighbors");
|
||||||
// an edge. So we assume that if it's zero, then this packet is from our node.
|
// The last sent ID will be 0 if the packet is from the phone, which we don't
|
||||||
|
// count as an edge. So we assume that if it's zero, then this packet is from
|
||||||
|
// our node.
|
||||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
||||||
getOrCreateNeighbor(mp.from, np->last_sent_by_id, np->node_broadcast_interval_secs, mp.rx_snr);
|
getOrCreateNeighbor(mp.from, np->last_sent_by_id, np->node_broadcast_interval_secs, mp.rx_snr);
|
||||||
}
|
}
|
||||||
@@ -188,7 +222,8 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
|
|||||||
// if found, update it
|
// if found, update it
|
||||||
neighbors[i].snr = snr;
|
neighbors[i].snr = snr;
|
||||||
neighbors[i].last_rx_time = getTime();
|
neighbors[i].last_rx_time = getTime();
|
||||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
// Only if this is the original sender, the broadcast interval corresponds
|
||||||
|
// to it
|
||||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||||
neighbors[i].node_broadcast_interval_secs = node_broadcast_interval_secs;
|
neighbors[i].node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||||
return &neighbors[i];
|
return &neighbors[i];
|
||||||
@@ -200,10 +235,12 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
|
|||||||
new_nbr.node_id = n;
|
new_nbr.node_id = n;
|
||||||
new_nbr.snr = snr;
|
new_nbr.snr = snr;
|
||||||
new_nbr.last_rx_time = getTime();
|
new_nbr.last_rx_time = getTime();
|
||||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
// Only if this is the original sender, the broadcast interval corresponds to
|
||||||
|
// it
|
||||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||||
new_nbr.node_broadcast_interval_secs = node_broadcast_interval_secs;
|
new_nbr.node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||||
else // Assume the same broadcast interval as us for the neighbor if we don't know it
|
else // Assume the same broadcast interval as us for the neighbor if we don't
|
||||||
|
// know it
|
||||||
new_nbr.node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
new_nbr.node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||||
|
|
||||||
if (neighbors.size() < MAX_NUM_NEIGHBORS) {
|
if (neighbors.size() < MAX_NUM_NEIGHBORS) {
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
|||||||
*/
|
*/
|
||||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override;
|
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override;
|
||||||
|
|
||||||
|
/* Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||||
|
virtual meshtastic_MeshPacket *allocReply() override;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
* Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
||||||
* @return the number of entries collected
|
* @return the number of entries collected
|
||||||
@@ -66,5 +70,8 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
|||||||
/* These are for debugging only */
|
/* These are for debugging only */
|
||||||
void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
|
void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
|
||||||
void printNodeDBNeighbors();
|
void printNodeDBNeighbors();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t lastSentReply = 0; // Last time we sent a position reply (used for reply throttling only)
|
||||||
};
|
};
|
||||||
extern NeighborInfoModule *neighborInfoModule;
|
extern NeighborInfoModule *neighborInfoModule;
|
||||||
@@ -53,7 +53,7 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
|||||||
#include "Sensor/LTR390UVSensor.h"
|
#include "Sensor/LTR390UVSensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(MESHTASTIC_BME680_HEADER)
|
#if __has_include(<bsec2.h>)
|
||||||
#include "Sensor/BME680Sensor.h"
|
#include "Sensor/BME680Sensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
#if __has_include(<Adafruit_LTR390.h>)
|
#if __has_include(<Adafruit_LTR390.h>)
|
||||||
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
|
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(MESHTASTIC_BME680_HEADER)
|
#if __has_include(<bsec2.h>)
|
||||||
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
|
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<Adafruit_BMP280.h>)
|
#if __has_include(<Adafruit_BMP280.h>)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<bsec2.h>)
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "BME680Sensor.h"
|
#include "BME680Sensor.h"
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
int32_t BME680Sensor::runOnce()
|
int32_t BME680Sensor::runOnce()
|
||||||
{
|
{
|
||||||
if (!bme680.run()) {
|
if (!bme680.run()) {
|
||||||
@@ -18,13 +17,10 @@ int32_t BME680Sensor::runOnce()
|
|||||||
}
|
}
|
||||||
return 35;
|
return 35;
|
||||||
}
|
}
|
||||||
#endif // defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
|
||||||
|
|
||||||
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
{
|
{
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
if (!bme680.begin(dev->address.address, *bus))
|
if (!bme680.begin(dev->address.address, *bus))
|
||||||
checkStatus("begin");
|
checkStatus("begin");
|
||||||
|
|
||||||
@@ -46,25 +42,12 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
if (status == 0)
|
if (status == 0)
|
||||||
LOG_DEBUG("BME680Sensor::runOnce: bme680.status %d", bme680.status);
|
LOG_DEBUG("BME680Sensor::runOnce: bme680.status %d", bme680.status);
|
||||||
|
|
||||||
#else
|
|
||||||
bme680 = makeBME680(bus);
|
|
||||||
|
|
||||||
if (!bme680->begin(dev->address.address)) {
|
|
||||||
LOG_ERROR("Init sensor: %s failed at begin()", sensorName);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = 1;
|
|
||||||
|
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
|
|
||||||
initI2CSensor();
|
initI2CSensor();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
{
|
{
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
|
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -82,27 +65,9 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
// Check if we need to save state to filesystem (every STATE_SAVE_PERIOD ms)
|
// Check if we need to save state to filesystem (every STATE_SAVE_PERIOD ms)
|
||||||
measurement->variant.environment_metrics.iaq = bme680.getData(BSEC_OUTPUT_IAQ).signal;
|
measurement->variant.environment_metrics.iaq = bme680.getData(BSEC_OUTPUT_IAQ).signal;
|
||||||
updateState();
|
updateState();
|
||||||
#else
|
|
||||||
if (!bme680->performReading()) {
|
|
||||||
LOG_ERROR("BME680Sensor::getMetrics: performReading failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
measurement->variant.environment_metrics.has_temperature = true;
|
|
||||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
|
||||||
measurement->variant.environment_metrics.has_barometric_pressure = true;
|
|
||||||
measurement->variant.environment_metrics.has_gas_resistance = true;
|
|
||||||
|
|
||||||
measurement->variant.environment_metrics.temperature = bme680->readTemperature();
|
|
||||||
measurement->variant.environment_metrics.relative_humidity = bme680->readHumidity();
|
|
||||||
measurement->variant.environment_metrics.barometric_pressure = bme680->readPressure() / 100.0F;
|
|
||||||
measurement->variant.environment_metrics.gas_resistance = bme680->readGas() / 1000.0;
|
|
||||||
|
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
void BME680Sensor::loadState()
|
void BME680Sensor::loadState()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
@@ -179,6 +144,5 @@ void BME680Sensor::checkStatus(const char *functionName)
|
|||||||
else if (bme680.sensor.status > BME68X_OK)
|
else if (bme680.sensor.status > BME68X_OK)
|
||||||
LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status);
|
LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status);
|
||||||
}
|
}
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,40 +1,23 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<bsec2.h>)
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
#include <bme68xLibrary.h>
|
|
||||||
#include <bsec2.h>
|
#include <bsec2.h>
|
||||||
#else
|
|
||||||
#include <Adafruit_BME680.h>
|
|
||||||
#include <memory>
|
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
|
|
||||||
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
|
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
const uint8_t bsec_config[] = {
|
const uint8_t bsec_config[] = {
|
||||||
#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
|
#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
|
||||||
};
|
};
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
class BME680Sensor : public TelemetrySensor
|
class BME680Sensor : public TelemetrySensor
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
Bsec2 bme680;
|
Bsec2 bme680;
|
||||||
#else
|
|
||||||
using BME680Ptr = std::unique_ptr<Adafruit_BME680>;
|
|
||||||
|
|
||||||
static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique<Adafruit_BME680>(bus); }
|
|
||||||
|
|
||||||
BME680Ptr bme680;
|
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
const char *bsecConfigFileName = "/prefs/bsec.dat";
|
const char *bsecConfigFileName = "/prefs/bsec.dat";
|
||||||
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
|
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
|
||||||
uint8_t accuracy = 0;
|
uint8_t accuracy = 0;
|
||||||
@@ -51,13 +34,10 @@ class BME680Sensor : public TelemetrySensor
|
|||||||
void loadState();
|
void loadState();
|
||||||
void updateState();
|
void updateState();
|
||||||
void checkStatus(const char *functionName);
|
void checkStatus(const char *functionName);
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BME680Sensor();
|
BME680Sensor();
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
|
||||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ constexpr int reconnectMax = 5;
|
|||||||
static uint8_t bytes[meshtastic_MqttClientProxyMessage_size + 30]; // 12 for channel name and 16 for nodeid
|
static uint8_t bytes[meshtastic_MqttClientProxyMessage_size + 30]; // 12 for channel name and 16 for nodeid
|
||||||
|
|
||||||
static bool isMqttServerAddressPrivate = false;
|
static bool isMqttServerAddressPrivate = false;
|
||||||
|
static bool isConnected = false;
|
||||||
|
|
||||||
inline void onReceiveProto(char *topic, byte *payload, size_t length)
|
inline void onReceiveProto(char *topic, byte *payload, size_t length)
|
||||||
{
|
{
|
||||||
@@ -320,8 +321,10 @@ bool connectPubSub(const PubSubConfig &config, PubSubClient &pubSub, Client &cli
|
|||||||
std::string nodeId = nodeDB->getNodeId();
|
std::string nodeId = nodeDB->getNodeId();
|
||||||
const bool connected = pubSub.connect(nodeId.c_str(), config.mqttUsername, config.mqttPassword);
|
const bool connected = pubSub.connect(nodeId.c_str(), config.mqttUsername, config.mqttPassword);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
|
isConnected = true;
|
||||||
LOG_INFO("MQTT connected");
|
LOG_INFO("MQTT connected");
|
||||||
} else {
|
} else {
|
||||||
|
isConnected = false;
|
||||||
LOG_WARN("Failed to connect to MQTT server");
|
LOG_WARN("Failed to connect to MQTT server");
|
||||||
}
|
}
|
||||||
return connected;
|
return connected;
|
||||||
@@ -507,6 +510,7 @@ bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, boo
|
|||||||
|
|
||||||
void MQTT::reconnect()
|
void MQTT::reconnect()
|
||||||
{
|
{
|
||||||
|
isConnected = false;
|
||||||
if (wantsLink()) {
|
if (wantsLink()) {
|
||||||
if (moduleConfig.mqtt.proxy_to_client_enabled) {
|
if (moduleConfig.mqtt.proxy_to_client_enabled) {
|
||||||
LOG_INFO("MQTT connect via client proxy instead");
|
LOG_INFO("MQTT connect via client proxy instead");
|
||||||
@@ -534,7 +538,7 @@ void MQTT::reconnect()
|
|||||||
runASAP = true;
|
runASAP = true;
|
||||||
reconnectCount = 0;
|
reconnectCount = 0;
|
||||||
isMqttServerAddressPrivate = isPrivateIpAddress(clientConnection->remoteIP());
|
isMqttServerAddressPrivate = isPrivateIpAddress(clientConnection->remoteIP());
|
||||||
|
isConnected = true;
|
||||||
publishNodeInfo();
|
publishNodeInfo();
|
||||||
sendSubscriptions();
|
sendSubscriptions();
|
||||||
} else {
|
} else {
|
||||||
@@ -688,7 +692,7 @@ void MQTT::publishNodeInfo()
|
|||||||
}
|
}
|
||||||
void MQTT::publishQueuedMessages()
|
void MQTT::publishQueuedMessages()
|
||||||
{
|
{
|
||||||
if (mqttQueue.isEmpty())
|
if (mqttQueue.isEmpty() || !isConnected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_DEBUG("Publish enqueued MQTT message");
|
LOG_DEBUG("Publish enqueued MQTT message");
|
||||||
@@ -895,4 +899,4 @@ void MQTT::perhapsReportToMap()
|
|||||||
|
|
||||||
// Update the last report time
|
// Update the last report time
|
||||||
last_report_to_map = millis();
|
last_report_to_map = millis();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
|
#include "power.h"
|
||||||
|
|
||||||
|
#include <hal/nrf_lpcomp.h>
|
||||||
|
|
||||||
#ifdef BQ25703A_ADDR
|
#ifdef BQ25703A_ADDR
|
||||||
#include "BQ25713.h"
|
#include "BQ25713.h"
|
||||||
@@ -389,6 +392,23 @@ void cpuDeepSleep(uint32_t msecToWake)
|
|||||||
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BATTERY_LPCOMP_INPUT
|
||||||
|
// Wake up if power rises again
|
||||||
|
nrf_lpcomp_config_t c;
|
||||||
|
c.reference = BATTERY_LPCOMP_THRESHOLD;
|
||||||
|
c.detection = NRF_LPCOMP_DETECT_UP;
|
||||||
|
c.hyst = NRF_LPCOMP_HYST_NOHYST;
|
||||||
|
nrf_lpcomp_configure(NRF_LPCOMP, &c);
|
||||||
|
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT);
|
||||||
|
nrf_lpcomp_enable(NRF_LPCOMP);
|
||||||
|
|
||||||
|
battery_adcEnable();
|
||||||
|
|
||||||
|
nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
|
||||||
|
while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY))
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
auto ok = sd_power_system_off();
|
auto ok = sd_power_system_off();
|
||||||
if (ok != NRF_SUCCESS) {
|
if (ok != NRF_SUCCESS) {
|
||||||
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
||||||
@@ -420,4 +440,4 @@ void enterDfuMode()
|
|||||||
#else
|
#else
|
||||||
enterUf2Dfu();
|
enterUf2Dfu();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,6 +146,20 @@ void getMacAddr(uint8_t *dmac)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string cleanupNameForAutoconf(std::string name)
|
||||||
|
{
|
||||||
|
// Convert spaces -> dashes, lowercase
|
||||||
|
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) {
|
||||||
|
if (c == ' ') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return (char)std::tolower(c);
|
||||||
|
});
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/** apps run under portduino can optionally define a portduinoSetup() to
|
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||||
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
||||||
* before running 'arduino' code.
|
* before running 'arduino' code.
|
||||||
@@ -218,6 +232,11 @@ void portduinoSetup()
|
|||||||
// If LoRa `Module: auto` (default in config.yaml),
|
// If LoRa `Module: auto` (default in config.yaml),
|
||||||
// attempt to auto config based on Product Strings
|
// attempt to auto config based on Product Strings
|
||||||
if (portduino_config.lora_module == use_autoconf) {
|
if (portduino_config.lora_module == use_autoconf) {
|
||||||
|
bool found_hat = false;
|
||||||
|
bool found_rak_eeprom = false;
|
||||||
|
bool found_ch341 = false;
|
||||||
|
|
||||||
|
char hat_vendor[96] = {0};
|
||||||
char autoconf_product[96] = {0};
|
char autoconf_product[96] = {0};
|
||||||
// Try CH341
|
// Try CH341
|
||||||
try {
|
try {
|
||||||
@@ -227,21 +246,32 @@ void portduinoSetup()
|
|||||||
ch341Hal->getProductString(autoconf_product, 95);
|
ch341Hal->getProductString(autoconf_product, 95);
|
||||||
delete ch341Hal;
|
delete ch341Hal;
|
||||||
std::cout << "autoconf: Found CH341 device " << autoconf_product << std::endl;
|
std::cout << "autoconf: Found CH341 device " << autoconf_product << std::endl;
|
||||||
|
|
||||||
|
found_ch341 = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cout << "autoconf: Could not locate CH341 device" << std::endl;
|
std::cout << "autoconf: Could not locate CH341 device" << std::endl;
|
||||||
}
|
}
|
||||||
// Try Pi HAT+
|
// Try Pi HAT+
|
||||||
if (strlen(autoconf_product) < 6) {
|
if (strlen(autoconf_product) < 6) {
|
||||||
std::cout << "autoconf: Looking for Pi HAT+..." << std::endl;
|
std::cout << "autoconf: Looking for Pi HAT+..." << std::endl;
|
||||||
|
if (access("/proc/device-tree/hat/vendor", R_OK) == 0) {
|
||||||
|
std::ifstream hatVendorFile("/proc/device-tree/hat/vendor");
|
||||||
|
if (hatVendorFile.is_open()) {
|
||||||
|
hatVendorFile.read(hat_vendor, 95);
|
||||||
|
hatVendorFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (access("/proc/device-tree/hat/product", R_OK) == 0) {
|
if (access("/proc/device-tree/hat/product", R_OK) == 0) {
|
||||||
std::ifstream hatProductFile("/proc/device-tree/hat/product");
|
std::ifstream hatProductFile("/proc/device-tree/hat/product");
|
||||||
if (hatProductFile.is_open()) {
|
if (hatProductFile.is_open()) {
|
||||||
hatProductFile.read(autoconf_product, 95);
|
hatProductFile.read(autoconf_product, 95);
|
||||||
hatProductFile.close();
|
hatProductFile.close();
|
||||||
}
|
}
|
||||||
std::cout << "autoconf: Found Pi HAT+ " << autoconf_product << " at /proc/device-tree/hat/product" << std::endl;
|
std::cout << "autoconf: Found Pi HAT+ " << hat_vendor << " " << autoconf_product << " at /proc/device-tree/hat"
|
||||||
|
<< std::endl;
|
||||||
|
found_hat = true;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat/product" << std::endl;
|
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// attempt to load autoconf data from an EEPROM on 0x50
|
// attempt to load autoconf data from an EEPROM on 0x50
|
||||||
@@ -297,6 +327,7 @@ void portduinoSetup()
|
|||||||
autoconf_product[0] = 0x0;
|
autoconf_product[0] = 0x0;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "autoconf: Found eeprom data " << autoconf_raw << std::endl;
|
std::cout << "autoconf: Found eeprom data " << autoconf_raw << std::endl;
|
||||||
|
found_rak_eeprom = true;
|
||||||
if (mac_start != nullptr) {
|
if (mac_start != nullptr) {
|
||||||
std::cout << "autoconf: Found mac data " << mac_start << std::endl;
|
std::cout << "autoconf: Found mac data " << mac_start << std::endl;
|
||||||
if (strlen(mac_start) == 12)
|
if (strlen(mac_start) == 12)
|
||||||
@@ -325,12 +356,29 @@ void portduinoSetup()
|
|||||||
if (strlen(autoconf_product) > 0) {
|
if (strlen(autoconf_product) > 0) {
|
||||||
// From configProducts map in PortduinoGlue.h
|
// From configProducts map in PortduinoGlue.h
|
||||||
std::string product_config = "";
|
std::string product_config = "";
|
||||||
try {
|
|
||||||
|
if (configProducts.find(autoconf_product) != configProducts.end()) {
|
||||||
product_config = configProducts.at(autoconf_product);
|
product_config = configProducts.at(autoconf_product);
|
||||||
} catch (std::out_of_range &e) {
|
} else {
|
||||||
std::cerr << "autoconf: Unable to find config for " << autoconf_product << std::endl;
|
if (found_hat) {
|
||||||
exit(EXIT_FAILURE);
|
product_config =
|
||||||
|
cleanupNameForAutoconf("lora-hat-" + std::string(hat_vendor) + "-" + autoconf_product + ".yaml");
|
||||||
|
} else if (found_ch341) {
|
||||||
|
product_config = cleanupNameForAutoconf("lora-usb-" + std::string(autoconf_product) + ".yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't try to automatically find config for a device with RAK eeprom.
|
||||||
|
if (found_rak_eeprom) {
|
||||||
|
std::cerr << "autoconf: Found unknown RAK product " << autoconf_product << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (access((portduino_config.available_directory + product_config).c_str(), R_OK) != 0) {
|
||||||
|
std::cerr << "autoconf: Unable to find config for " << autoconf_product << "(tried " << product_config << ")"
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadConfig((portduino_config.available_directory + product_config).c_str())) {
|
if (loadConfig((portduino_config.available_directory + product_config).c_str())) {
|
||||||
std::cout << "autoconf: Using " << product_config << " as config file for " << autoconf_product << std::endl;
|
std::cout << "autoconf: Using " << product_config << " as config file for " << autoconf_product << std::endl;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -144,4 +144,6 @@ class Power : private concurrency::OSThread
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void battery_adcEnable();
|
||||||
|
|
||||||
extern Power *power;
|
extern Power *power;
|
||||||
|
|||||||
@@ -210,6 +210,16 @@ No longer populated on PCB
|
|||||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
#define ADC_MULTIPLIER (4.916F)
|
#define ADC_MULTIPLIER (4.916F)
|
||||||
|
|
||||||
|
// rf52840 AIN2 = Pin 4
|
||||||
|
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_2
|
||||||
|
|
||||||
|
// We have AIN2 with a VBAT divider so AIN2 = VBAT * (100/490)
|
||||||
|
// We have the device going deep sleep under 3.1V, which is AIN2 = 0.63V
|
||||||
|
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN2 = 0.67V
|
||||||
|
// Ratio 0.67/3.3 = 0.20, so we can pick a bit higher, 2/8 VDD, which means
|
||||||
|
// VBAT=4.04V
|
||||||
|
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_2_8
|
||||||
|
|
||||||
#define HAS_RTC 0
|
#define HAS_RTC 0
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,6 +267,20 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
|||||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
#define ADC_MULTIPLIER 1.73
|
#define ADC_MULTIPLIER 1.73
|
||||||
|
|
||||||
|
// RAK4630 AIN0 = nrf52840 AIN3 = Pin 5
|
||||||
|
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_3
|
||||||
|
|
||||||
|
// We have AIN3 with a VBAT divider so AIN3 = VBAT * (1.5/2.5)
|
||||||
|
// We have the device going deep sleep under 3.1V, which is AIN3 = 1.86V
|
||||||
|
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN3 = 1.98V
|
||||||
|
// 1.98/3.3 = 6/10, but that's close to the VBAT divider, so we
|
||||||
|
// pick 6/8VDD, which means VBAT=4.1V.
|
||||||
|
// Reference:
|
||||||
|
// VDD=3.3V AIN3=5/8*VDD=2.06V VBAT=1.66*AIN3=3.41V
|
||||||
|
// VDD=3.3V AIN3=11/16*VDD=2.26V VBAT=1.66*AIN3=3.76V
|
||||||
|
// VDD=3.3V AIN3=6/8*VDD=2.47V VBAT=1.66*AIN3=4.1V
|
||||||
|
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_11_16
|
||||||
|
|
||||||
#define HAS_RTC 1
|
#define HAS_RTC 1
|
||||||
|
|
||||||
#define HAS_ETHERNET 1
|
#define HAS_ETHERNET 1
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 2
|
major = 2
|
||||||
minor = 7
|
minor = 7
|
||||||
build = 14
|
build = 15
|
||||||
|
|||||||
Reference in New Issue
Block a user