mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-31 22:21:51 +00:00
Compare commits
63 Commits
v2.3.13.83
...
v2.3.14.64
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64531fa1ae | ||
|
|
23ac6b6514 | ||
|
|
f5098dc6d8 | ||
|
|
2e0d96cece | ||
|
|
8078e03f5f | ||
|
|
eb6bd3a06f | ||
|
|
d32cdecc06 | ||
|
|
f8db38cf99 | ||
|
|
02d8715ca0 | ||
|
|
0dd363fa98 | ||
|
|
0bcc60d535 | ||
|
|
2d39911f91 | ||
|
|
ddc406209b | ||
|
|
f145b5f16f | ||
|
|
e050888b26 | ||
|
|
9266a53f4e | ||
|
|
9a80951d6f | ||
|
|
f0a38a5cf0 | ||
|
|
1515c8e763 | ||
|
|
3e9e0fdd49 | ||
|
|
ca560d64ea | ||
|
|
c59cb3c292 | ||
|
|
f79039fe57 | ||
|
|
e780b9a798 | ||
|
|
3c4fa2101f | ||
|
|
8fa0911ec8 | ||
|
|
5fceab7f0f | ||
|
|
5cebe4a0a7 | ||
|
|
275e393115 | ||
|
|
e7181988b6 | ||
|
|
e822525ce5 | ||
|
|
5e92136ed0 | ||
|
|
cd60ee80bd | ||
|
|
9d8a5221a9 | ||
|
|
30b14c57e7 | ||
|
|
7a25e0b69a | ||
|
|
b6066a78c1 | ||
|
|
5d2f7d1962 | ||
|
|
00162b4ccf | ||
|
|
ce3be5b4e8 | ||
|
|
cf2a824cc1 | ||
|
|
a453d7f52c | ||
|
|
ba14ffb8d3 | ||
|
|
2eb3cfd5e0 | ||
|
|
ce9e63a2cb | ||
|
|
dbb254ba7a | ||
|
|
27bb3506d3 | ||
|
|
97e8b1fd18 | ||
|
|
53fc22178b | ||
|
|
08e1c2f681 | ||
|
|
537814df58 | ||
|
|
d1d49efc6e | ||
|
|
3cda598673 | ||
|
|
5554cc46a7 | ||
|
|
c46c3427f0 | ||
|
|
dca8615eaa | ||
|
|
79511aa61e | ||
|
|
80762518d5 | ||
|
|
d2390cb98a | ||
|
|
a37f309c03 | ||
|
|
3a628047ef | ||
|
|
a5fdb663e2 | ||
|
|
1ec0e750a3 |
@@ -44,7 +44,7 @@ lib_deps =
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
h2zero/NimBLE-Arduino@^1.4.1
|
||||
h2zero/NimBLE-Arduino@^1.4.2
|
||||
https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
|
||||
|
||||
@@ -7,13 +7,6 @@
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x8029"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"],
|
||||
["0x239A", "0x802A"]
|
||||
],
|
||||
"usb_product": "WIO-BOOT",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "Seeed_WIO_WM1110",
|
||||
"bsp": {
|
||||
|
||||
3
extra_scripts/README.md
Normal file
3
extra_scripts/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# extra_scripts
|
||||
|
||||
This directory contains special [scripts](https://docs.platformio.org/en/latest/scripting/index.html) that are used to modify the platformio environment in rare cases.
|
||||
20
extra_scripts/disable_adafruit_usb.py
Normal file
20
extra_scripts/disable_adafruit_usb.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# trunk-ignore-all(flake8/F821)
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
|
||||
Import("env")
|
||||
|
||||
# NOTE: This is not currently used, but can serve as an example on how to write extra_scripts
|
||||
|
||||
print("Current CLI targets", COMMAND_LINE_TARGETS)
|
||||
print("Current Build targets", BUILD_TARGETS)
|
||||
print("CPP defs", env.get("CPPDEFINES"))
|
||||
|
||||
# Adafruit.py in the platformio build tree is a bit naive and always enables their USB stack for building. We don't want this.
|
||||
# So come in after that python script has run and disable it. This hack avoids us having to fork that big project and send in a PR
|
||||
# which might not be accepted. -@geeksville
|
||||
|
||||
env["CPPDEFINES"].remove("USBCON")
|
||||
env["CPPDEFINES"].remove("USE_TINYUSB")
|
||||
|
||||
# Custom actions when building program/firmware
|
||||
# env.AddPreAction("buildprog", callback...)
|
||||
@@ -80,7 +80,7 @@ monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
jgromes/RadioLib@~6.6.0
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#dcacac5d2c7942376bc17f7079cced6a73cb659f ; ESP8266_SSD1306
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#2b40affbe7f7dc63b6c00fa88e7e12ed1f8e1719 ; ESP8266_SSD1306
|
||||
mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
|
||||
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
|
||||
|
||||
Submodule protobufs updated: 0c90a6814f...4da558d0f7
@@ -10,4 +10,6 @@ const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd,
|
||||
const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78, 0xb8,
|
||||
0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c};
|
||||
const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6,
|
||||
0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed};
|
||||
0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed};
|
||||
const uint8_t LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa,
|
||||
0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c};
|
||||
@@ -11,10 +11,11 @@
|
||||
#define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
||||
#define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002"
|
||||
#define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453"
|
||||
#define LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2"
|
||||
|
||||
// NRF52 wants these constants as byte arrays
|
||||
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
|
||||
extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[];
|
||||
extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[], LOGRADIO_UUID_16[];
|
||||
|
||||
/// Given a level between 0-100, update the BLE attribute
|
||||
void updateBatteryLevel(uint8_t level);
|
||||
@@ -27,4 +28,5 @@ class BluetoothApi
|
||||
virtual void clearBonds();
|
||||
virtual bool isConnected();
|
||||
virtual int getRssi() = 0;
|
||||
virtual void sendLog(const char *logMessage);
|
||||
};
|
||||
@@ -124,7 +124,7 @@ class GPSStatus : public Status
|
||||
if (isDirty) {
|
||||
if (hasLock) {
|
||||
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
||||
LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
|
||||
LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d\n", p.timestamp,
|
||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||
p.ground_speed * 1e-2, p.sats_in_view);
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "RTC.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
@@ -166,9 +167,43 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
va_end(arg);
|
||||
|
||||
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);
|
||||
#ifdef HAS_FREE_RTOS
|
||||
xSemaphoreGive(inDebugPrint);
|
||||
#else
|
||||
|
||||
@@ -75,11 +75,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Regulatory overrides for producing regional builds
|
||||
// Regulatory overrides
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Define if region should override user saved region
|
||||
// #define LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923
|
||||
// Override user saved region, for producing region-locked builds
|
||||
// #define REGULATORY_LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923
|
||||
|
||||
// Total system gain in dBm to subtract from Tx power to remain within regulatory ERP limit for non-licensed operators
|
||||
// This value should be set in variant.h and is PA gain + antenna gain (if system ships with an antenna)
|
||||
#ifndef REGULATORY_GAIN_LORA
|
||||
#define REGULATORY_GAIN_LORA 0
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Feature toggles
|
||||
|
||||
@@ -6,6 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::
|
||||
ScanI2C::ScanI2C() = default;
|
||||
|
||||
void ScanI2C::scanPort(ScanI2C::I2CPort port) {}
|
||||
void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address, uint8_t asize) {}
|
||||
|
||||
void ScanI2C::setSuppressScreen()
|
||||
{
|
||||
|
||||
@@ -88,6 +88,7 @@ class ScanI2C
|
||||
ScanI2C();
|
||||
|
||||
virtual void scanPort(ScanI2C::I2CPort);
|
||||
virtual void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t);
|
||||
|
||||
/*
|
||||
* A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it.
|
||||
|
||||
@@ -14,6 +14,15 @@
|
||||
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
|
||||
#endif
|
||||
|
||||
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
if (lookfor == array[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const
|
||||
{
|
||||
concurrency::LockGuard guard((concurrency::Lock *)&lock);
|
||||
@@ -135,11 +144,11 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
|
||||
type = T; \
|
||||
break;
|
||||
|
||||
void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
{
|
||||
concurrency::LockGuard guard((concurrency::Lock *)&lock);
|
||||
|
||||
LOG_DEBUG("Scanning for i2c devices on port %d\n", port);
|
||||
LOG_DEBUG("Scanning for I2C devices on port %d\n", port);
|
||||
|
||||
uint8_t err;
|
||||
|
||||
@@ -163,6 +172,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
#endif
|
||||
|
||||
for (addr.address = 1; addr.address < 127; addr.address++) {
|
||||
if (asize != 0) {
|
||||
if (!in_array(address, asize, addr.address))
|
||||
continue;
|
||||
LOG_DEBUG("Scanning address 0x%x\n", addr.address);
|
||||
}
|
||||
i2cBus->beginTransmission(addr.address);
|
||||
#ifdef ARCH_PORTDUINO
|
||||
if (i2cBus->read() != -1)
|
||||
@@ -356,7 +370,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
|
||||
}
|
||||
} else if (err == 4) {
|
||||
LOG_ERROR("Unknown error at address 0x%x\n", addr);
|
||||
LOG_ERROR("Unknown error at address 0x%x\n", addr.address);
|
||||
}
|
||||
|
||||
// Check if a type was found for the enumerated device - save, if so
|
||||
@@ -367,6 +381,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
}
|
||||
}
|
||||
|
||||
void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
{
|
||||
scanPort(port, nullptr, 0);
|
||||
}
|
||||
|
||||
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
|
||||
{
|
||||
if (address.port == ScanI2C::I2CPort::WIRE) {
|
||||
|
||||
@@ -16,6 +16,8 @@ class ScanI2CTwoWire : public ScanI2C
|
||||
public:
|
||||
void scanPort(ScanI2C::I2CPort) override;
|
||||
|
||||
void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t) override;
|
||||
|
||||
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
|
||||
|
||||
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
|
||||
@@ -53,4 +55,4 @@ class ScanI2CTwoWire : public ScanI2C
|
||||
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
|
||||
|
||||
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
|
||||
};
|
||||
};
|
||||
@@ -778,6 +778,22 @@ GPS::~GPS()
|
||||
notifyGPSSleepObserver.observe(¬ifyGPSSleep);
|
||||
}
|
||||
|
||||
const char *GPS::powerStateToString()
|
||||
{
|
||||
switch (powerState) {
|
||||
case GPS_OFF:
|
||||
return "OFF";
|
||||
case GPS_IDLE:
|
||||
return "IDLE";
|
||||
case GPS_STANDBY:
|
||||
return "STANDBY";
|
||||
case GPS_ACTIVE:
|
||||
return "ACTIVE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime)
|
||||
{
|
||||
// Record the current powerState
|
||||
@@ -792,7 +808,7 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime)
|
||||
else
|
||||
powerState = GPS_OFF;
|
||||
|
||||
LOG_DEBUG("GPS::powerState=%d\n", powerState);
|
||||
LOG_DEBUG("GPS::powerState=%s\n", powerStateToString());
|
||||
|
||||
// If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out.
|
||||
if (!on && powerState == GPS_IDLE)
|
||||
|
||||
@@ -289,6 +289,8 @@ class GPS : private concurrency::OSThread
|
||||
// delay counter to allow more sats before fixed position stops GPS thread
|
||||
uint8_t fixeddelayCtr = 0;
|
||||
|
||||
const char *powerStateToString();
|
||||
|
||||
protected:
|
||||
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
|
||||
};
|
||||
|
||||
@@ -43,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "meshUtils.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "modules/WaypointModule.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
|
||||
@@ -59,6 +60,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
/// Convert an integer GPS coords to a floating point
|
||||
#define DegD(i) (i * 1e-7)
|
||||
|
||||
using namespace meshtastic; /** @todo remove */
|
||||
|
||||
namespace graphics
|
||||
@@ -446,6 +450,37 @@ static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
||||
return packet->from != 0 && !moduleConfig.store_forward.enabled;
|
||||
}
|
||||
|
||||
// Determine whether the waypoint frame should be drawn (waypoint deleted? expired?)
|
||||
static bool shouldDrawWaypoint(const meshtastic_MeshPacket *packet)
|
||||
{
|
||||
#if !MESHTASTIC_EXCLUDE_WAYPOINT
|
||||
// If no waypoint to show
|
||||
if (!devicestate.has_rx_waypoint)
|
||||
return false;
|
||||
|
||||
// Decode the message, to find the expiration time (is waypoint still valid)
|
||||
// This handles "deletion" as well as expiration
|
||||
meshtastic_Waypoint wp;
|
||||
memset(&wp, 0, sizeof(wp));
|
||||
if (pb_decode_from_bytes(packet->decoded.payload.bytes, packet->decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) {
|
||||
// Valid waypoint
|
||||
if (wp.expire > getTime())
|
||||
return devicestate.has_rx_waypoint = true;
|
||||
|
||||
// Expired, or deleted
|
||||
else
|
||||
return devicestate.has_rx_waypoint = false;
|
||||
}
|
||||
|
||||
// If decoding failed
|
||||
LOG_ERROR("Failed to decode waypoint\n");
|
||||
devicestate.has_rx_waypoint = false;
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
|
||||
static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
|
||||
{
|
||||
@@ -1091,43 +1126,6 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Draw the last waypoint we received
|
||||
static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
static char tempBuf[237];
|
||||
|
||||
meshtastic_MeshPacket &mp = devicestate.rx_waypoint;
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
|
||||
uint32_t seconds = sinceReceived(&mp);
|
||||
uint32_t minutes = seconds / 60;
|
||||
uint32_t hours = minutes / 60;
|
||||
uint32_t days = hours / 24;
|
||||
|
||||
if (config.display.heading_bold) {
|
||||
display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s",
|
||||
screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||
(node && node->has_user) ? node->user.short_name : "???");
|
||||
}
|
||||
display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||
(node && node->has_user) ? node->user.short_name : "???");
|
||||
|
||||
display->setColor(WHITE);
|
||||
meshtastic_Waypoint scratch;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
|
||||
snprintf(tempBuf, sizeof(tempBuf), "Received waypoint: %s", scratch.name);
|
||||
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a series of fields in a column, wrapping to multiple columns if needed
|
||||
static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
||||
{
|
||||
@@ -1453,8 +1451,35 @@ static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t com
|
||||
drawLine(display, N1, N4);
|
||||
}
|
||||
|
||||
/// Convert an integer GPS coords to a floating point
|
||||
#define DegD(i) (i * 1e-7)
|
||||
// Get a string representation of the time passed since something happened
|
||||
static void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength)
|
||||
{
|
||||
// Use an absolute timestamp in some cases.
|
||||
// Particularly useful with E-Ink displays. Static UI, fewer refreshes.
|
||||
uint8_t timestampHours, timestampMinutes;
|
||||
int32_t daysAgo;
|
||||
bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo);
|
||||
|
||||
if (agoSecs < 120) // last 2 mins?
|
||||
snprintf(timeStr, maxLength, "%u seconds ago", agoSecs);
|
||||
// -- if suitable for timestamp --
|
||||
else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes
|
||||
snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / SECONDS_IN_MINUTE);
|
||||
else if (useTimestamp && daysAgo == 0) // Today
|
||||
snprintf(timeStr, maxLength, "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes);
|
||||
else if (useTimestamp && daysAgo == 1) // Yesterday
|
||||
snprintf(timeStr, maxLength, "Seen yesterday");
|
||||
else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method)
|
||||
snprintf(timeStr, maxLength, "%li days ago", (long)daysAgo);
|
||||
// -- if using time delta instead --
|
||||
else if (agoSecs < 120 * 60) // last 2 hrs
|
||||
snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / 60);
|
||||
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data.
|
||||
else if ((agoSecs / 60 / 60) < (hours_in_month * 6))
|
||||
snprintf(timeStr, maxLength, "%u hours ago", agoSecs / 60 / 60);
|
||||
else
|
||||
snprintf(timeStr, maxLength, "unknown age");
|
||||
}
|
||||
|
||||
static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -1494,34 +1519,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100));
|
||||
}
|
||||
|
||||
uint32_t agoSecs = sinceLastSeen(node);
|
||||
static char lastStr[20];
|
||||
|
||||
// Use an absolute timestamp in some cases.
|
||||
// Particularly useful with E-Ink displays. Static UI, fewer refreshes.
|
||||
uint8_t timestampHours, timestampMinutes;
|
||||
int32_t daysAgo;
|
||||
bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo);
|
||||
|
||||
if (agoSecs < 120) // last 2 mins?
|
||||
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
|
||||
// -- if suitable for timestamp --
|
||||
else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes
|
||||
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / SECONDS_IN_MINUTE);
|
||||
else if (useTimestamp && daysAgo == 0) // Today
|
||||
snprintf(lastStr, sizeof(lastStr), "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes);
|
||||
else if (useTimestamp && daysAgo == 1) // Yesterday
|
||||
snprintf(lastStr, sizeof(lastStr), "Seen yesterday");
|
||||
else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method)
|
||||
snprintf(lastStr, sizeof(lastStr), "%li days ago", (long)daysAgo);
|
||||
// -- if using time delta instead --
|
||||
else if (agoSecs < 120 * 60) // last 2 hrs
|
||||
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
|
||||
// Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data.
|
||||
else if ((agoSecs / 60 / 60) < (hours_in_month * 6))
|
||||
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
|
||||
else
|
||||
snprintf(lastStr, sizeof(lastStr), "unknown age");
|
||||
getTimeAgoStr(sinceLastSeen(node), lastStr, sizeof(lastStr));
|
||||
|
||||
static char distStr[20];
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
@@ -1596,6 +1595,112 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
drawColumns(display, x, y, fields);
|
||||
}
|
||||
|
||||
/// Draw the last waypoint we received
|
||||
static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// Prepare to draw
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
// Handle inverted display
|
||||
// Unsure of expected behavior: for now, copy drawNodeInfo
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED)
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
|
||||
// Decode the waypoint
|
||||
meshtastic_MeshPacket &mp = devicestate.rx_waypoint;
|
||||
meshtastic_Waypoint wp;
|
||||
memset(&wp, 0, sizeof(wp));
|
||||
if (!pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) {
|
||||
// This *should* be caught by shouldDrawWaypoint, but we'll short-circuit here just in case
|
||||
display->drawStringMaxWidth(0 + x, 0 + y, x + display->getWidth(), "Couldn't decode waypoint");
|
||||
devicestate.has_rx_waypoint = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get timestamp info. Will pass as a field to drawColumns
|
||||
static char lastStr[20];
|
||||
getTimeAgoStr(sinceReceived(&mp), lastStr, sizeof(lastStr));
|
||||
|
||||
// Will contain distance information, passed as a field to drawColumns
|
||||
static char distStr[20];
|
||||
|
||||
// Get our node, to use our own position
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
// Text fields to draw (left of compass)
|
||||
// Last element must be NULL. This signals the end of the char*[] to drawColumns
|
||||
const char *fields[] = {"Waypoint", lastStr, wp.name, distStr, NULL};
|
||||
|
||||
// Co-ordinates for the center of the compass/circle
|
||||
int16_t compassX = 0, compassY = 0;
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||||
compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5;
|
||||
compassY = y + SCREEN_HEIGHT / 2;
|
||||
} else {
|
||||
compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5;
|
||||
compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2;
|
||||
}
|
||||
|
||||
// If our node has a position:
|
||||
if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) {
|
||||
const meshtastic_PositionLite &op = ourNode->position;
|
||||
float myHeading;
|
||||
if (screen->hasHeading())
|
||||
myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians
|
||||
else
|
||||
myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
|
||||
// Distance to Waypoint
|
||||
float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
if (d < (2 * MILES_TO_FEET))
|
||||
snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET);
|
||||
} else {
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
}
|
||||
|
||||
// Compass bearing to waypoint
|
||||
float bearingToOther =
|
||||
GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i));
|
||||
// If the top of the compass is a static north then bearingToOther can be drawn on the compass directly
|
||||
// If the top of the compass is not a static north we need adjust bearingToOther based on heading
|
||||
if (!config.display.compass_north_top)
|
||||
bearingToOther -= myHeading;
|
||||
drawNodeHeading(display, compassX, compassY, bearingToOther);
|
||||
}
|
||||
|
||||
// If our node doesn't have position
|
||||
else {
|
||||
// ? in the compass
|
||||
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
|
||||
|
||||
// ? in the distance field
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL)
|
||||
strncpy(distStr, "? mi", sizeof(distStr));
|
||||
else
|
||||
strncpy(distStr, "? km", sizeof(distStr));
|
||||
}
|
||||
|
||||
// Undo color-inversion, if set prior to drawing header
|
||||
// Unsure of expected behavior? For now: copy drawNodeInfo
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
|
||||
// Draw compass circle
|
||||
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
|
||||
|
||||
// Must be after distStr is populated
|
||||
drawColumns(display, x, y, fields);
|
||||
}
|
||||
|
||||
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
|
||||
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32)
|
||||
{
|
||||
@@ -1806,6 +1911,8 @@ void Screen::setup()
|
||||
textMessageObserver.observe(textMessageModule);
|
||||
if (inputBroker)
|
||||
inputObserver.observe(inputBroker);
|
||||
if (waypointModule)
|
||||
waypointObserver.observe(waypointModule);
|
||||
|
||||
// Modules can notify screen about refresh
|
||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||
@@ -2133,8 +2240,9 @@ void Screen::setFrames()
|
||||
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
|
||||
normalFrames[numframes++] = drawTextMessageFrame;
|
||||
}
|
||||
// If we have a waypoint - show it next, unless it's a phone message and we aren't using any special modules
|
||||
if (devicestate.has_rx_waypoint && shouldDrawMessage(&devicestate.rx_waypoint)) {
|
||||
|
||||
// If we have a waypoint (not expired, not deleted)
|
||||
if (devicestate.has_rx_waypoint && shouldDrawWaypoint(&devicestate.rx_waypoint)) {
|
||||
normalFrames[numframes++] = drawWaypointFrame;
|
||||
}
|
||||
|
||||
@@ -2736,6 +2844,13 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Screen::handleWaypoint(const meshtastic_MeshPacket *arg)
|
||||
{
|
||||
// TODO: move to appropriate frame when redrawing
|
||||
setFrames();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#else
|
||||
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||
|
||||
@@ -126,6 +126,8 @@ class Screen : public concurrency::OSThread
|
||||
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||
CallbackObserver<Screen, const meshtastic_MeshPacket *> textMessageObserver =
|
||||
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
|
||||
CallbackObserver<Screen, const meshtastic_MeshPacket *> waypointObserver =
|
||||
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleWaypoint);
|
||||
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
||||
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
|
||||
CallbackObserver<Screen, const InputEvent *> inputObserver =
|
||||
@@ -336,6 +338,7 @@ class Screen : public concurrency::OSThread
|
||||
int handleTextMessage(const meshtastic_MeshPacket *arg);
|
||||
int handleUIFrameEvent(const UIFrameEvent *arg);
|
||||
int handleInputEvent(const InputEvent *arg);
|
||||
int handleWaypoint(const meshtastic_MeshPacket *arg);
|
||||
|
||||
/// Used to force (super slow) eink displays to draw critical frames
|
||||
void forceDisplay(bool forceUiUpdate = false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "InputBroker.h"
|
||||
#include "PowerFSM.h" // needed for event trigger
|
||||
|
||||
InputBroker *inputBroker;
|
||||
InputBroker *inputBroker = nullptr;
|
||||
|
||||
InputBroker::InputBroker(){};
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "cardKbI2cImpl.h"
|
||||
#include "InputBroker.h"
|
||||
#include "detect/ScanI2CTwoWire.h"
|
||||
#include "main.h"
|
||||
|
||||
CardKbI2cImpl *cardKbI2cImpl;
|
||||
|
||||
@@ -7,10 +9,52 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
|
||||
|
||||
void CardKbI2cImpl::init()
|
||||
{
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if (cardkb_found.address == 0x00) {
|
||||
LOG_DEBUG("Rescanning for I2C keyboard\n");
|
||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR};
|
||||
uint8_t i2caddr_asize = 3;
|
||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||
|
||||
#if defined(I2C_SDA1)
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize);
|
||||
#endif
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize);
|
||||
auto kb_info = i2cScanner->firstKeyboard();
|
||||
|
||||
if (kb_info.type != ScanI2C::DeviceType::NONE) {
|
||||
cardkb_found = kb_info.address;
|
||||
switch (kb_info.type) {
|
||||
case ScanI2C::DeviceType::RAK14004:
|
||||
kb_model = 0x02;
|
||||
break;
|
||||
case ScanI2C::DeviceType::CARDKB:
|
||||
kb_model = 0x00;
|
||||
break;
|
||||
case ScanI2C::DeviceType::TDECKKB:
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x10;
|
||||
break;
|
||||
case ScanI2C::DeviceType::BBQ10KB:
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x11;
|
||||
break;
|
||||
default:
|
||||
// use this as default since it's also just zero
|
||||
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
|
||||
kb_model = 0x00;
|
||||
}
|
||||
}
|
||||
if (cardkb_found.address == 0x00) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (cardkb_found.address == 0x00) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include "kbI2cBase.h"
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* @brief The idea behind this class to have static methods for the event handlers.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "kbI2cBase.h"
|
||||
#include "configuration.h"
|
||||
#include "detect/ScanI2C.h"
|
||||
#include "detect/ScanI2CTwoWire.h"
|
||||
|
||||
extern ScanI2C::DeviceAddress cardkb_found;
|
||||
extern uint8_t kb_model;
|
||||
@@ -29,11 +30,6 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len
|
||||
|
||||
int32_t KbI2cBase::runOnce()
|
||||
{
|
||||
if (cardkb_found.address == 0x00) {
|
||||
// Input device is not detected.
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
if (!i2cBus) {
|
||||
switch (cardkb_found.port) {
|
||||
case ScanI2C::WIRE1:
|
||||
|
||||
21
src/main.cpp
21
src/main.cpp
@@ -41,13 +41,13 @@
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
#include "nimble/NimbleBluetooth.h"
|
||||
NimbleBluetooth *nimbleBluetooth;
|
||||
NimbleBluetooth *nimbleBluetooth = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_NRF52
|
||||
#include "NRF52Bluetooth.h"
|
||||
NRF52Bluetooth *nrf52Bluetooth;
|
||||
NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
||||
#endif
|
||||
|
||||
#if HAS_WIFI
|
||||
@@ -94,23 +94,23 @@ NRF52Bluetooth *nrf52Bluetooth;
|
||||
#include "ButtonThread.h"
|
||||
#endif
|
||||
|
||||
#include "AmbientLightingThread.h"
|
||||
#include "PowerFSMThread.h"
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
#include "AccelerometerThread.h"
|
||||
#include "AmbientLightingThread.h"
|
||||
AccelerometerThread *accelerometerThread;
|
||||
AccelerometerThread *accelerometerThread = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_I2S
|
||||
#include "AudioThread.h"
|
||||
AudioThread *audioThread;
|
||||
AudioThread *audioThread = nullptr;
|
||||
#endif
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
// We always create a screen object, but we only init it if we find the hardware
|
||||
graphics::Screen *screen;
|
||||
graphics::Screen *screen = nullptr;
|
||||
|
||||
// Global power status
|
||||
meshtastic::PowerStatus *powerStatus = new meshtastic::PowerStatus();
|
||||
@@ -154,6 +154,7 @@ bool isVibrating = false;
|
||||
bool eink_found = true;
|
||||
|
||||
uint32_t serialSinceMsec;
|
||||
bool pauseBluetoothLogging = false;
|
||||
|
||||
bool pmu_found;
|
||||
|
||||
@@ -172,7 +173,7 @@ const char *getDeviceName()
|
||||
static char name[20];
|
||||
snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]);
|
||||
// if the shortname exists and is NOT the new default of ab3c, use it for BLE name.
|
||||
if ((owner.short_name != NULL) && (strcmp(owner.short_name, name) != 0)) {
|
||||
if (strcmp(owner.short_name, name) != 0) {
|
||||
snprintf(name, sizeof(name), "%s_%02x%02x", owner.short_name, dmac[4], dmac[5]);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "Meshtastic_%02x%02x", dmac[4], dmac[5]);
|
||||
@@ -241,7 +242,7 @@ void setup()
|
||||
initDeepSleep();
|
||||
|
||||
// power on peripherals
|
||||
#if defined(TTGO_T_ECHO) && defined(PIN_POWER_EN)
|
||||
#if defined(PIN_POWER_EN)
|
||||
pinMode(PIN_POWER_EN, OUTPUT);
|
||||
digitalWrite(PIN_POWER_EN, HIGH);
|
||||
// digitalWrite(PIN_POWER_EN1, INPUT);
|
||||
@@ -421,10 +422,6 @@ void setup()
|
||||
auto i2cCount = i2cScanner->countDevices();
|
||||
if (i2cCount == 0) {
|
||||
LOG_INFO("No I2C devices found\n");
|
||||
Wire.end();
|
||||
#ifdef I2C_SDA1
|
||||
Wire1.end();
|
||||
#endif
|
||||
} else {
|
||||
LOG_INFO("%i I2C devices found\n", i2cCount);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,8 @@ extern uint32_t serialSinceMsec;
|
||||
// This will suppress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
extern bool pauseBluetoothLogging;
|
||||
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode();
|
||||
|
||||
meshtastic_DeviceMetadata getDeviceMetadata();
|
||||
|
||||
@@ -20,7 +20,7 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p)
|
||||
bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignoring incoming msg, because we've already seen it", p);
|
||||
printPacket("Ignoring incoming msg we've already seen", p);
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
|
||||
@@ -373,8 +373,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
|
||||
pos.time = getValidTime(RTCQualityFromNet);
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB)
|
||||
LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i,
|
||||
pos.longitude_i, pos.altitude);
|
||||
LOG_DEBUG("onGPSChanged() pos@%x time=%u lat=%d lon=%d alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, pos.longitude_i,
|
||||
pos.altitude);
|
||||
|
||||
// Update our current position in the local DB
|
||||
nodeDB->updatePosition(nodeDB->getNodeNum(), pos, RX_SRC_LOCAL);
|
||||
|
||||
@@ -141,11 +141,6 @@ NodeDB::NodeDB()
|
||||
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
||||
saveWhat |= SEGMENT_CHANNELS;
|
||||
|
||||
if (!devicestate.node_remote_hardware_pins) {
|
||||
meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default};
|
||||
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
|
||||
}
|
||||
|
||||
if (config.position.gps_enabled) {
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
||||
config.position.gps_enabled = 0;
|
||||
@@ -826,8 +821,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
|
||||
|
||||
if (src == RX_SRC_LOCAL) {
|
||||
// Local packet, fully authoritative
|
||||
LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i,
|
||||
p.longitude_i, p.altitude);
|
||||
LOG_INFO("updatePosition LOCAL pos@%x time=%u lat=%d lon=%d alt=%d\n", p.timestamp, p.time, p.latitude_i, p.longitude_i,
|
||||
p.altitude);
|
||||
|
||||
setLocalPosition(p);
|
||||
info->position = TypeConversions::ConvertToPositionLite(p);
|
||||
@@ -842,7 +837,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
|
||||
// recorded based on the packet rxTime
|
||||
//
|
||||
// FIXME perhaps handle RX_SRC_USER separately?
|
||||
LOG_INFO("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||
LOG_INFO("updatePosition REMOTE node=0x%x time=%u lat=%d lon=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||
|
||||
// First, back up fields that we want to protect from overwrite
|
||||
uint32_t tmp_time = info->position.time;
|
||||
|
||||
@@ -155,8 +155,8 @@ class NodeDB
|
||||
localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time;
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%u, timestamp=%u\n", position.latitude_i,
|
||||
position.longitude_i, position.time, position.timestamp);
|
||||
LOG_DEBUG("Setting local position: lat=%i lon=%i time=%u timestamp=%u\n", position.latitude_i, position.longitude_i,
|
||||
position.time, position.timestamp);
|
||||
localPosition = position;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ void PhoneAPI::handleStartConfig()
|
||||
|
||||
// even if we were already connected - restart our state machine
|
||||
state = STATE_SEND_MY_INFO;
|
||||
pauseBluetoothLogging = true;
|
||||
|
||||
LOG_INFO("Starting API client config\n");
|
||||
nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos
|
||||
@@ -352,9 +353,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.config_complete_id = config_nonce;
|
||||
config_nonce = 0;
|
||||
state = STATE_SEND_PACKETS;
|
||||
pauseBluetoothLogging = false;
|
||||
break;
|
||||
|
||||
case STATE_SEND_PACKETS:
|
||||
pauseBluetoothLogging = false;
|
||||
// Do we have a message from the mesh or packet from the local device?
|
||||
LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n");
|
||||
if (queueStatusPacketForPhone) {
|
||||
@@ -398,6 +401,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
|
||||
void PhoneAPI::handleDisconnect()
|
||||
{
|
||||
pauseBluetoothLogging = false;
|
||||
LOG_INFO("PhoneAPI disconnect\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -98,8 +98,6 @@ class PhoneAPI
|
||||
|
||||
bool isConnected() { return state != STATE_SEND_NOTHING; }
|
||||
|
||||
void setInitialState() { state = STATE_SEND_MY_INFO; }
|
||||
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
meshtastic_FromRadio fromRadioScratch = {};
|
||||
|
||||
@@ -154,8 +154,8 @@ static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
void initRegion()
|
||||
{
|
||||
const RegionInfo *r = regions;
|
||||
#ifdef LORA_REGIONCODE
|
||||
for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != LORA_REGIONCODE; r++)
|
||||
#ifdef REGULATORY_LORA_REGIONCODE
|
||||
for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != REGULATORY_LORA_REGIONCODE; r++)
|
||||
;
|
||||
LOG_INFO("Wanted region %d, regulatory override to %s\n", config.lora.region, r->name);
|
||||
#else
|
||||
@@ -478,8 +478,8 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
power = loraConfig.tx_power;
|
||||
|
||||
if ((power == 0) || ((power > myRegion->powerLimit) && !devicestate.owner.is_licensed))
|
||||
power = myRegion->powerLimit;
|
||||
if ((power == 0) || ((power + REGULATORY_GAIN_LORA > myRegion->powerLimit) && !devicestate.owner.is_licensed))
|
||||
power = myRegion->powerLimit - REGULATORY_GAIN_LORA;
|
||||
|
||||
if (power == 0)
|
||||
power = 17; // Default to this power level if we don't have a valid regional power limit (powerLimit of myRegion defaults
|
||||
|
||||
@@ -372,6 +372,9 @@ typedef struct _meshtastic_Config_PowerConfig {
|
||||
uint32_t min_wake_secs;
|
||||
/* I2C address of INA_2XX to use for reading device battery voltage */
|
||||
uint8_t device_battery_ina_address;
|
||||
/* If non-zero, we want powermon log outputs. With the particular (bitfield) sources enabled.
|
||||
Note: we picked an ID of 32 so that lower more efficient IDs can be used for more frequently used options. */
|
||||
uint64_t powermon_enables;
|
||||
} meshtastic_Config_PowerConfig;
|
||||
|
||||
typedef struct _meshtastic_Config_NetworkConfig_IpV4Config {
|
||||
@@ -511,6 +514,8 @@ typedef struct _meshtastic_Config_BluetoothConfig {
|
||||
meshtastic_Config_BluetoothConfig_PairingMode mode;
|
||||
/* Specified PIN for PairingMode.FixedPin */
|
||||
uint32_t fixed_pin;
|
||||
/* Enables device (serial style logs) over Bluetooth */
|
||||
bool device_logging_enabled;
|
||||
} meshtastic_Config_BluetoothConfig;
|
||||
|
||||
typedef struct _meshtastic_Config {
|
||||
@@ -610,21 +615,21 @@ extern "C" {
|
||||
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
|
||||
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0}
|
||||
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
|
||||
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN}
|
||||
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0}
|
||||
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0}
|
||||
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
|
||||
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0}
|
||||
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
|
||||
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN}
|
||||
#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0}
|
||||
#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_Config_DeviceConfig_role_tag 1
|
||||
@@ -660,6 +665,7 @@ extern "C" {
|
||||
#define meshtastic_Config_PowerConfig_ls_secs_tag 7
|
||||
#define meshtastic_Config_PowerConfig_min_wake_secs_tag 8
|
||||
#define meshtastic_Config_PowerConfig_device_battery_ina_address_tag 9
|
||||
#define meshtastic_Config_PowerConfig_powermon_enables_tag 32
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_ip_tag 1
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_gateway_tag 2
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_subnet_tag 3
|
||||
@@ -702,6 +708,7 @@ extern "C" {
|
||||
#define meshtastic_Config_BluetoothConfig_enabled_tag 1
|
||||
#define meshtastic_Config_BluetoothConfig_mode_tag 2
|
||||
#define meshtastic_Config_BluetoothConfig_fixed_pin_tag 3
|
||||
#define meshtastic_Config_BluetoothConfig_device_logging_enabled_tag 4
|
||||
#define meshtastic_Config_device_tag 1
|
||||
#define meshtastic_Config_position_tag 2
|
||||
#define meshtastic_Config_power_tag 3
|
||||
@@ -770,7 +777,8 @@ X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sds_secs, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, ls_secs, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9)
|
||||
X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT64, powermon_enables, 32)
|
||||
#define meshtastic_Config_PowerConfig_CALLBACK NULL
|
||||
#define meshtastic_Config_PowerConfig_DEFAULT NULL
|
||||
|
||||
@@ -833,7 +841,8 @@ X(a, STATIC, SINGULAR, BOOL, ignore_mqtt, 104)
|
||||
#define meshtastic_Config_BluetoothConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UENUM, mode, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3)
|
||||
X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, device_logging_enabled, 4)
|
||||
#define meshtastic_Config_BluetoothConfig_CALLBACK NULL
|
||||
#define meshtastic_Config_BluetoothConfig_DEFAULT NULL
|
||||
|
||||
@@ -860,14 +869,14 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size
|
||||
#define meshtastic_Config_BluetoothConfig_size 10
|
||||
#define meshtastic_Config_BluetoothConfig_size 12
|
||||
#define meshtastic_Config_DeviceConfig_size 100
|
||||
#define meshtastic_Config_DisplayConfig_size 30
|
||||
#define meshtastic_Config_LoRaConfig_size 80
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
|
||||
#define meshtastic_Config_NetworkConfig_size 196
|
||||
#define meshtastic_Config_PositionConfig_size 62
|
||||
#define meshtastic_Config_PowerConfig_size 40
|
||||
#define meshtastic_Config_PowerConfig_size 52
|
||||
#define meshtastic_Config_size 199
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -308,7 +308,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
|
||||
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size
|
||||
#define meshtastic_ChannelFile_size 718
|
||||
#define meshtastic_NodeInfoLite_size 166
|
||||
#define meshtastic_OEMStore_size 3370
|
||||
#define meshtastic_OEMStore_size 3384
|
||||
#define meshtastic_PositionLite_size 28
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size
|
||||
#define meshtastic_LocalConfig_size 539
|
||||
#define meshtastic_LocalConfig_size 553
|
||||
#define meshtastic_LocalModuleConfig_size 685
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -69,6 +69,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_WIO_WM1110 = 21,
|
||||
/* RAK2560 Solar base station based on RAK4630 */
|
||||
meshtastic_HardwareModel_RAK2560 = 22,
|
||||
/* Heltec HRU-3601: https://heltec.org/project/hru-3601/ */
|
||||
meshtastic_HardwareModel_HELTEC_HRU_3601 = 23,
|
||||
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
|
||||
meshtastic_HardwareModel_STATION_G1 = 25,
|
||||
/* RAK11310 (RP2040 + SX1262) */
|
||||
|
||||
13
src/mesh/generated/meshtastic/powermon.pb.cpp
Normal file
13
src/mesh/generated/meshtastic/powermon.pb.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.8 */
|
||||
|
||||
#include "meshtastic/powermon.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(meshtastic_PowerMon, meshtastic_PowerMon, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
85
src/mesh/generated/meshtastic/powermon.pb.h
Normal file
85
src/mesh/generated/meshtastic/powermon.pb.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.8 */
|
||||
|
||||
#ifndef PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED
|
||||
#define PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
/* Enum definitions */
|
||||
/* Any significant power changing event in meshtastic should be tagged with a powermon state transition.
|
||||
If you are making new meshtastic features feel free to add new entries at the end of this definition. */
|
||||
typedef enum _meshtastic_PowerMon_State {
|
||||
meshtastic_PowerMon_State_None = 0,
|
||||
meshtastic_PowerMon_State_CPU_DeepSleep = 1,
|
||||
meshtastic_PowerMon_State_CPU_LightSleep = 2,
|
||||
/* The external Vext1 power is on. Many boards have auxillary power rails that the CPU turns on only
|
||||
occasionally. In cases where that rail has multiple devices on it we usually want to have logging on
|
||||
the state of that rail as an independent record.
|
||||
For instance on the Heltec Tracker 1.1 board, this rail is the power source for the GPS and screen.
|
||||
|
||||
The log messages will be short and complete (see PowerMon.Event in the protobufs for details).
|
||||
something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of all current states.
|
||||
(We use a bitmask for states so that if a log message gets lost it won't be fatal) */
|
||||
meshtastic_PowerMon_State_Vext1_On = 4,
|
||||
meshtastic_PowerMon_State_Lora_RXOn = 8,
|
||||
meshtastic_PowerMon_State_Lora_TXOn = 16,
|
||||
meshtastic_PowerMon_State_Lora_RXActive = 32,
|
||||
meshtastic_PowerMon_State_BT_On = 64,
|
||||
meshtastic_PowerMon_State_LED_On = 128,
|
||||
meshtastic_PowerMon_State_Screen_On = 256,
|
||||
meshtastic_PowerMon_State_Screen_Drawing = 512,
|
||||
meshtastic_PowerMon_State_Wifi_On = 1024,
|
||||
/* GPS is actively trying to find our location
|
||||
See GPSPowerState for more details */
|
||||
meshtastic_PowerMon_State_GPS_Active = 2048
|
||||
} meshtastic_PowerMon_State;
|
||||
|
||||
/* Struct definitions */
|
||||
/* Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs).
|
||||
But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) */
|
||||
typedef struct _meshtastic_PowerMon {
|
||||
char dummy_field;
|
||||
} meshtastic_PowerMon;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_PowerMon_State_MIN meshtastic_PowerMon_State_None
|
||||
#define _meshtastic_PowerMon_State_MAX meshtastic_PowerMon_State_GPS_Active
|
||||
#define _meshtastic_PowerMon_State_ARRAYSIZE ((meshtastic_PowerMon_State)(meshtastic_PowerMon_State_GPS_Active+1))
|
||||
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_PowerMon_init_default {0}
|
||||
#define meshtastic_PowerMon_init_zero {0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_PowerMon_FIELDLIST(X, a) \
|
||||
|
||||
#define meshtastic_PowerMon_CALLBACK NULL
|
||||
#define meshtastic_PowerMon_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_PowerMon_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define meshtastic_PowerMon_fields &meshtastic_PowerMon_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_POWERMON_PB_H_MAX_SIZE meshtastic_PowerMon_size
|
||||
#define meshtastic_PowerMon_size 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -299,8 +299,8 @@ void AdminModule::handleGetModuleConfigResponse(const meshtastic_MeshPacket &mp,
|
||||
{
|
||||
// Skip if it's disabled or no pins are exposed
|
||||
if (!r->get_module_config_response.payload_variant.remote_hardware.enabled ||
|
||||
!r->get_module_config_response.payload_variant.remote_hardware.available_pins) {
|
||||
LOG_DEBUG("Remote hardware module disabled or no vailable_pins. Skipping...\n");
|
||||
r->get_module_config_response.payload_variant.remote_hardware.available_pins_count == 0) {
|
||||
LOG_DEBUG("Remote hardware module disabled or no available_pins. Skipping...\n");
|
||||
return;
|
||||
}
|
||||
for (uint8_t i = 0; i < devicestate.node_remote_hardware_pins_count; i++) {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "modules/Telemetry/DeviceTelemetry.h"
|
||||
#endif
|
||||
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
#include "main.h"
|
||||
#include "modules/Telemetry/AirQualityTelemetry.h"
|
||||
#include "modules/Telemetry/EnvironmentTelemetry.h"
|
||||
#endif
|
||||
|
||||
@@ -73,7 +73,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
}
|
||||
|
||||
// Log packet size and data fields
|
||||
LOG_DEBUG("POSITION node=%08x l=%d latI=%d lonI=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d "
|
||||
LOG_DEBUG("POSITION node=%08x l=%d lat=%d lon=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d "
|
||||
"time=%d\n",
|
||||
getFrom(&mp), mp.decoded.payload.size, p.latitude_i, p.longitude_i, p.altitude, p.altitude_hae,
|
||||
p.altitude_geoidal_separation, p.PDOP, p.HDOP, p.VDOP, p.sats_in_view, p.fix_quality, p.fix_type, p.timestamp,
|
||||
@@ -219,7 +219,7 @@ meshtastic_MeshPacket *PositionModule::allocReply()
|
||||
LOG_INFO("Providing time to mesh %u\n", p.time);
|
||||
}
|
||||
|
||||
LOG_INFO("Position reply: time=%i, latI=%i, lonI=%i\n", p.time, p.latitude_i, p.longitude_i);
|
||||
LOG_INFO("Position reply: time=%i lat=%i lon=%i\n", p.time, p.latitude_i, p.longitude_i);
|
||||
|
||||
// TAK Tracker devices should send their position in a TAK packet over the ATAK port
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)
|
||||
|
||||
@@ -85,53 +85,90 @@ bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPack
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m)
|
||||
{
|
||||
if (!aqi.read(&data)) {
|
||||
LOG_WARN("Skipping send measurements. Could not read AQIn\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
m.time = getTime();
|
||||
m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
|
||||
m.variant.air_quality_metrics.pm10_standard = data.pm10_standard;
|
||||
m.variant.air_quality_metrics.pm25_standard = data.pm25_standard;
|
||||
m.variant.air_quality_metrics.pm100_standard = data.pm100_standard;
|
||||
m->time = getTime();
|
||||
m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
|
||||
m->variant.air_quality_metrics.pm10_standard = data.pm10_standard;
|
||||
m->variant.air_quality_metrics.pm25_standard = data.pm25_standard;
|
||||
m->variant.air_quality_metrics.pm100_standard = data.pm100_standard;
|
||||
|
||||
m.variant.air_quality_metrics.pm10_environmental = data.pm10_env;
|
||||
m.variant.air_quality_metrics.pm25_environmental = data.pm25_env;
|
||||
m.variant.air_quality_metrics.pm100_environmental = data.pm100_env;
|
||||
m->variant.air_quality_metrics.pm10_environmental = data.pm10_env;
|
||||
m->variant.air_quality_metrics.pm25_environmental = data.pm25_env;
|
||||
m->variant.air_quality_metrics.pm100_environmental = data.pm100_env;
|
||||
|
||||
LOG_INFO("(Sending): PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i\n",
|
||||
m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard,
|
||||
m.variant.air_quality_metrics.pm100_standard);
|
||||
m->variant.air_quality_metrics.pm10_standard, m->variant.air_quality_metrics.pm25_standard,
|
||||
m->variant.air_quality_metrics.pm100_standard);
|
||||
|
||||
LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i\n",
|
||||
m.variant.air_quality_metrics.pm10_environmental, m.variant.air_quality_metrics.pm25_environmental,
|
||||
m.variant.air_quality_metrics.pm100_environmental);
|
||||
m->variant.air_quality_metrics.pm10_environmental, m->variant.air_quality_metrics.pm25_environmental,
|
||||
m->variant.air_quality_metrics.pm100_environmental);
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(m);
|
||||
p->to = dest;
|
||||
p->decoded.want_response = false;
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR)
|
||||
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
|
||||
else
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
|
||||
// release previous packet before occupying a new spot
|
||||
if (lastMeasurementPacket != nullptr)
|
||||
packetPool.release(lastMeasurementPacket);
|
||||
|
||||
lastMeasurementPacket = packetPool.allocCopy(*p);
|
||||
if (phoneOnly) {
|
||||
LOG_INFO("Sending packet to phone\n");
|
||||
service.sendToPhone(p);
|
||||
} else {
|
||||
LOG_INFO("Sending packet to mesh\n");
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
} else {
|
||||
LOG_ERROR("Error decoding AirQualityTelemetry module!\n");
|
||||
return NULL;
|
||||
}
|
||||
// Check for a request for air quality metrics
|
||||
if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
if (getAirQualityTelemetry(&m)) {
|
||||
LOG_INFO("Air quality telemetry replying to request\n");
|
||||
return allocDataProtobuf(m);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
{
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
if (getAirQualityTelemetry(&m)) {
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(m);
|
||||
p->to = dest;
|
||||
p->decoded.want_response = false;
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR)
|
||||
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
|
||||
else
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
|
||||
// release previous packet before occupying a new spot
|
||||
if (lastMeasurementPacket != nullptr)
|
||||
packetPool.release(lastMeasurementPacket);
|
||||
|
||||
lastMeasurementPacket = packetPool.allocCopy(*p);
|
||||
if (phoneOnly) {
|
||||
LOG_INFO("Sending packet to phone\n");
|
||||
service.sendToPhone(p);
|
||||
} else {
|
||||
LOG_INFO("Sending packet to mesh\n");
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,11 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override;
|
||||
virtual int32_t runOnce() override;
|
||||
/** Called to get current Air Quality data
|
||||
@return true if it contains valid data
|
||||
*/
|
||||
bool getAirQualityTelemetry(meshtastic_Telemetry *m);
|
||||
virtual meshtastic_MeshPacket *allocReply() override;
|
||||
/**
|
||||
* Send our Telemetry into the mesh
|
||||
*/
|
||||
|
||||
@@ -52,14 +52,27 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
|
||||
meshtastic_MeshPacket *DeviceTelemetryModule::allocReply()
|
||||
{
|
||||
if (ignoreRequest) {
|
||||
return NULL;
|
||||
if (currentRequest) {
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
} else {
|
||||
LOG_ERROR("Error decoding DeviceTelemetry module!\n");
|
||||
return NULL;
|
||||
}
|
||||
// Check for a request for device metrics
|
||||
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
|
||||
LOG_INFO("Device telemetry replying to request\n");
|
||||
|
||||
meshtastic_Telemetry telemetry = getDeviceTelemetry();
|
||||
return allocDataProtobuf(telemetry);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("Device telemetry replying to request\n");
|
||||
|
||||
meshtastic_Telemetry telemetry = getDeviceTelemetry();
|
||||
return allocDataProtobuf(telemetry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry()
|
||||
@@ -104,4 +117,4 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -270,98 +270,129 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m)
|
||||
{
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
bool valid = true;
|
||||
bool hasSensor = false;
|
||||
m.time = getTime();
|
||||
m.which_variant = meshtastic_Telemetry_environment_metrics_tag;
|
||||
m->time = getTime();
|
||||
m->which_variant = meshtastic_Telemetry_environment_metrics_tag;
|
||||
|
||||
if (dfRobotLarkSensor.hasSensor()) {
|
||||
valid = valid && dfRobotLarkSensor.getMetrics(&m);
|
||||
valid = valid && dfRobotLarkSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (sht31Sensor.hasSensor()) {
|
||||
valid = valid && sht31Sensor.getMetrics(&m);
|
||||
valid = valid && sht31Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (lps22hbSensor.hasSensor()) {
|
||||
valid = valid && lps22hbSensor.getMetrics(&m);
|
||||
valid = valid && lps22hbSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (shtc3Sensor.hasSensor()) {
|
||||
valid = valid && shtc3Sensor.getMetrics(&m);
|
||||
valid = valid && shtc3Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (bmp085Sensor.hasSensor()) {
|
||||
valid = valid && bmp085Sensor.getMetrics(&m);
|
||||
valid = valid && bmp085Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (bmp280Sensor.hasSensor()) {
|
||||
valid = valid && bmp280Sensor.getMetrics(&m);
|
||||
valid = valid && bmp280Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (bme280Sensor.hasSensor()) {
|
||||
valid = valid && bme280Sensor.getMetrics(&m);
|
||||
valid = valid && bme280Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (bme680Sensor.hasSensor()) {
|
||||
valid = valid && bme680Sensor.getMetrics(&m);
|
||||
valid = valid && bme680Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (mcp9808Sensor.hasSensor()) {
|
||||
valid = valid && mcp9808Sensor.getMetrics(&m);
|
||||
valid = valid && mcp9808Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (ina219Sensor.hasSensor()) {
|
||||
valid = valid && ina219Sensor.getMetrics(&m);
|
||||
valid = valid && ina219Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (ina260Sensor.hasSensor()) {
|
||||
valid = valid && ina260Sensor.getMetrics(&m);
|
||||
valid = valid && ina260Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (veml7700Sensor.hasSensor()) {
|
||||
valid = valid && veml7700Sensor.getMetrics(&m);
|
||||
valid = valid && veml7700Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (tsl2591Sensor.hasSensor()) {
|
||||
valid = valid && tsl2591Sensor.getMetrics(&m);
|
||||
valid = valid && tsl2591Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (opt3001Sensor.hasSensor()) {
|
||||
valid = valid && opt3001Sensor.getMetrics(&m);
|
||||
valid = valid && opt3001Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (mlx90632Sensor.hasSensor()) {
|
||||
valid = valid && mlx90632Sensor.getMetrics(&m);
|
||||
valid = valid && mlx90632Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (rcwl9620Sensor.hasSensor()) {
|
||||
valid = valid && rcwl9620Sensor.getMetrics(&m);
|
||||
valid = valid && rcwl9620Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (nau7802Sensor.hasSensor()) {
|
||||
valid = valid && nau7802Sensor.getMetrics(&m);
|
||||
valid = valid && nau7802Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (aht10Sensor.hasSensor()) {
|
||||
if (!bmp280Sensor.hasSensor()) {
|
||||
valid = valid && aht10Sensor.getMetrics(&m);
|
||||
valid = valid && aht10Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
} else {
|
||||
// prefer bmp280 temp if both sensors are present, fetch only humidity
|
||||
meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero;
|
||||
LOG_INFO("AHTX0+BMP280 module detected: using temp from BMP280 and humy from AHTX0\n");
|
||||
aht10Sensor.getMetrics(&m_ahtx);
|
||||
m.variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity;
|
||||
m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity;
|
||||
}
|
||||
}
|
||||
|
||||
valid = valid && hasSensor;
|
||||
return valid && hasSensor;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
} else {
|
||||
LOG_ERROR("Error decoding EnvironmentTelemetry module!\n");
|
||||
return NULL;
|
||||
}
|
||||
// Check for a request for environment metrics
|
||||
if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
if (getEnvironmentTelemetry(&m)) {
|
||||
LOG_INFO("Environment telemetry replying to request\n");
|
||||
return allocDataProtobuf(m);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
{
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
if (getEnvironmentTelemetry(&m)) {
|
||||
LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n",
|
||||
m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current,
|
||||
m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity,
|
||||
@@ -399,8 +430,9 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
setIntervalFromNow(5000);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return valid;
|
||||
return false;
|
||||
}
|
||||
|
||||
AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
||||
|
||||
@@ -32,6 +32,11 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override;
|
||||
virtual int32_t runOnce() override;
|
||||
/** Called to get current Environment telemetry data
|
||||
@return true if it contains valid data
|
||||
*/
|
||||
bool getEnvironmentTelemetry(meshtastic_Telemetry *m);
|
||||
virtual meshtastic_MeshPacket *allocReply() override;
|
||||
/**
|
||||
* Send our Telemetry into the mesh
|
||||
*/
|
||||
|
||||
@@ -163,29 +163,63 @@ bool PowerTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &m
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m)
|
||||
{
|
||||
bool valid = false;
|
||||
m->time = getTime();
|
||||
m->which_variant = meshtastic_Telemetry_power_metrics_tag;
|
||||
|
||||
m->variant.power_metrics.ch1_voltage = 0;
|
||||
m->variant.power_metrics.ch1_current = 0;
|
||||
m->variant.power_metrics.ch2_voltage = 0;
|
||||
m->variant.power_metrics.ch2_current = 0;
|
||||
m->variant.power_metrics.ch3_voltage = 0;
|
||||
m->variant.power_metrics.ch3_current = 0;
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
|
||||
if (ina219Sensor.hasSensor())
|
||||
valid = ina219Sensor.getMetrics(m);
|
||||
if (ina260Sensor.hasSensor())
|
||||
valid = ina260Sensor.getMetrics(m);
|
||||
if (ina3221Sensor.hasSensor())
|
||||
valid = ina3221Sensor.getMetrics(m);
|
||||
#endif
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *PowerTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
meshtastic_Telemetry *decoded = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
} else {
|
||||
LOG_ERROR("Error decoding PowerTelemetry module!\n");
|
||||
return NULL;
|
||||
}
|
||||
// Check for a request for power metrics
|
||||
if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
if (getPowerTelemetry(&m)) {
|
||||
LOG_INFO("Power telemetry replying to request\n");
|
||||
return allocDataProtobuf(m);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
{
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
bool valid = false;
|
||||
m.time = getTime();
|
||||
m.which_variant = meshtastic_Telemetry_power_metrics_tag;
|
||||
|
||||
m.variant.power_metrics.ch1_voltage = 0;
|
||||
m.variant.power_metrics.ch1_current = 0;
|
||||
m.variant.power_metrics.ch2_voltage = 0;
|
||||
m.variant.power_metrics.ch2_current = 0;
|
||||
m.variant.power_metrics.ch3_voltage = 0;
|
||||
m.variant.power_metrics.ch3_current = 0;
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
|
||||
if (ina219Sensor.hasSensor())
|
||||
valid = ina219Sensor.getMetrics(&m);
|
||||
if (ina260Sensor.hasSensor())
|
||||
valid = ina260Sensor.getMetrics(&m);
|
||||
if (ina3221Sensor.hasSensor())
|
||||
valid = ina3221Sensor.getMetrics(&m);
|
||||
#endif
|
||||
|
||||
if (valid) {
|
||||
if (getPowerTelemetry(&m)) {
|
||||
LOG_INFO("(Sending): ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, "
|
||||
"ch3_voltage=%f, ch3_current=%f\n",
|
||||
m.variant.power_metrics.ch1_voltage, m.variant.power_metrics.ch1_current, m.variant.power_metrics.ch2_voltage,
|
||||
@@ -218,8 +252,9 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
setIntervalFromNow(5000);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return valid;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -33,6 +33,11 @@ class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModul
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override;
|
||||
virtual int32_t runOnce() override;
|
||||
/** Called to get current Power telemetry data
|
||||
@return true if it contains valid data
|
||||
*/
|
||||
bool getPowerTelemetry(meshtastic_Telemetry *m);
|
||||
virtual meshtastic_MeshPacket *allocReply() override;
|
||||
/**
|
||||
* Send our Telemetry into the mesh
|
||||
*/
|
||||
|
||||
@@ -16,8 +16,7 @@ int32_t INA3221Sensor::runOnce()
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
if (!status) {
|
||||
ina3221.setAddr(INA3221_ADDR42_SDA); // i2c address 0x42
|
||||
ina3221.begin();
|
||||
ina3221.begin(nodeTelemetrySensorsMap[sensorType].second);
|
||||
ina3221.setShuntRes(100, 100, 100); // 0.1 Ohm shunt resistors
|
||||
status = true;
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "OPT3001Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "OPT3001Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <ClosedCube_OPT3001.h>
|
||||
|
||||
OPT3001Sensor::OPT3001Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_OPT3001, "OPT3001") {}
|
||||
@@ -41,4 +44,6 @@ bool OPT3001Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
LOG_INFO("Lux: %f\n", measurement->variant.environment_metrics.lux);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,8 @@
|
||||
#pragma once
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <ClosedCube_OPT3001.h>
|
||||
@@ -14,4 +19,6 @@ class OPT3001Sensor : public TelemetrySensor
|
||||
OPT3001Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -66,10 +66,6 @@ bool PaxcounterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, m
|
||||
|
||||
meshtastic_MeshPacket *PaxcounterModule::allocReply()
|
||||
{
|
||||
if (ignoreRequest) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
meshtastic_Paxcount pl = meshtastic_Paxcount_init_default;
|
||||
pl.wifi = count_from_libpax.wifi_count;
|
||||
pl.ble = count_from_libpax.ble_count;
|
||||
@@ -131,4 +127,4 @@ void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
}
|
||||
#endif // HAS_SCREEN
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -482,7 +482,12 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &
|
||||
|
||||
auto &ch = channels.getByIndex(chIndex);
|
||||
|
||||
if (&mp_decoded.decoded && strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 &&
|
||||
if (mp_decoded.which_payload_variant != meshtastic_MeshPacket_decoded_tag) {
|
||||
LOG_CRIT("MQTT::onSend(): mp_decoded isn't actually decoded\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 &&
|
||||
(mp_decoded.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP ||
|
||||
mp_decoded.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) {
|
||||
LOG_DEBUG("MQTT onSend - Ignoring range test or detection sensor message on public mqtt\n");
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
NimBLECharacteristic *fromNumCharacteristic;
|
||||
NimBLECharacteristic *BatteryCharacteristic;
|
||||
NimBLECharacteristic *logRadioCharacteristic;
|
||||
NimBLEServer *bleServer;
|
||||
|
||||
static bool passkeyShowing;
|
||||
@@ -58,7 +59,6 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
|
||||
{
|
||||
virtual void onRead(NimBLECharacteristic *pCharacteristic)
|
||||
{
|
||||
LOG_INFO("From Radio onread\n");
|
||||
uint8_t fromRadioBytes[meshtastic_FromRadio_size];
|
||||
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
|
||||
|
||||
@@ -180,6 +180,8 @@ void NimbleBluetooth::setupService()
|
||||
ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE);
|
||||
FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ);
|
||||
fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ);
|
||||
logRadioCharacteristic =
|
||||
bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ, 512U);
|
||||
} else {
|
||||
ToRadioCharacteristic = bleService->createCharacteristic(
|
||||
TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
@@ -188,6 +190,10 @@ void NimbleBluetooth::setupService()
|
||||
fromNumCharacteristic =
|
||||
bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
|
||||
logRadioCharacteristic = bleService->createCharacteristic(
|
||||
LOGRADIO_UUID,
|
||||
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC, 512U);
|
||||
logRadioCharacteristic->setValue("Init");
|
||||
}
|
||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||
|
||||
@@ -236,6 +242,14 @@ void NimbleBluetooth::clearBonds()
|
||||
NimBLEDevice::deleteAllBonds();
|
||||
}
|
||||
|
||||
void NimbleBluetooth::sendLog(const char *logMessage)
|
||||
{
|
||||
if (!bleServer || !isConnected() || strlen(logMessage) > 512) {
|
||||
return;
|
||||
}
|
||||
logRadioCharacteristic->notify(reinterpret_cast<const uint8_t *>(logMessage), strlen(logMessage), true);
|
||||
}
|
||||
|
||||
void clearNVS()
|
||||
{
|
||||
NimBLEDevice::deleteAllBonds();
|
||||
|
||||
@@ -11,6 +11,7 @@ class NimbleBluetooth : BluetoothApi
|
||||
bool isActive();
|
||||
bool isConnected();
|
||||
int getRssi();
|
||||
void sendLog(const char *logMessage);
|
||||
|
||||
private:
|
||||
void setupService();
|
||||
|
||||
@@ -101,6 +101,8 @@
|
||||
#define HW_VENDOR meshtastic_HardwareModel_STATION_G1
|
||||
#elif defined(DR_DEV)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_DR_DEV
|
||||
#elif defined(HELTEC_HRU_3601)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HRU_3601
|
||||
#elif defined(HELTEC_V3)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_V3
|
||||
#elif defined(HELTEC_WSL_V3)
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include <bluefruit.h>
|
||||
#include <utility/bonding.h>
|
||||
|
||||
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
|
||||
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
|
||||
static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
|
||||
static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16));
|
||||
static BLECharacteristic logRadio = BLECharacteristic(BLEUuid(LOGRADIO_UUID_16));
|
||||
|
||||
static BLEDis bledis; // DIS (Device Information Service) helper class instance
|
||||
static BLEBas blebas; // BAS (Battery Service) helper class instance
|
||||
static BLEDfu bledfu; // DFU software update helper service
|
||||
|
||||
static BLEDfu bledfu; // DFU software update helper service
|
||||
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
|
||||
// process at once
|
||||
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
|
||||
@@ -50,16 +50,14 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
|
||||
void onConnect(uint16_t conn_handle)
|
||||
{
|
||||
|
||||
// Get the reference to current connection
|
||||
BLEConnection *connection = Bluefruit.Connection(conn_handle);
|
||||
connectionHandle = conn_handle;
|
||||
|
||||
char central_name[32] = {0};
|
||||
connection->getPeerName(central_name, sizeof(central_name));
|
||||
|
||||
LOG_INFO("BLE Connected to %s\n", central_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when a connection is dropped
|
||||
* @param conn_handle connection where this event happens
|
||||
@@ -70,15 +68,13 @@ void onDisconnect(uint16_t conn_handle, uint8_t reason)
|
||||
// FIXME - we currently assume only one active connection
|
||||
LOG_INFO("BLE Disconnected, reason = 0x%x\n", reason);
|
||||
}
|
||||
|
||||
void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
|
||||
{
|
||||
// Display the raw request packet
|
||||
LOG_INFO("CCCD Updated: %u\n", cccd_value);
|
||||
|
||||
// Check the characteristic this CCCD update is associated with in case
|
||||
// this handler is used for multiple CCCD records.
|
||||
if (chr->uuid == fromNum.uuid) {
|
||||
if (chr->uuid == fromNum.uuid || chr->uuid == logRadio.uuid) {
|
||||
if (chr->notifyEnabled(conn_hdl)) {
|
||||
LOG_INFO("fromNum 'Notify' enabled\n");
|
||||
} else {
|
||||
@@ -86,21 +82,17 @@ void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startAdv(void)
|
||||
{
|
||||
// Advertising packet
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
|
||||
// IncludeService UUID
|
||||
// Bluefruit.ScanResponse.addService(meshBleService);
|
||||
Bluefruit.ScanResponse.addTxPower();
|
||||
Bluefruit.ScanResponse.addName();
|
||||
|
||||
// Include Name
|
||||
// Bluefruit.Advertising.addName();
|
||||
Bluefruit.Advertising.addService(meshBleService);
|
||||
|
||||
/* Start Advertising
|
||||
* - Enable auto advertising if disconnected
|
||||
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
|
||||
@@ -115,7 +107,6 @@ void startAdv(void)
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X
|
||||
}
|
||||
|
||||
// Just ack that the caller is allowed to read
|
||||
static void authorizeRead(uint16_t conn_hdl)
|
||||
{
|
||||
@@ -123,7 +114,6 @@ static void authorizeRead(uint16_t conn_hdl)
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* client is starting read, pull the bytes from our API class
|
||||
*/
|
||||
@@ -132,7 +122,6 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e
|
||||
if (request->offset == 0) {
|
||||
// If the read is long, we will get multiple authorize invocations - we only populate data on the first
|
||||
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
|
||||
|
||||
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
|
||||
// or make empty if the queue is empty
|
||||
fromRadio.write(fromRadioBytes, numBytes);
|
||||
@@ -141,37 +130,22 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e
|
||||
}
|
||||
authorizeRead(conn_hdl);
|
||||
}
|
||||
|
||||
void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
|
||||
{
|
||||
LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len);
|
||||
|
||||
bluetoothPhoneAPI->handleToRadio(data, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* client is starting read, pull the bytes from our API class
|
||||
*/
|
||||
void onFromNumAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
{
|
||||
LOG_INFO("fromNumAuthorizeCb\n");
|
||||
|
||||
authorizeRead(conn_hdl);
|
||||
}
|
||||
|
||||
void setupMeshService(void)
|
||||
{
|
||||
bluetoothPhoneAPI = new BluetoothPhoneAPI();
|
||||
|
||||
meshBleService.begin();
|
||||
|
||||
// Note: You must call .begin() on the BLEService before calling .begin() on
|
||||
// any characteristic(s) within that service definition.. Calling .begin() on
|
||||
// a BLECharacteristic will cause it to be added to the last BLEService that
|
||||
// was 'begin()'ed!
|
||||
auto secMode =
|
||||
config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN ? SECMODE_OPEN : SECMODE_ENC_NO_MITM;
|
||||
|
||||
fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ);
|
||||
fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!!
|
||||
fromNum.setFixedLen(
|
||||
@@ -201,10 +175,15 @@ void setupMeshService(void)
|
||||
// We don't call this callback via the adafruit queue, because we can safely run in the BLE context
|
||||
toRadio.setWriteCallback(onToRadioWrite, false);
|
||||
toRadio.begin();
|
||||
|
||||
logRadio.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ);
|
||||
logRadio.setPermission(secMode, SECMODE_NO_ACCESS);
|
||||
logRadio.setMaxLen(512);
|
||||
logRadio.setCccdWriteCallback(onCccd);
|
||||
logRadio.write32(0);
|
||||
logRadio.begin();
|
||||
}
|
||||
|
||||
static uint32_t configuredPasskey;
|
||||
|
||||
void NRF52Bluetooth::shutdown()
|
||||
{
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
@@ -214,29 +193,23 @@ void NRF52Bluetooth::shutdown()
|
||||
}
|
||||
Bluefruit.Advertising.stop();
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::startDisabled()
|
||||
{
|
||||
// Setup Bluetooth
|
||||
nrf52Bluetooth->setup();
|
||||
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
Bluefruit.Advertising.stop();
|
||||
Bluefruit.setTxPower(-40); // Minimum power
|
||||
|
||||
LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n");
|
||||
}
|
||||
|
||||
bool NRF52Bluetooth::isConnected()
|
||||
{
|
||||
return Bluefruit.connected(connectionHandle);
|
||||
}
|
||||
|
||||
int NRF52Bluetooth::getRssi()
|
||||
{
|
||||
return 0; // FIXME figure out where to source this
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::setup()
|
||||
{
|
||||
// Initialise the Bluefruit module
|
||||
@@ -244,12 +217,10 @@ void NRF52Bluetooth::setup()
|
||||
Bluefruit.autoConnLed(false);
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.begin();
|
||||
|
||||
// Clear existing data.
|
||||
Bluefruit.Advertising.stop();
|
||||
Bluefruit.Advertising.clearData();
|
||||
Bluefruit.ScanResponse.clearData();
|
||||
|
||||
if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) {
|
||||
configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN
|
||||
? config.bluetooth.fixed_pin
|
||||
@@ -268,37 +239,29 @@ void NRF52Bluetooth::setup()
|
||||
}
|
||||
// Set the advertised device name (keep it short!)
|
||||
Bluefruit.setName(getDeviceName());
|
||||
|
||||
// Set the connect/disconnect callback handlers
|
||||
Bluefruit.Periph.setConnectCallback(onConnect);
|
||||
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
|
||||
|
||||
bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||
bledfu.begin(); // Install the DFU helper
|
||||
|
||||
// Configure and Start the Device Information Service
|
||||
LOG_INFO("Configuring the Device Information Service\n");
|
||||
bledis.setModel(optstr(HW_VERSION));
|
||||
bledis.setFirmwareRev(optstr(APP_VERSION));
|
||||
bledis.begin();
|
||||
|
||||
// Start the BLE Battery Service and set it to 100%
|
||||
LOG_INFO("Configuring the Battery Service\n");
|
||||
blebas.begin();
|
||||
blebas.write(0); // Unknown battery level for now
|
||||
|
||||
// Setup the Heart Rate Monitor service using
|
||||
// BLEService and BLECharacteristic classes
|
||||
LOG_INFO("Configuring the Mesh bluetooth service\n");
|
||||
setupMeshService();
|
||||
|
||||
// Setup the advertising packet(s)
|
||||
LOG_INFO("Setting up the advertising payload(s)\n");
|
||||
startAdv();
|
||||
|
||||
LOG_INFO("Advertising\n");
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::resumeAdvertising()
|
||||
{
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
@@ -306,34 +269,28 @@ void NRF52Bluetooth::resumeAdvertising()
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0);
|
||||
}
|
||||
|
||||
/// Given a level between 0-100, update the BLE attribute
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
blebas.write(level);
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::clearBonds()
|
||||
{
|
||||
LOG_INFO("Clearing bluetooth bonds!\n");
|
||||
bond_print_list(BLE_GAP_ROLE_PERIPH);
|
||||
bond_print_list(BLE_GAP_ROLE_CENTRAL);
|
||||
|
||||
Bluefruit.Periph.clearBonds();
|
||||
Bluefruit.Central.clearBonds();
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle)
|
||||
{
|
||||
LOG_INFO("BLE connection secured\n");
|
||||
}
|
||||
|
||||
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
|
||||
{
|
||||
LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3);
|
||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||
screen->startBluetoothPinScreen(configuredPasskey);
|
||||
|
||||
if (match_request) {
|
||||
uint32_t start_time = millis();
|
||||
while (millis() < start_time + 30000) {
|
||||
@@ -344,13 +301,18 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke
|
||||
LOG_INFO("BLE passkey pairing: match_request=%i\n", match_request);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status)
|
||||
{
|
||||
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
|
||||
LOG_INFO("BLE pairing success\n");
|
||||
else
|
||||
LOG_INFO("BLE pairing failed\n");
|
||||
|
||||
screen->stopBluetoothPinScreen();
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::sendLog(const char *logMessage)
|
||||
{
|
||||
if (!isConnected() || strlen(logMessage) > 512)
|
||||
return;
|
||||
logRadio.notify(logMessage);
|
||||
}
|
||||
@@ -13,10 +13,10 @@ class NRF52Bluetooth : BluetoothApi
|
||||
void clearBonds();
|
||||
bool isConnected();
|
||||
int getRssi();
|
||||
void sendLog(const char *logMessage);
|
||||
|
||||
private:
|
||||
static void onConnectionSecured(uint16_t conn_handle);
|
||||
void convertToUint8(uint8_t target[4], uint32_t source);
|
||||
static bool onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request);
|
||||
static void onPairingCompleted(uint16_t conn_handle, uint8_t auth_status);
|
||||
};
|
||||
@@ -231,12 +231,10 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
|
||||
|
||||
nodeDB->saveToDisk();
|
||||
|
||||
#ifdef TTGO_T_ECHO
|
||||
#ifdef PIN_POWER_EN
|
||||
pinMode(PIN_POWER_EN, INPUT); // power off peripherals
|
||||
// pinMode(PIN_POWER_EN1, INPUT_PULLDOWN);
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_GPS
|
||||
// Kill GPS power completely (even if previously we just had it in sleep mode)
|
||||
if (gps)
|
||||
|
||||
25
variants/heltec_hru_3601/pins_arduino.h
Normal file
25
variants/heltec_hru_3601/pins_arduino.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <variant.h>
|
||||
|
||||
static const uint8_t TX = UART_TX;
|
||||
static const uint8_t RX = UART_RX;
|
||||
|
||||
static const uint8_t SDA = I2C_SDA;
|
||||
static const uint8_t SCL = I2C_SCL;
|
||||
|
||||
static const uint8_t SS = 8;
|
||||
static const uint8_t MOSI = 7;
|
||||
static const uint8_t MISO = 6;
|
||||
static const uint8_t SCK = 10;
|
||||
|
||||
static const uint8_t A0 = 0;
|
||||
static const uint8_t A1 = 1;
|
||||
static const uint8_t A2 = 2;
|
||||
static const uint8_t A3 = 3;
|
||||
static const uint8_t A4 = 4;
|
||||
static const uint8_t A5 = 5;
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
9
variants/heltec_hru_3601/platformio.ini
Normal file
9
variants/heltec_hru_3601/platformio.ini
Normal file
@@ -0,0 +1,9 @@
|
||||
[env:heltec-hru-3601]
|
||||
extends = esp32c3_base
|
||||
board = adafruit_qtpy_esp32c3
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-D HELTEC_HRU_3601
|
||||
-I variants/heltec_hru_3601
|
||||
lib_deps = ${esp32c3_base.lib_deps}
|
||||
adafruit/Adafruit NeoPixel @ ^1.12.0
|
||||
40
variants/heltec_hru_3601/variant.h
Normal file
40
variants/heltec_hru_3601/variant.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#define BUTTON_PIN 9
|
||||
|
||||
#define HAS_SCREEN 0
|
||||
#define HAS_GPS 0
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#define USE_SX1262
|
||||
#define LORA_SCK 10
|
||||
#define LORA_MISO 6
|
||||
#define LORA_MOSI 7
|
||||
#define LORA_CS 8
|
||||
#define LORA_DIO0 RADIOLIB_NC
|
||||
#define LORA_RESET 5
|
||||
#define LORA_DIO1 3
|
||||
#define LORA_DIO2 RADIOLIB_NC
|
||||
#define LORA_BUSY 4
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_BUSY
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// Vext_Ctrl pin controls 3.3V LDO (U2) which provides power to I2C peripheral
|
||||
#define PIN_POWER_EN 1
|
||||
|
||||
// Board has I2C connected to UART0 pins, and no other hardware serial port
|
||||
#define UART_TX -1
|
||||
#define UART_RX -1
|
||||
|
||||
// Board has I2C connected to U0RXD and U0TXD
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 20
|
||||
|
||||
// Board has RGB LED on GPIO2
|
||||
#define HAS_NEOPIXEL // Enable the use of neopixels
|
||||
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
|
||||
#define NEOPIXEL_DATA 2 // gpio pin used to send data to the neopixels
|
||||
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
|
||||
@@ -1,7 +1,7 @@
|
||||
[env:heltec-wireless-tracker]
|
||||
extends = esp32s3_base
|
||||
board = heltec_wireless_tracker
|
||||
upload_protocol = esp-builtin
|
||||
upload_protocol = esptool
|
||||
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker
|
||||
@@ -11,4 +11,4 @@ build_flags =
|
||||
|
||||
lib_deps =
|
||||
${esp32s3_base.lib_deps}
|
||||
lovyan03/LovyanGFX@^1.1.8
|
||||
lovyan03/LovyanGFX@^1.1.8
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
extends = esp32s3_base
|
||||
board = tlora-t3s3-v1
|
||||
board_check = true
|
||||
upload_protocol = esp-builtin
|
||||
upload_protocol = esptool
|
||||
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
[env:wio-sdk-wm1110]
|
||||
extends = nrf52840_base
|
||||
board = wio-sdk-wm1110
|
||||
|
||||
# Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board)
|
||||
build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB
|
||||
|
||||
board_level = extra
|
||||
; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -DWIO_WM1110
|
||||
@@ -12,4 +16,4 @@ lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
upload_protocol = jlink
|
||||
upload_protocol = jlink
|
||||
|
||||
@@ -31,6 +31,13 @@
|
||||
|
||||
#include "WVariant.h"
|
||||
|
||||
#ifdef USE_TINYUSB
|
||||
#error TinyUSB must be disabled by platformio before using this variant
|
||||
#endif
|
||||
|
||||
// We use the hardware serial port for the serial console
|
||||
#define Serial Serial1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
extends = nrf52840_base
|
||||
board = xiao_ble_sense
|
||||
board_level = extra
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Ivariants/xiao_ble/softdevice -Ivariants/xiao_ble/softdevice/nrf52 -D EBYTE_E22 -DPRIVATE_HW
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Ivariants/xiao_ble/softdevice -Ivariants/xiao_ble/softdevice/nrf52 -D EBYTE_E22 -DEBYTE_E22_900M30S -DPRIVATE_HW
|
||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||
board_build.ldscript = variants/xiao_ble/nrf52840_s140_v7.ld
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/xiao_ble>
|
||||
|
||||
@@ -142,6 +142,16 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
// (which is the default for the sx1262interface code)
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
#ifdef EBYTE_E22_900M30S
|
||||
// 10dB PA gain and 30dB rated output; based on PA output table from Ebyte Robin <sales06@ebyte.com>
|
||||
#define REGULATORY_GAIN_LORA 10
|
||||
#define SX126X_MAX_POWER 20
|
||||
#endif
|
||||
#ifdef EBYTE_E22_900M33S
|
||||
// 25dB PA gain and 33dB rated output; based on TX Power Curve from E22-900M33S_UserManual_EN_v1.0.pdf
|
||||
#define REGULATORY_GAIN_LORA 25
|
||||
#define SX126X_MAX_POWER 8
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 2
|
||||
minor = 3
|
||||
build = 13
|
||||
build = 14
|
||||
|
||||
Reference in New Issue
Block a user