diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index dd4133dab..81ff6ee25 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -45,6 +45,7 @@ jobs: - name: build .debpkg run: | + mkdir -p .debpkg/debian mkdir -p .debpkg/usr/share/doc/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd @@ -55,6 +56,7 @@ jobs: cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml chmod +x .debpkg/usr/sbin/meshtasticd cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service + echo "etc/meshtasticd/config.yaml" > .debpkg/debian/conffiles - uses: jiro4989/build-deb-action@v3 with: diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini index 5de0fa549..df66de2ed 100644 --- a/arch/esp32/esp32s2.ini +++ b/arch/esp32/esp32s2.ini @@ -2,14 +2,17 @@ extends = esp32_base build_src_filter = - ${esp32_base.build_src_filter} - - + ${esp32_base.build_src_filter} - - - monitor_speed = 115200 build_flags = ${esp32_base.build_flags} -DHAS_BLUETOOTH=0 + -DMESHTASTIC_EXCLUDE_PAXCOUNTER + -DMESHTASTIC_EXCLUDE_BLUETOOTH lib_ignore = ${esp32_base.lib_ignore} - NimBLE-Arduino \ No newline at end of file + NimBLE-Arduino + libpax \ No newline at end of file diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 53f06c9f3..4857933ec 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -1,6 +1,6 @@ ; The Portduino based sim environment on top of any host OS, all hardware will be simulated [portduino_base] -platform = https://github.com/meshtastic/platform-native.git#6fb39b6f94ece9c042141edb4afb91aca94dcaab +platform = https://github.com/meshtastic/platform-native.git#659e49346aa33008b150dfb206b1817ddabc7132 framework = arduino build_src_filter = @@ -24,7 +24,7 @@ lib_deps = ${env.lib_deps} ${networking_base.lib_deps} rweather/Crypto@^0.4.0 - lovyan03/LovyanGFX@^1.1.12 + https://github.com/lovyan03/LovyanGFX.git#d35e60f269dfecbb18a8cb0fd07d594c2fb7e7a8 build_flags = ${arduino_base.build_flags} @@ -34,4 +34,4 @@ build_flags = -DPORTDUINO_LINUX_HARDWARE -lbluetooth -lgpiod - -lyaml-cpp + -lyaml-cpp \ No newline at end of file diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index f729f1ac7..05b4a7b0a 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -38,6 +38,15 @@ Lora: # Busy: 20 # Reset: 18 +# Module: sx1268 # SX1268-based modules, tested with Ebyte E22 400M33S +# CS: 21 +# IRQ: 16 +# Busy: 20 +# Reset: 18 +# TXen: 6 +# RXen: 12 +# DIO3_TCXO_VOLTAGE: true + # DIO3_TCXO_VOLTAGE: true # the Waveshare Core1262 and others are known to need this setting # TXen: x # TX and RX enable pins @@ -96,17 +105,21 @@ Display: # Panel: ILI9341 # CS: 8 # DC: 25 -# Backlight: 2 -# Width: 320 -# Height: 240 +# Width: 240 +# Height: 320 +# Rotate: true Touchscreen: ### Note, at least for now, the touchscreen must have a CS pin defined, even if you let Linux manage the CS switching. -# Module: STMPE610 +# Module: STMPE610 # Option 1 for Adafruit PiTFT 2.8 # CS: 7 # IRQ: 24 +# Module: FT5x06 # Option 2 for Adafruit PiTFT 2.8 +# IRQ: 24 +# I2CAddr: 0x38 + # Module: XPT2046 # Waveshare 2.8inch # CS: 7 # IRQ: 17 diff --git a/platformio.ini b/platformio.ini index a1082a84a..e178fdb16 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,7 +78,7 @@ lib_deps = https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; 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#964f75a72cccd6b53cd74e4add1f7a42c6f7344d + https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0 nanopb/Nanopb@^0.4.7 erriez/ErriezCRC32@^1.0.1 diff --git a/protobufs b/protobufs index eade2c6be..e21899aa6 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit eade2c6befb65a9c46c5d28ae1e8e24c37a1a3d0 +Subproject commit e21899aa6b2b49863cfa2758e5e3b6faacf04bba diff --git a/src/AmbientLightingThread.h b/src/AmbientLightingThread.h index 98ccedde4..6b3360b1f 100644 --- a/src/AmbientLightingThread.h +++ b/src/AmbientLightingThread.h @@ -5,6 +5,16 @@ NCP5623 rgb; #endif +#ifdef HAS_NEOPIXEL +#include +Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_DATA, NEOPIXEL_TYPE); +#endif + +#ifdef UNPHONE +#include "unPhone.h" +extern unPhone unphone; +#endif + namespace concurrency { class AmbientLightingThread : public concurrency::OSThread @@ -27,15 +37,31 @@ class AmbientLightingThread : public concurrency::OSThread disable(); return; } +#endif +#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE) if (!moduleConfig.ambient_lighting.led_state) { LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF\n"); disable(); return; } LOG_DEBUG("AmbientLightingThread initializing\n"); +#ifdef HAS_NCP5623 if (_type == ScanI2C::NCP5623) { rgb.begin(); +#endif +#ifdef RGBLED_RED + pinMode(RGBLED_RED, OUTPUT); + pinMode(RGBLED_GREEN, OUTPUT); + pinMode(RGBLED_BLUE, OUTPUT); +#endif +#ifdef HAS_NEOPIXEL + pixels.begin(); // Initialise the pixel(s) + pixels.clear(); // Set all pixel colors to 'off' + pixels.setBrightness(moduleConfig.ambient_lighting.current); +#endif setLighting(); +#endif +#ifdef HAS_NCP5623 } #endif } @@ -43,16 +69,17 @@ class AmbientLightingThread : public concurrency::OSThread protected: int32_t runOnce() override { +#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE) #ifdef HAS_NCP5623 if (_type == ScanI2C::NCP5623 && moduleConfig.ambient_lighting.led_state) { +#endif setLighting(); return 30000; // 30 seconds to reset from any animations that may have been running from Ext. Notification - } else { - return disable(); +#ifdef HAS_NCP5623 } -#else - return disable(); #endif +#endif + return disable(); } private: @@ -65,9 +92,36 @@ class AmbientLightingThread : public concurrency::OSThread rgb.setRed(moduleConfig.ambient_lighting.red); rgb.setGreen(moduleConfig.ambient_lighting.green); rgb.setBlue(moduleConfig.ambient_lighting.blue); - LOG_DEBUG("Initializing Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n", + LOG_DEBUG("Initializing NCP5623 Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n", moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue); +#endif +#ifdef HAS_NEOPIXEL + pixels.fill(pixels.Color(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, + moduleConfig.ambient_lighting.blue), + 0, NEOPIXEL_COUNT); + pixels.show(); + LOG_DEBUG("Initializing NeoPixel Ambient lighting w/ brightness(current)=%d, red=%d, green=%d, blue=%d\n", + moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, + moduleConfig.ambient_lighting.blue); +#endif +#ifdef RGBLED_CA + analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red); + analogWrite(RGBLED_GREEN, 255 - moduleConfig.ambient_lighting.green); + analogWrite(RGBLED_BLUE, 255 - moduleConfig.ambient_lighting.blue); + LOG_DEBUG("Initializing Ambient lighting RGB Common Anode w/ red=%d, green=%d, blue=%d\n", + moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue); +#elif defined(RGBLED_RED) + analogWrite(RGBLED_RED, moduleConfig.ambient_lighting.red); + analogWrite(RGBLED_GREEN, moduleConfig.ambient_lighting.green); + analogWrite(RGBLED_BLUE, moduleConfig.ambient_lighting.blue); + LOG_DEBUG("Initializing Ambient lighting RGB Common Cathode w/ red=%d, green=%d, blue=%d\n", + moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue); +#endif +#ifdef UNPHONE + unphone.rgb(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue); + LOG_DEBUG("Initializing unPhone Ambient lighting w/ red=%d, green=%d, blue=%d\n", moduleConfig.ambient_lighting.red, + moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue); #endif } }; diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 206bb7239..4566de924 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -136,9 +136,12 @@ int32_t ButtonThread::runOnce() case BUTTON_EVENT_DOUBLE_PRESSED: { LOG_BUTTON("Double press!\n"); service.refreshLocalMeshNode(); - service.sendNetworkPing(NODENUM_BROADCAST, true); + auto sentPosition = service.trySendPosition(NODENUM_BROADCAST, true); if (screen) { - screen->print("Sent ad-hoc ping\n"); + if (sentPosition) + screen->print("Sent ad-hoc position\n"); + else + screen->print("Sent ad-hoc nodeinfo\n"); screen->forceDisplay(true); // Force a new UI frame, then force an EInk update } break; @@ -193,15 +196,13 @@ int32_t ButtonThread::runOnce() #ifdef BUTTON_PIN_TOUCH case BUTTON_EVENT_TOUCH_LONG_PRESSED: { LOG_BUTTON("Touch press!\n"); - if (config.display.wake_on_tap_or_motion) { - if (screen) { - // Wake if asleep - if (powerFSM.getState() == &stateDARK) - powerFSM.trigger(EVENT_PRESS); + if (screen) { + // Wake if asleep + if (powerFSM.getState() == &stateDARK) + powerFSM.trigger(EVENT_PRESS); - // Update display (legacy behaviour) - screen->forceDisplay(); - } + // Update display (legacy behaviour) + screen->forceDisplay(); } break; } diff --git a/src/Power.cpp b/src/Power.cpp index d13fd6891..2658b74a4 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -184,7 +184,7 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual uint16_t getBattVoltage() override { -#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) if (hasINA()) { LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address); return getINAVoltage(); @@ -360,7 +360,7 @@ class AnalogBatteryLevel : public HasBatteryLevel float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS); uint32_t last_read_time_ms = 0; -#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) uint16_t getINAVoltage() { if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index c8fcfee10..05a5cb2ea 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -41,9 +41,7 @@ class ScanI2C BQ24295, LSM6DS3, TCA9555, -#ifdef HAS_NCP5623 NCP5623, -#endif } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index e2e2188b6..ba2820a77 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -279,6 +279,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } else { // Unknown device LOG_INFO("No INA3221 found at address 0x%x\n", (uint8_t)addr.address); } + break; case MCP9808_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2); if (registerValue == 0x0400) { diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 0d0bfd9a2..17e35a4b3 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -452,7 +452,7 @@ bool GPS::setup() // Set the NEMA output messages // Ask for only RMC and GGA uint8_t fields[] = {CAS_NEMA_RMC, CAS_NEMA_GGA}; - for (int i = 0; i < sizeof(fields); i++) { + for (uint i = 0; i < sizeof(fields); i++) { // Construct a CAS-CFG-MSG packet uint8_t cas_cfg_msg_packet[] = {0x4e, fields[i], 0x01, 0x00}; msglen = makeCASPacket(0x06, 0x01, sizeof(cas_cfg_msg_packet), cas_cfg_msg_packet); @@ -1584,7 +1584,7 @@ bool GPS::hasFlow() bool GPS::whileIdle() { - int charsInBuf = 0; + uint charsInBuf = 0; bool isValid = false; if (!isAwake) { clearBuffer(); diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index 26af7cac2..a2cdb5b30 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -104,13 +104,15 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) bool shouldSet; if (q > currentQuality) { shouldSet = true; - LOG_DEBUG("Upgrading time to quality %d\n", q); - } else if (q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) { - // Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift + LOG_DEBUG("Upgrading time to quality %s\n", RtcName(q)); + } else if (q >= RTCQualityNTP && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) { + // Every 12 hrs we will slam in a new GPS or Phone GPS / NTP time, to correct for local RTC clock drift shouldSet = true; LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec); - } else + } else { shouldSet = false; + LOG_DEBUG("Current RTC quality: %s. Ignoring time of RTC quality of %s\n", RtcName(currentQuality), RtcName(q)); + } if (shouldSet) { currentQuality = q; @@ -162,6 +164,24 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) } } +const char *RtcName(RTCQuality quality) +{ + switch (quality) { + case RTCQualityNone: + return "None"; + case RTCQualityDevice: + return "Device"; + case RTCQualityFromNet: + return "Net"; + case RTCQualityNTP: + return "NTP"; + case RTCQualityGPS: + return "GPS"; + default: + return "Unknown"; + } +} + /** * Sets the RTC time if the provided time is of higher quality than the current RTC time. * @@ -203,7 +223,7 @@ int32_t getTZOffset() now = time(NULL); gmt = gmtime(&now); gmt->tm_isdst = -1; - return (int16_t)difftime(now, mktime(gmt)); + return (int32_t)difftime(now, mktime(gmt)); } /** diff --git a/src/gps/RTC.h b/src/gps/RTC.h index 0561819bd..1d609f136 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -28,6 +28,9 @@ RTCQuality getRTCQuality(); bool perhapsSetRTC(RTCQuality q, const struct timeval *tv); bool perhapsSetRTC(RTCQuality q, struct tm &t); +/// Return a string name for the quality +const char *RtcName(RTCQuality quality); + /// Return time since 1970 in secs. While quality is RTCQualityNone we will be returning time based at zero uint32_t getTime(bool local = false); diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index b396446fa..5b97b8d48 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -534,6 +534,10 @@ void EInkDynamicDisplay::checkBusyAsyncRefresh() return; } + + // Async refresh appears to have stopped, but wasn't caught by onNotify() + else + pollAsyncRefresh(); // Check (and terminate) the async refresh manually } // Hold control while an async refresh runs diff --git a/src/graphics/NeoPixel.h b/src/graphics/NeoPixel.h new file mode 100644 index 000000000..dde74366e --- /dev/null +++ b/src/graphics/NeoPixel.h @@ -0,0 +1,4 @@ +#ifdef HAS_NEOPIXEL +#include +extern Adafruit_NeoPixel pixels; +#endif \ No newline at end of file diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 12e549424..b529bf0e4 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -1,7 +1,6 @@ #include "configuration.h" #include "main.h" #if ARCH_PORTDUINO -#include "mesh_bus_spi.h" #include "platform/portduino/PortduinoGlue.h" #endif @@ -340,7 +339,7 @@ static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h class LGFX : public lgfx::LGFX_Device { lgfx::Panel_LCD *_panel_instance; - lgfx::Mesh_Bus_SPI _bus_instance; + lgfx::Bus_SPI _bus_instance; lgfx::ITouch *_touch_instance; @@ -357,7 +356,7 @@ class LGFX : public lgfx::LGFX_Device _panel_instance = new lgfx::Panel_ILI9341; auto buscfg = _bus_instance.config(); buscfg.spi_mode = 0; - _bus_instance.spi_device(DisplaySPI, settingsStrings[displayspidev]); + _bus_instance.spi_device(DisplaySPI); buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable) @@ -383,6 +382,8 @@ class LGFX : public lgfx::LGFX_Device _touch_instance = new lgfx::Touch_XPT2046; } else if (settingsMap[touchscreenModule] == stmpe610) { _touch_instance = new lgfx::Touch_STMPE610; + } else if (settingsMap[touchscreenModule] == ft5x06) { + _touch_instance = new lgfx::Touch_FT5x06; } auto touch_cfg = _touch_instance->config(); @@ -394,6 +395,9 @@ class LGFX : public lgfx::LGFX_Device touch_cfg.pin_int = settingsMap[touchscreenIRQ]; touch_cfg.bus_shared = true; touch_cfg.offset_rotation = 1; + if (settingsMap[touchscreenI2CAddr] != -1) { + touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr]; + } _touch_instance->config(touch_cfg); _panel_instance->setTouch(_touch_instance); @@ -711,4 +715,4 @@ bool TFTDisplay::connect() return true; } -#endif +#endif \ No newline at end of file diff --git a/src/graphics/mesh_bus_spi.cpp b/src/graphics/mesh_bus_spi.cpp deleted file mode 100644 index a9536d490..000000000 --- a/src/graphics/mesh_bus_spi.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// This code has been copied from LovyanGFX to make the SPI device selectable for touchscreens. -// Ideally this could eventually be an inherited class from BUS_SPI, -// but currently too many internal objects are set private. - -#include "configuration.h" -#if ARCH_PORTDUINO -#include "lgfx/v1/misc/pixelcopy.hpp" -#include "main.h" -#include "mesh_bus_spi.h" -#include -#include - -namespace lgfx -{ -inline namespace v1 -{ -//---------------------------------------------------------------------------- - -void Mesh_Bus_SPI::config(const config_t &config) -{ - _cfg = config; - - if (_cfg.pin_dc >= 0) { - pinMode(_cfg.pin_dc, pin_mode_t::output); - gpio_hi(_cfg.pin_dc); - } -} - -bool Mesh_Bus_SPI::init(void) -{ - dc_h(); - pinMode(_cfg.pin_dc, pin_mode_t::output); - if (SPIName != "") - PrivateSPI->begin(SPIName.c_str()); - else - PrivateSPI->begin(); - return true; -} - -void Mesh_Bus_SPI::release(void) -{ - PrivateSPI->end(); -} - -void Mesh_Bus_SPI::spi_device(HardwareSPI *newSPI, std::string newSPIName) -{ - PrivateSPI = newSPI; - SPIName = newSPIName; -} -void Mesh_Bus_SPI::beginTransaction(void) -{ - dc_h(); - SPISettings setting(_cfg.freq_write, MSBFIRST, _cfg.spi_mode); - PrivateSPI->beginTransaction(setting); -} - -void Mesh_Bus_SPI::endTransaction(void) -{ - PrivateSPI->endTransaction(); - dc_h(); -} - -void Mesh_Bus_SPI::beginRead(void) -{ - PrivateSPI->endTransaction(); - // SPISettings setting(_cfg.freq_read, BitOrder::MSBFIRST, _cfg.spi_mode, false); - SPISettings setting(_cfg.freq_read, MSBFIRST, _cfg.spi_mode); - PrivateSPI->beginTransaction(setting); -} - -void Mesh_Bus_SPI::endRead(void) -{ - PrivateSPI->endTransaction(); - beginTransaction(); -} - -void Mesh_Bus_SPI::wait(void) {} - -bool Mesh_Bus_SPI::busy(void) const -{ - return false; -} - -bool Mesh_Bus_SPI::writeCommand(uint32_t data, uint_fast8_t bit_length) -{ - dc_l(); - PrivateSPI->transfer((uint8_t *)&data, bit_length >> 3); - dc_h(); - return true; -} - -void Mesh_Bus_SPI::writeData(uint32_t data, uint_fast8_t bit_length) -{ - PrivateSPI->transfer((uint8_t *)&data, bit_length >> 3); -} - -void Mesh_Bus_SPI::writeDataRepeat(uint32_t data, uint_fast8_t bit_length, uint32_t length) -{ - const uint8_t dst_bytes = bit_length >> 3; - uint32_t limit = (dst_bytes == 3) ? 12 : 16; - auto buf = _flip_buffer.getBuffer(512); - size_t fillpos = 0; - reinterpret_cast(buf)[0] = data; - fillpos += dst_bytes; - uint32_t len; - do { - len = ((length - 1) % limit) + 1; - if (limit <= 64) - limit <<= 1; - - while (fillpos < len * dst_bytes) { - memcpy(&buf[fillpos], buf, fillpos); - fillpos += fillpos; - } - - PrivateSPI->transfer(buf, len * dst_bytes); - } while (length -= len); -} - -void Mesh_Bus_SPI::writePixels(pixelcopy_t *param, uint32_t length) -{ - const uint8_t dst_bytes = param->dst_bits >> 3; - uint32_t limit = (dst_bytes == 3) ? 12 : 16; - uint32_t len; - do { - len = ((length - 1) % limit) + 1; - if (limit <= 32) - limit <<= 1; - auto buf = _flip_buffer.getBuffer(len * dst_bytes); - param->fp_copy(buf, 0, len, param); - PrivateSPI->transfer(buf, len * dst_bytes); - } while (length -= len); -} - -void Mesh_Bus_SPI::writeBytes(const uint8_t *data, uint32_t length, bool dc, bool use_dma) -{ - if (dc) - dc_h(); - else - dc_l(); - PrivateSPI->transfer(const_cast(data), length); - if (!dc) - dc_h(); -} - -uint32_t Mesh_Bus_SPI::readData(uint_fast8_t bit_length) -{ - uint32_t res = 0; - bit_length >>= 3; - if (!bit_length) - return res; - int idx = 0; - do { - res |= PrivateSPI->transfer(0) << idx; - idx += 8; - } while (--bit_length); - return res; -} - -bool Mesh_Bus_SPI::readBytes(uint8_t *dst, uint32_t length, bool use_dma) -{ - do { - dst[0] = PrivateSPI->transfer(0); - ++dst; - } while (--length); - return true; -} - -void Mesh_Bus_SPI::readPixels(void *dst, pixelcopy_t *param, uint32_t length) -{ - uint32_t bytes = param->src_bits >> 3; - uint32_t dstindex = 0; - uint32_t len = 4; - uint8_t buf[24]; - param->src_data = buf; - do { - if (len > length) - len = length; - readBytes((uint8_t *)buf, len * bytes, true); - param->src_x = 0; - dstindex = param->fp_copy(dst, dstindex, dstindex + len, param); - length -= len; - } while (length); -} - -} // namespace v1 -} // namespace lgfx -#endif \ No newline at end of file diff --git a/src/graphics/mesh_bus_spi.h b/src/graphics/mesh_bus_spi.h deleted file mode 100644 index 903f7ad9d..000000000 --- a/src/graphics/mesh_bus_spi.h +++ /dev/null @@ -1,100 +0,0 @@ -#if ARCH_PORTDUINO -/*----------------------------------------------------------------------------/ - Lovyan GFX - Graphics library for embedded devices. - -Original Source: - https://github.com/lovyan03/LovyanGFX/ - -Licence: - [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) - -Author: - [lovyan03](https://twitter.com/lovyan03) - -Contributors: - [ciniml](https://github.com/ciniml) - [mongonta0716](https://github.com/mongonta0716) - [tobozo](https://github.com/tobozo) -/----------------------------------------------------------------------------*/ -#pragma once - -#include - -#include "lgfx/v1/Bus.hpp" -#include "lgfx/v1/platforms/common.hpp" - -namespace lgfx -{ -inline namespace v1 -{ -//---------------------------------------------------------------------------- - -class Mesh_Bus_SPI : public IBus -{ - public: - struct config_t { - uint32_t freq_write = 16000000; - uint32_t freq_read = 8000000; - // bool spi_3wire = true; - // bool use_lock = true; - int16_t pin_sclk = -1; - int16_t pin_miso = -1; - int16_t pin_mosi = -1; - int16_t pin_dc = -1; - uint8_t spi_mode = 0; - }; - - const config_t &config(void) const { return _cfg; } - - void config(const config_t &config); - - bus_type_t busType(void) const override { return bus_type_t::bus_spi; } - - bool init(void) override; - void release(void) override; - void spi_device(HardwareSPI *newSPI, std::string newSPIName); - - void beginTransaction(void) override; - void endTransaction(void) override; - void wait(void) override; - bool busy(void) const override; - - bool writeCommand(uint32_t data, uint_fast8_t bit_length) override; - void writeData(uint32_t data, uint_fast8_t bit_length) override; - void writeDataRepeat(uint32_t data, uint_fast8_t bit_length, uint32_t count) override; - void writePixels(pixelcopy_t *param, uint32_t length) override; - void writeBytes(const uint8_t *data, uint32_t length, bool dc, bool use_dma) override; - - void initDMA(void) {} - void flush(void) {} - void addDMAQueue(const uint8_t *data, uint32_t length) override { writeBytes(data, length, true, true); } - void execDMAQueue(void) {} - uint8_t *getDMABuffer(uint32_t length) override { return _flip_buffer.getBuffer(length); } - - void beginRead(void) override; - void endRead(void) override; - uint32_t readData(uint_fast8_t bit_length) override; - bool readBytes(uint8_t *dst, uint32_t length, bool use_dma) override; - void readPixels(void *dst, pixelcopy_t *param, uint32_t length) override; - - private: - HardwareSPI *PrivateSPI; - std::string SPIName; - __attribute__((always_inline)) inline void dc_h(void) { gpio_hi(_cfg.pin_dc); } - __attribute__((always_inline)) inline void dc_l(void) { gpio_lo(_cfg.pin_dc); } - - config_t _cfg; - FlipBuffer _flip_buffer; - bool _need_wait; - uint32_t _mask_reg_dc; - uint32_t _last_apb_freq = -1; - uint32_t _clkdiv_write; - uint32_t _clkdiv_read; - volatile uint32_t *_gpio_reg_dc_h; - volatile uint32_t *_gpio_reg_dc_l; -}; - -//---------------------------------------------------------------------------- -} // namespace v1 -} // namespace lgfx -#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b1a15634f..4a663a8a0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -179,6 +179,11 @@ const char *getDeviceName() static int32_t ledBlinker() { + // Still set up the blinking (heartbeat) interval but skip code path below, so LED will blink if + // config.device.led_heartbeat_disabled is changed + if (config.device.led_heartbeat_disabled) + return 1000; + static bool ledOn; ledOn ^= 1; @@ -607,7 +612,9 @@ void setup() } #endif -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) +#if defined(HAS_NEOPIXEL) || defined(UNPHONE) || defined(RGBLED_RED) + ambientLightingThread = new AmbientLightingThread(ScanI2C::DeviceType::NONE); +#elif !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) if (rgb_found.type != ScanI2C::DeviceType::NONE) { ambientLightingThread = new AmbientLightingThread(rgb_found.type); } @@ -763,6 +770,21 @@ void setup() LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio\n"); } } + } else if (settingsMap[use_sx1268]) { + if (!rIf) { + LOG_DEBUG("Attempting to activate sx1268 radio on SPI port %s\n", settingsStrings[spidev].c_str()); + LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(*LoraSPI, spiSettings); + rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], + settingsMap[busy]); + if (!rIf->init()) { + LOG_ERROR("Failed to find SX1268 radio\n"); + delete rIf; + rIf = NULL; + exit(EXIT_FAILURE); + } else { + LOG_INFO("SX1268 Radio init succeeded, using SX1268 radio\n"); + } + } } #elif defined(HW_SPI1_DEVICE) @@ -1001,4 +1023,4 @@ void loop() mainDelay.delay(delayMsec); } // if (didWake) LOG_DEBUG("wake!\n"); -} \ No newline at end of file +} diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 4cfe982d8..dd547a6f1 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -35,11 +35,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { - bool isAck = - ((c && c->error_reason == meshtastic_Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK - if (isAck && p->to != getNodeNum()) { - // do not flood direct message that is ACKed - LOG_DEBUG("Receiving an ACK not for me, but don't need to rebroadcast this direct message anymore.\n"); + bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); + if (isAckorReply && p->to != getNodeNum() && p->to != NODENUM_BROADCAST) { + // do not flood direct message that is ACKed or replied to + LOG_DEBUG("Receiving an ACK or reply not for me, but don't need to rebroadcast this direct message anymore.\n"); Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM } if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) { diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 2c1969e30..66a2e6952 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -193,10 +193,7 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p) } #endif if (p.from != 0) { // We don't let phones assign nodenums to their sent messages - LOG_WARN("phone tried to pick a nodenum, we don't allow that.\n"); p.from = 0; - } else { - // p.from = nodeDB->getNodeNum(); } if (p.id == 0) @@ -267,7 +264,7 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh } } -void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) +bool MeshService::trySendPosition(NodeNum dest, bool wantReplies) { meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum()); @@ -278,6 +275,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) if (positionModule) { LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel); positionModule->sendOurPosition(dest, wantReplies, node->channel); + return true; } } else { #endif @@ -286,6 +284,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) nodeInfoModule->sendOurNodeInfo(dest, wantReplies, node->channel); } } + return false; } void MeshService::sendToPhone(meshtastic_MeshPacket *p) diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 8d1434030..d777b7a01 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -108,8 +108,9 @@ class MeshService void reloadOwner(bool shouldSave = true); /// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least - /// sends our owner - void sendNetworkPing(NodeNum dest, bool wantReplies = false); + /// sends our nodeinfo + /// returns true if we sent a position + bool trySendPosition(NodeNum dest, bool wantReplies = false); /// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after /// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 39422b454..249db627e 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -352,9 +352,6 @@ void NodeDB::installDefaultModuleConfig() moduleConfig.external_notification.alert_message = true; moduleConfig.external_notification.output_ms = 100; moduleConfig.external_notification.active = true; -#endif -#ifdef TTGO_T_ECHO - config.display.wake_on_tap_or_motion = true; // Enable touch button for screen-on / refresh #endif moduleConfig.has_canned_message = true; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 63912a03e..f5eb35cbe 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -76,9 +76,12 @@ const RegionInfo regions[] = { RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false, false), /* - ??? + Taiwan, 920-925Mhz, limited to 0.5W indoor or coastal, 1.0W outdoor. + 5.8.1 in the Low-power Radio-frequency Devices Technical Regulations + https://www.ncc.gov.tw/english/files/23070/102_5190_230703_1_doc_C.PDF + https://gazette.nat.gov.tw/egFront/e_detail.do?metaid=147283 */ - RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false, false), + RDEF(TW, 920.0f, 925.0f, 100, 0, 27, true, false, false), /* https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf @@ -492,7 +495,7 @@ void RadioInterface::applyModemConfig() // If user has manually specified a channel num, then use that, otherwise generate one by hashing the name const char *channelName = channels.getName(channels.getPrimaryIndex()); // channel_num is actually (channel_num - 1), since modulus (%) returns values from 0 to (numChannels - 1) - int channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels; + uint channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels; // Check if we use the default frequency slot RadioInterface::uses_default_frequency_slot = @@ -586,4 +589,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) sendingPacket = p; return p->encrypted.size + sizeof(PacketHeader); -} \ No newline at end of file +} diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index 54629f522..ba9f90873 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 658 +#define meshtastic_ChannelSet_size 674 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 185a47a98..d9c7d4ffa 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -34,6 +34,9 @@ typedef enum _meshtastic_Channel_Role { typedef struct _meshtastic_ModuleSettings { /* Bits of precision for the location sent in position packets. */ uint32_t position_precision; + /* Controls whether or not the phone / clients should mute the current channel + Useful for noisy public channels you don't necessarily want to disable */ + bool is_client_muted; } meshtastic_ModuleSettings; typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t; @@ -126,14 +129,15 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default} -#define meshtastic_ModuleSettings_init_default {0} +#define meshtastic_ModuleSettings_init_default {0, 0} #define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN} #define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero} -#define meshtastic_ModuleSettings_init_zero {0} +#define meshtastic_ModuleSettings_init_zero {0, 0} #define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_ModuleSettings_position_precision_tag 1 +#define meshtastic_ModuleSettings_is_client_muted_tag 2 #define meshtastic_ChannelSettings_channel_num_tag 1 #define meshtastic_ChannelSettings_psk_tag 2 #define meshtastic_ChannelSettings_name_tag 3 @@ -159,7 +163,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) #define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings #define meshtastic_ModuleSettings_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, position_precision, 1) +X(a, STATIC, SINGULAR, UINT32, position_precision, 1) \ +X(a, STATIC, SINGULAR, BOOL, is_client_muted, 2) #define meshtastic_ModuleSettings_CALLBACK NULL #define meshtastic_ModuleSettings_DEFAULT NULL @@ -182,9 +187,9 @@ extern const pb_msgdesc_t meshtastic_Channel_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size -#define meshtastic_ChannelSettings_size 70 -#define meshtastic_Channel_size 85 -#define meshtastic_ModuleSettings_size 6 +#define meshtastic_ChannelSettings_size 72 +#define meshtastic_Channel_size 87 +#define meshtastic_ModuleSettings_size 8 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 2506ec647..b8cc80633 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -306,7 +306,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_DeviceState_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size -#define meshtastic_ChannelFile_size 702 +#define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 #define meshtastic_OEMStore_size 3346 #define meshtastic_PositionLite_size 28 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 67b2edd15..68d9b4707 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -148,6 +148,9 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_TD_LORAC = 60, /* CDEBYTE EoRa-S3 board using their own MM modules, clone of LILYGO T3S3 */ meshtastic_HardwareModel_CDEBYTE_EORA_S3 = 61, + /* TWC_MESH_V4 + Adafruit NRF52840 feather express with SX1262, SSD1306 OLED and NEO6M GPS */ + meshtastic_HardwareModel_TWC_MESH_V4 = 62, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index cbd6fee72..a8b1b994b 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -161,10 +161,10 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) if (!event->kbchar) { if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) { this->payload = 0xb4; - this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; + // this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; } else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) { this->payload = 0xb7; - this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; + // this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; } } else { // pass the pressed key @@ -233,14 +233,16 @@ int32_t CannedMessageModule::runOnce() { if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) { + temporaryMessage = ""; return INT32_MAX; } // LOG_DEBUG("Check status\n"); UIFrameEvent e = {false, true}; if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) || - (this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED)) { - // TODO: might have some feedback of sendig state + (this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) { + // TODO: might have some feedback of sending state this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; + temporaryMessage = ""; e.frameChanged = true; this->currentMessageIndex = -1; this->freetext = ""; // clear freetext @@ -434,7 +436,7 @@ int32_t CannedMessageModule::runOnce() } if (screen) screen->forceDisplay(); - runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; + showTemporaryMessage("GPS Toggled"); break; // mute (switch off/toggle) external notifications on fn+m @@ -442,18 +444,21 @@ int32_t CannedMessageModule::runOnce() if (moduleConfig.external_notification.enabled == true) { if (externalNotificationModule->getMute()) { externalNotificationModule->setMute(false); - runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; + showTemporaryMessage("Notifications \nEnabled"); } else { externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop externalNotificationModule->setMute(true); - runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; + showTemporaryMessage("Notifications \nDisabled"); } } break; case 0xaf: // fn+space send network ping like double press does service.refreshLocalMeshNode(); - service.sendNetworkPing(NODENUM_BROADCAST, true); - runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; + if (service.trySendPosition(NODENUM_BROADCAST, true)) { + showTemporaryMessage("Position \nUpdate Sent"); + } else { + showTemporaryMessage("Node Info \nUpdate Sent"); + } break; default: if (this->cursor == this->freetext.length()) { @@ -542,12 +547,27 @@ int CannedMessageModule::getPrevIndex() return this->currentMessageIndex - 1; } } +void CannedMessageModule::showTemporaryMessage(const String &message) +{ + temporaryMessage = message; + UIFrameEvent e = {false, true}; + e.frameChanged = true; + notifyObservers(&e); + runState = CANNED_MESSAGE_RUN_STATE_MESSAGE; + // run this loop again in 2 seconds, next iteration will clear the display + setIntervalFromNow(2000); +} void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { char buffer[50]; - if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) { + if (temporaryMessage.length() != 0) { + LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str()); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage); + } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) { display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); String displayString; @@ -766,4 +786,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor) return result; } -#endif \ No newline at end of file +#endif diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index 4802be078..faf1d80f3 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -10,6 +10,7 @@ enum cannedMessageModuleRunState { CANNED_MESSAGE_RUN_STATE_FREETEXT, CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE, CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED, + CANNED_MESSAGE_RUN_STATE_MESSAGE, CANNED_MESSAGE_RUN_STATE_ACTION_SELECT, CANNED_MESSAGE_RUN_STATE_ACTION_UP, CANNED_MESSAGE_RUN_STATE_ACTION_DOWN, @@ -51,6 +52,8 @@ class CannedMessageModule : public SinglePortModule, public Observable +#endif +#ifdef HAS_NEOPIXEL +#include +#endif + +#ifdef UNPHONE +#include "unPhone.h" +extern unPhone unphone; +#endif + +#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE) uint8_t red = 0; uint8_t green = 0; uint8_t blue = 0; @@ -108,27 +119,44 @@ int32_t ExternalNotificationModule::runOnce() millis()) { getExternal(2) ? setExternalOff(2) : setExternalOn(2); } +#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE) + red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7 + green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7 + blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7 #ifdef HAS_NCP5623 if (rgb_found.type == ScanI2C::NCP5623) { - red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7 - green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7 - blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7 rgb.setColor(red, green, blue); - - if (ascending) { // fade in - brightnessIndex++; - if (brightnessIndex == (sizeof(brightnessValues) - 1)) { - ascending = false; - } - } else { - brightnessIndex--; // fade out + } +#endif +#ifdef RGBLED_CA + analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic + analogWrite(RGBLED_GREEN, 255 - green); + analogWrite(RGBLED_BLUE, 255 - blue); +#elif defined(RGBLED_RED) + analogWrite(RGBLED_RED, red); + analogWrite(RGBLED_GREEN, green); + analogWrite(RGBLED_BLUE, blue); +#endif +#ifdef HAS_NEOPIXEL + pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT); + pixels.show(); +#endif +#ifdef UNPHONE + unphone.rgb(red, green, blue); +#endif + if (ascending) { // fade in + brightnessIndex++; + if (brightnessIndex == (sizeof(brightnessValues) - 1)) { + ascending = false; } - if (brightnessIndex == 0) { - ascending = true; - colorState++; // next color - if (colorState > 7) { - colorState = 1; - } + } else { + brightnessIndex--; // fade out + } + if (brightnessIndex == 0) { + ascending = true; + colorState++; // next color + if (colorState > 7) { + colorState = 1; } } #endif @@ -179,6 +207,9 @@ void ExternalNotificationModule::setExternalOn(uint8_t index) switch (index) { case 1: +#ifdef UNPHONE + unphone.vibe(true); // the unPhone's vibration motor is on a i2c GPIO expander +#endif if (moduleConfig.external_notification.output_vibra) digitalWrite(moduleConfig.external_notification.output_vibra, true); break; @@ -197,6 +228,22 @@ void ExternalNotificationModule::setExternalOn(uint8_t index) rgb.setColor(red, green, blue); } #endif +#ifdef RGBLED_CA + analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic + analogWrite(RGBLED_GREEN, 255 - green); + analogWrite(RGBLED_BLUE, 255 - blue); +#elif defined(RGBLED_RED) + analogWrite(RGBLED_RED, red); + analogWrite(RGBLED_GREEN, green); + analogWrite(RGBLED_BLUE, blue); +#endif +#ifdef HAS_NEOPIXEL + pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT); + pixels.show(); +#endif +#ifdef UNPHONE + unphone.rgb(red, green, blue); +#endif #ifdef T_WATCH_S3 drv.go(); #endif @@ -209,6 +256,9 @@ void ExternalNotificationModule::setExternalOff(uint8_t index) switch (index) { case 1: +#ifdef UNPHONE + unphone.vibe(false); // the unPhone's vibration motor is on a i2c GPIO expander +#endif if (moduleConfig.external_notification.output_vibra) digitalWrite(moduleConfig.external_notification.output_vibra, false); break; @@ -222,14 +272,33 @@ void ExternalNotificationModule::setExternalOff(uint8_t index) break; } +#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE) + red = 0; + green = 0; + blue = 0; #ifdef HAS_NCP5623 if (rgb_found.type == ScanI2C::NCP5623) { - red = 0; - green = 0; - blue = 0; rgb.setColor(red, green, blue); } #endif +#ifdef RGBLED_CA + analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic + analogWrite(RGBLED_GREEN, 255 - green); + analogWrite(RGBLED_BLUE, 255 - blue); +#elif defined(RGBLED_RED) + analogWrite(RGBLED_RED, red); + analogWrite(RGBLED_GREEN, green); + analogWrite(RGBLED_BLUE, blue); +#endif +#ifdef HAS_NEOPIXEL + pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT); + pixels.show(); +#endif +#ifdef UNPHONE + unphone.rgb(red, green, blue); +#endif +#endif + #ifdef T_WATCH_S3 drv.stop(); #endif @@ -244,7 +313,8 @@ void ExternalNotificationModule::stopNow() { rtttl::stop(); #ifdef HAS_I2S - audioThread->stop(); + if (audioThread->isPlaying()) + audioThread->stop(); #endif nagCycleCutoff = 1; // small value isNagging = false; @@ -327,6 +397,21 @@ ExternalNotificationModule::ExternalNotificationModule() rgb.begin(); rgb.setCurrent(10); } +#endif +#ifdef RGBLED_RED + pinMode(RGBLED_RED, OUTPUT); // set up the RGB led pins + pinMode(RGBLED_GREEN, OUTPUT); + pinMode(RGBLED_BLUE, OUTPUT); +#endif +#ifdef RGBLED_CA + analogWrite(RGBLED_RED, 255); // with a common anode type, logic is reversed + analogWrite(RGBLED_GREEN, 255); // so we want to initialise with lights off + analogWrite(RGBLED_BLUE, 255); +#endif +#ifdef HAS_NEOPIXEL + pixels.begin(); // Initialise the pixel(s) + pixels.clear(); // Set all pixel colors to 'off' + pixels.setBrightness(moduleConfig.ambient_lighting.current); #endif } else { LOG_INFO("External Notification Module Disabled\n"); @@ -508,4 +593,4 @@ void ExternalNotificationModule::handleSetRingtone(const char *from_msg) if (changed) { nodeDB->saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig); } -} \ No newline at end of file +} diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 250daec57..7c459dc35 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -71,14 +71,8 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes p.time); if (p.time && channels.getByIndex(mp.channel).role == meshtastic_Channel_Role_PRIMARY) { - struct timeval tv; - uint32_t secs = p.time; - - tv.tv_sec = secs; - tv.tv_usec = 0; - // Set from phone RTC Quality to RTCQualityNTP since it should be approximately so - perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv); + trySetRtc(p, isLocal); } nodeDB->updatePosition(getFrom(&mp), p); @@ -93,6 +87,33 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes return false; // Let others look at this message also if they want } +void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p) +{ + // Phone position packets need to be truncated to the channel precision + if (nodeDB->getNodeNum() == getFrom(&mp) && (precision < 32 && precision > 0)) { + LOG_DEBUG("Truncating phone position to channel precision %i\n", precision); + p->latitude_i = p->latitude_i & (UINT32_MAX << (32 - precision)); + p->longitude_i = p->longitude_i & (UINT32_MAX << (32 - precision)); + + // We want the imprecise position to be the middle of the possible location, not + p->latitude_i += (1 << (31 - precision)); + p->longitude_i += (1 << (31 - precision)); + + mp.decoded.payload.size = + pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), &meshtastic_Position_msg, p); + } +} + +void PositionModule::trySetRtc(meshtastic_Position p, bool isLocal) +{ + struct timeval tv; + uint32_t secs = p.time; + + tv.tv_sec = secs; + tv.tv_usec = 0; + perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv); +} + meshtastic_MeshPacket *PositionModule::allocReply() { if (precision == 0) { diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h index 0e24e3a9e..1161159f7 100644 --- a/src/modules/PositionModule.h +++ b/src/modules/PositionModule.h @@ -42,6 +42,8 @@ class PositionModule : public ProtobufModule, private concu */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *p) override; + virtual void alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p) override; + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ virtual meshtastic_MeshPacket *allocReply() override; @@ -52,6 +54,7 @@ class PositionModule : public ProtobufModule, private concu private: struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition); meshtastic_MeshPacket *allocAtakPli(); + void trySetRtc(meshtastic_Position p, bool isLocal); uint32_t precision; void sendLostAndFoundText(); diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index a52328ca4..fe1abab05 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -51,7 +51,7 @@ uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit; if (hopsUsed > config.lora.hop_limit) { return hopsUsed; // If the request used more hops than the limit, use the same amount of hops - } else if (hopsUsed + 2 < config.lora.hop_limit) { + } else if ((uint8_t)(hopsUsed + 2) < config.lora.hop_limit) { return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different } } diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index aad7b5d63..b9fdfcb63 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -1,5 +1,5 @@ #include "configuration.h" -#if defined(ARCH_ESP32) +#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_PAXCOUNTER #include "Default.h" #include "MeshService.h" #include "PaxcounterModule.h" diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index da1c204b8..508830203 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -54,9 +54,9 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length) JSONObject json; json = json_value->AsObject(); - // parse the channel name from the topic string by looking for "json/" - const char *jsonSlash = "json/"; - char *ptr = strstr(topic, jsonSlash) + sizeof(jsonSlash) + 1; // set pointer to after "json/" + // parse the channel name from the topic string + // the topic has been checked above for having jsonTopic prefix, so just move past it + char *ptr = topic + jsonTopic.length(); ptr = strtok(ptr, "/") ? strtok(ptr, "/") : ptr; // if another "/" was added, parse string up to that character meshtastic_Channel sendChannel = channels.getByName(ptr); // We allow downlink JSON packets only on a channel named "mqtt" @@ -76,6 +76,8 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length) p->channel = json["channel"]->AsNumber(); if (json.find("to") != json.end() && json["to"]->IsNumber()) p->to = json["to"]->AsNumber(); + if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber()) + p->hop_limit = json["hopLimit"]->AsNumber(); if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) { memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length()); p->decoded.payload.size = jsonPayloadStr.length(); @@ -105,6 +107,8 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length) p->channel = json["channel"]->AsNumber(); if (json.find("to") != json.end() && json["to"]->IsNumber()) p->to = json["to"]->AsNumber(); + if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber()) + p->hop_limit = json["hopLimit"]->AsNumber(); p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Position_msg, &pos); // make the Data protobuf from position @@ -548,7 +552,10 @@ void MQTT::perhapsReportToMap() } else { if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) { last_report_to_map = millis(); - LOG_WARN("MQTT Map reporting is enabled, but precision is 0 or no position available.\n"); + if (map_position_precision == 0) + LOG_WARN("MQTT Map reporting is enabled, but precision is 0\n"); + if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0) + LOG_WARN("MQTT Map reporting is enabled, but no position available.\n"); return; } @@ -904,6 +911,7 @@ bool MQTT::isValidJsonEnvelope(JSONObject &json) { // if "sender" is provided, avoid processing packets we uplinked return (json.find("sender") != json.end() ? (json["sender"]->AsString().compare(owner.id) != 0) : true) && + (json.find("hopLimit") != json.end() ? json["hopLimit"]->IsNumber() : true) && // hop limit should be a number (json.find("from") != json.end()) && json["from"]->IsNumber() && (json["from"]->AsNumber() == nodeDB->getNodeNum()) && // only accept message if the "from" is us (json.find("type") != json.end()) && json["type"]->IsString() && // should specify a type diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 35cd4fd84..3be3e7e55 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -52,6 +52,8 @@ #define HW_VENDOR meshtastic_HardwareModel_CANARYONE #elif defined(NORDIC_PCA10059) #define HW_VENDOR meshtastic_HardwareModel_NRF52840_PCA10059 +#elif defined(TWC_MESH_V4) +#define HW_VENDOR meshtastic_HardwareModel_TWC_MESH_V4 #elif defined(PRIVATE_HW) || defined(FEATHER_DIY) #define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW #else @@ -110,4 +112,4 @@ #if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA) // No serial ports on this board - ONLY use segger in memory console #define USE_SEGGER -#endif +#endif \ No newline at end of file diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index a04c9c12c..d86ac6677 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -136,6 +136,7 @@ void portduinoSetup() settingsMap[use_sx1262] = false; settingsMap[use_rf95] = false; settingsMap[use_sx1280] = false; + settingsMap[use_sx1268] = false; if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1262") { settingsMap[use_sx1262] = true; @@ -143,6 +144,8 @@ void portduinoSetup() settingsMap[use_rf95] = true; } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1280") { settingsMap[use_sx1280] = true; + } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1268") { + settingsMap[use_sx1268] = true; } settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as(false); settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(false); @@ -221,6 +224,7 @@ void portduinoSetup() settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as(-1); settingsMap[touchscreenBusFrequency] = yamlConfig["Touchscreen"]["BusFrequency"].as(1000000); settingsMap[touchscreenRotate] = yamlConfig["Touchscreen"]["Rotate"].as(-1); + settingsMap[touchscreenI2CAddr] = yamlConfig["Touchscreen"]["I2CAddr"].as(-1); if (yamlConfig["Touchscreen"]["spidev"]) { settingsStrings[touchscreenspidev] = "/dev/" + yamlConfig["Touchscreen"]["spidev"].as(""); } @@ -332,4 +336,4 @@ int initGPIOPin(int pinNum, std::string gpioChipName) std::cout << "Warning, cannot claim pin " << gpio_name << (p ? p.__cxa_exception_type()->name() : "null") << std::endl; return ERRNO_DISABLED; } -} +} \ No newline at end of file diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index ed2954eef..94cdbf2f8 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -13,6 +13,7 @@ enum configNames { dio3_tcxo_voltage, use_rf95, use_sx1280, + use_sx1268, user, gpiochip, spidev, @@ -21,6 +22,7 @@ enum configNames { touchscreenModule, touchscreenCS, touchscreenIRQ, + touchscreenI2CAddr, touchscreenBusFrequency, touchscreenRotate, touchscreenspidev, diff --git a/src/sleep.cpp b/src/sleep.cpp index e58c3872a..fe73a755c 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -211,7 +211,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) // esp_wifi_stop(); waitEnterSleep(skipPreflight); -#ifdef ARCH_ESP32 +#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH // Full shutdown of bluetooth hardware if (nimbleBluetooth) nimbleBluetooth->deinit(); diff --git a/variants/Dongle_nRF52840-pca10059-v1/variant.cpp b/variants/Dongle_nRF52840-pca10059-v1/variant.cpp index 8c6bf039c..2fc87c718 100644 --- a/variants/Dongle_nRF52840-pca10059-v1/variant.cpp +++ b/variants/Dongle_nRF52840-pca10059-v1/variant.cpp @@ -29,10 +29,7 @@ const uint32_t g_ADigitalPinMap[] = { void initVariant() { - // LED1 & LED2 + // LED1 pinMode(PIN_LED1, OUTPUT); ledOff(PIN_LED1); - - pinMode(PIN_LED2, OUTPUT); - ledOff(PIN_LED2); -} +} \ No newline at end of file diff --git a/variants/Dongle_nRF52840-pca10059-v1/variant.h b/variants/Dongle_nRF52840-pca10059-v1/variant.h index 533367a30..2318450eb 100644 --- a/variants/Dongle_nRF52840-pca10059-v1/variant.h +++ b/variants/Dongle_nRF52840-pca10059-v1/variant.h @@ -43,16 +43,12 @@ extern "C" { #define NUM_ANALOG_OUTPUTS (0) // LEDs -#define PIN_LED1 (0 + 12) // Blue LED P1.12 -#define PIN_LED2 (0 + 6) // Built in Green P0.06 - -// Green Built in LED1 -// #define PIN_LED1 (0 + 6) // LED1 P1.15 - -// RGB NeoPixel LED2 -// #define PIN_LED1 (0 + 8) Red -// #define PIN_LED1 (32 + 9) Green -// #define PIN_LED1 (0 + 12) Blue +#define PIN_LED1 (0 + 6) // Built in Green P0.06 +#define PIN_LED2 (0 + 6) // Just here for completeness +#define RGBLED_RED (0 + 8) // Red of RGB P0.08 +#define RGBLED_GREEN (32 + 9) // Green of RGB P1.09 +#define RGBLED_BLUE (0 + 12) // Blue of RGB P0.12 +#define RGBLED_CA // comment out this line if you have a common cathode type, as defined use common anode logic #define LED_BUILTIN PIN_LED1 #define LED_CONN PIN_LED2 @@ -168,4 +164,4 @@ static const uint8_t SCK = PIN_SPI_SCK; * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif \ No newline at end of file +#endif diff --git a/variants/TWC_mesh_v4/platformio.ini b/variants/TWC_mesh_v4/platformio.ini new file mode 100644 index 000000000..9cf25c685 --- /dev/null +++ b/variants/TWC_mesh_v4/platformio.ini @@ -0,0 +1,10 @@ +[env:TWC_mesh_v4] +extends = nrf52840_base +board = TWC_mesh_v4 +board_level = extra +build_flags = ${nrf52840_base.build_flags} -I variants/TWC_mesh_v4 -D TWC_mesh_v4 -L".pio\libdeps\TWC_mesh_v4\BSEC2 Software Library\src\cortex-m4\fpv4-sp-d16-hard" +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/TWC_mesh_v4> +lib_deps = + ${nrf52840_base.lib_deps} + zinggjm/GxEPD2@^1.4.9 +debug_tool = jlink \ No newline at end of file diff --git a/variants/TWC_mesh_v4/variant.cpp b/variants/TWC_mesh_v4/variant.cpp new file mode 100644 index 000000000..b3712346d --- /dev/null +++ b/variants/TWC_mesh_v4/variant.cpp @@ -0,0 +1,38 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); +} \ No newline at end of file diff --git a/variants/TWC_mesh_v4/variant.h b/variants/TWC_mesh_v4/variant.h new file mode 100644 index 000000000..6a6f541e6 --- /dev/null +++ b/variants/TWC_mesh_v4/variant.h @@ -0,0 +1,133 @@ +#ifndef _VARIANT_TWC_MESH_V4_ +#define _VARIANT_TWC_MESH_V4_ + +#define PCA10059 + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (32 + 10) // Blue LED P1.10 +#define PIN_LED2 (32 + 15) // Built in Green P1.15 + +// RGB NeoPixel LED2 +// #define PIN_LED1 (0 + 8) Red +// #define PIN_LED1 (32 + 9) Green +// #define PIN_LED1 (0 + 12) Blue + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 0 // State when LED is litted + +/* + * Buttons + */ +#define PIN_BUTTON1 (32 + 2) // BTN_DN P1.02 Built in button + +/* + * Analog pins + */ +#define PIN_A0 (0 + 29) // using VDIV (A6 / P0.29) + +static const uint8_t A0 = PIN_A0; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF (-1) // AREF Not yet used + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (0 + 24) +#define PIN_SERIAL1_TX (0 + 25) + +// Connected to Jlink CDC +#define PIN_SERIAL2_RX (-1) +#define PIN_SERIAL2_TX (-1) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (0 + 15) // MISO P0.15 +#define PIN_SPI_MOSI (0 + 13) // MOSI P0.13 +#define PIN_SPI_SCK (0 + 14) // SCK P0.14 + +static const uint8_t SS = (0 + 6); // LORA_CS P0.6 +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +////#define USE_EINK +#define USE_SSD1306 + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (0 + 12) // SDA P0.12 +#define PIN_WIRE_SCL (0 + 11) // SCL P0.11 + +// NiceRF 868 LoRa module +#define USE_SX1262 +#define USE_LLCC68 + +#define SX126X_CS (0 + 6) // LORA_CS P0.06 +#define SX126X_DIO1 (0 + 7) // DIO1 P0.07 +#define SX126X_BUSY (0 + 26) // LORA_BUSY P0.26 +#define SX126X_RESET (0 + 27) // LORA_RESET P0.27 +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define PIN_GPS_EN (-1) +#define PIN_GPS_PPS (-1) // Pulse per second input from the GPS + +#define GPS_RX_PIN PIN_SERIAL1_RX +#define GPS_TX_PIN PIN_SERIAL1_TX + +// Battery +// The battery sense is hooked to pin A6 (0.29) +#define BATTERY_PIN PIN_A0 +// and has 12 bit resolution +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER (2.0F) + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif \ No newline at end of file diff --git a/variants/betafpv_2400_tx_micro/platformio.ini b/variants/betafpv_2400_tx_micro/platformio.ini index 82fe2a9e4..531e8532d 100644 --- a/variants/betafpv_2400_tx_micro/platformio.ini +++ b/variants/betafpv_2400_tx_micro/platformio.ini @@ -15,4 +15,4 @@ upload_protocol = esptool upload_speed = 460800 lib_deps = ${esp32_base.lib_deps} - makuna/NeoPixelBus@^2.7.1 + adafruit/Adafruit NeoPixel @ ^1.12.0 \ No newline at end of file diff --git a/variants/betafpv_2400_tx_micro/variant.h b/variants/betafpv_2400_tx_micro/variant.h index 8c615d168..fd06183ee 100644 --- a/variants/betafpv_2400_tx_micro/variant.h +++ b/variants/betafpv_2400_tx_micro/variant.h @@ -1,5 +1,4 @@ // https://betafpv.com/products/elrs-micro-tx-module -#include // 0.96" OLED #define I2C_SDA 22 @@ -15,7 +14,11 @@ #define LORA_CS 5 #define RF95_FAN_EN 17 -#define LED_PIN 16 // This is a LED_WS2812 not a standard LED +// #define LED_PIN 16 // This is a LED_WS2812 not a standard LED +#define HAS_NEOPIXEL // Enable the use of neopixels +#define NEOPIXEL_COUNT 1 // How many neopixels are connected +#define NEOPIXEL_DATA 16 // gpio pin used to send data to the neopixels +#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use #define BUTTON_PIN 25 #define BUTTON_NEED_PULLUP @@ -31,4 +34,4 @@ #define SX128X_TXEN 26 #define SX128X_RXEN 27 #define SX128X_RESET LORA_RESET -#define SX128X_MAX_POWER 13 +#define SX128X_MAX_POWER 13 \ No newline at end of file diff --git a/variants/esp32-s3-pico/platformio.ini b/variants/esp32-s3-pico/platformio.ini index ef737d98a..ff77c30e0 100644 --- a/variants/esp32-s3-pico/platformio.ini +++ b/variants/esp32-s3-pico/platformio.ini @@ -22,4 +22,4 @@ build_flags = ${esp32_base.build_flags} lib_deps = ${esp32s3_base.lib_deps} zinggjm/GxEPD2@^1.5.3 - ;adafruit/Adafruit NeoPixel@^1.10.7 + adafruit/Adafruit NeoPixel @ ^1.12.0 \ No newline at end of file diff --git a/variants/esp32-s3-pico/variant.h b/variants/esp32-s3-pico/variant.h index 87378d378..bfcb6059d 100644 --- a/variants/esp32-s3-pico/variant.h +++ b/variants/esp32-s3-pico/variant.h @@ -10,6 +10,10 @@ // #define LED_PIN PIN_LED // Board has RGB LED 21 +#define HAS_NEOPIXEL // Enable the use of neopixels +#define NEOPIXEL_COUNT 1 // How many neopixels are connected +#define NEOPIXEL_DATA 21 // gpio pin used to send data to the neopixels +#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use // The usbPower state is revered ? // DEBUG | ??:??:?? 365 [Power] Battery: usbPower=0, isCharging=0, batMv=4116, batPct=90 diff --git a/variants/heltec_esp32c3/variant.h b/variants/heltec_esp32c3/variant.h index 6641f9d21..360d9bf1f 100644 --- a/variants/heltec_esp32c3/variant.h +++ b/variants/heltec_esp32c3/variant.h @@ -1,24 +1,16 @@ -#define I2C_SDA 1 -#define I2C_SCL 0 - #define BUTTON_PIN 9 -#define BUTTON_NEED_PULLUP -// LED flashes brighter +// LED pin on HT-DEV-ESP_V2 and HT-DEV-ESP_V3 // https://resource.heltec.cn/download/HT-CT62/HT-CT62_Reference_Design.pdf -#define LED_PIN 18 // LED -#define LED_INVERTED 1 +// https://resource.heltec.cn/download/HT-DEV-ESP/HT-DEV-ESP_V3_Sch.pdf +#define LED_PIN 2 // LED +#define LED_INVERTED 0 -#define HAS_SCREEN 1 +#define HAS_SCREEN 0 #define HAS_GPS 0 #undef GPS_RX_PIN #undef GPS_TX_PIN -#undef LORA_SCK -#undef LORA_MISO -#undef LORA_MOSI -#undef LORA_CS - #define USE_SX1262 #define LORA_SCK 10 #define LORA_MISO 6 diff --git a/variants/lora_relay_v1/platformio.ini b/variants/lora_relay_v1/platformio.ini index 77402aadc..8660bf64a 100644 --- a/variants/lora_relay_v1/platformio.ini +++ b/variants/lora_relay_v1/platformio.ini @@ -20,4 +20,5 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/lora_relay_v1> lib_deps = ${nrf52840_base.lib_deps} sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0 - bodmer/TFT_eSPI@^2.4.76 \ No newline at end of file + bodmer/TFT_eSPI@^2.4.76 + adafruit/Adafruit NeoPixel @ ^1.12.0 \ No newline at end of file diff --git a/variants/lora_relay_v1/variant.h b/variants/lora_relay_v1/variant.h index 9cfb69337..54bc87b68 100644 --- a/variants/lora_relay_v1/variant.h +++ b/variants/lora_relay_v1/variant.h @@ -44,7 +44,11 @@ extern "C" { // LEDs #define PIN_LED1 (3) #define PIN_LED2 (4) -#define PIN_NEOPIXEL (8) +// #define PIN_NEOPIXEL (8) +#define HAS_NEOPIXEL // Enable the use of neopixels +#define NEOPIXEL_COUNT 1 // How many neopixels are connected +#define NEOPIXEL_DATA 8 // gpio pin used to send data to the neopixels +#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use #define LED_BUILTIN PIN_LED1 #define LED_CONN PIN_LED2 diff --git a/variants/lora_relay_v2/platformio.ini b/variants/lora_relay_v2/platformio.ini index 4439d8a46..cd2109f00 100644 --- a/variants/lora_relay_v2/platformio.ini +++ b/variants/lora_relay_v2/platformio.ini @@ -23,3 +23,4 @@ lib_deps = ${nrf52840_base.lib_deps} sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0 bodmer/TFT_eSPI@^2.4.76 + adafruit/Adafruit NeoPixel @ ^1.12.0 \ No newline at end of file diff --git a/variants/lora_relay_v2/variant.h b/variants/lora_relay_v2/variant.h index 3afe8620e..6ef7ad7d6 100644 --- a/variants/lora_relay_v2/variant.h +++ b/variants/lora_relay_v2/variant.h @@ -61,7 +61,12 @@ extern "C" { // LEDs #define PIN_LED1 (3) #define PIN_LED2 (4) -#define PIN_NEOPIXEL (8) +// #define PIN_NEOPIXEL (8) +#define HAS_NEOPIXEL // Enable the use of neopixels +#define NEOPIXEL_COUNT 1 // How many neopixels are connected +#define NEOPIXEL_DATA 8 // gpio pin used to send data to the neopixels +#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use + #define PIN_BUZZER (40) #define LED_BUILTIN PIN_LED1 diff --git a/variants/my_esp32s3_diy_eink/platformio.ini b/variants/my_esp32s3_diy_eink/platformio.ini index 966bc580e..e81f2c1ab 100644 --- a/variants/my_esp32s3_diy_eink/platformio.ini +++ b/variants/my_esp32s3_diy_eink/platformio.ini @@ -13,7 +13,7 @@ platform_packages = lib_deps = ${esp32_base.lib_deps} zinggjm/GxEPD2@^1.5.1 - adafruit/Adafruit NeoPixel@^1.10.7 + adafruit/Adafruit NeoPixel @ ^1.12.0 build_unflags = -DARDUINO_USB_MODE=1 build_flags = ;${esp32_base.build_flags} -D MY_ESP32S3_DIY -I variants/my_esp32s3_diy_eink @@ -24,4 +24,4 @@ build_flags = -DEINK_HEIGHT=128 -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue - -DARDUINO_USB_MODE=0 + -DARDUINO_USB_MODE=0 \ No newline at end of file diff --git a/variants/my_esp32s3_diy_eink/variant.h b/variants/my_esp32s3_diy_eink/variant.h index 516fa7f34..024f912dd 100644 --- a/variants/my_esp32s3_diy_eink/variant.h +++ b/variants/my_esp32s3_diy_eink/variant.h @@ -12,6 +12,10 @@ #define I2C_SCL 17 // 2 // #define LED_PIN 38 // This is a RGB LED not a standard LED +#define HAS_NEOPIXEL // Enable the use of neopixels +#define NEOPIXEL_COUNT 1 // How many neopixels are connected +#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels +#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use #define BUTTON_PIN 0 // This is the BOOT button #define BUTTON_NEED_PULLUP diff --git a/variants/my_esp32s3_diy_oled/platformio.ini b/variants/my_esp32s3_diy_oled/platformio.ini index 9b8b09f7f..2d7a5cd91 100644 --- a/variants/my_esp32s3_diy_oled/platformio.ini +++ b/variants/my_esp32s3_diy_oled/platformio.ini @@ -12,11 +12,11 @@ platform_packages = tool-esptoolpy@^1.40500.0 lib_deps = ${esp32_base.lib_deps} - adafruit/Adafruit NeoPixel@^1.10.7 + adafruit/Adafruit NeoPixel @ ^1.12.0 build_unflags = -DARDUINO_USB_MODE=1 build_flags = ;${esp32_base.build_flags} -D MY_ESP32S3_DIY -I variants/my_esp32s3_diy_oled ${esp32_base.build_flags} -D PRIVATE_HW -I variants/my_esp32s3_diy_oled -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue - -DARDUINO_USB_MODE=0 + -DARDUINO_USB_MODE=0 \ No newline at end of file diff --git a/variants/my_esp32s3_diy_oled/variant.h b/variants/my_esp32s3_diy_oled/variant.h index 6dd18c236..8a3a39003 100644 --- a/variants/my_esp32s3_diy_oled/variant.h +++ b/variants/my_esp32s3_diy_oled/variant.h @@ -12,6 +12,10 @@ #define I2C_SCL 17 // 2 // #define LED_PIN 38 // This is a RGB LED not a standard LED +#define HAS_NEOPIXEL // Enable the use of neopixels +#define NEOPIXEL_COUNT 1 // How many neopixels are connected +#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels +#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use #define BUTTON_PIN 0 // This is the BOOT button #define BUTTON_NEED_PULLUP @@ -53,4 +57,4 @@ // #define PIN_EINK_DC 1 // #define PIN_EINK_RES (-1) // #define PIN_EINK_SCLK 5 -// #define PIN_EINK_MOSI 6 +// #define PIN_EINK_MOSI 6 \ No newline at end of file diff --git a/variants/rak11310/variant.h b/variants/rak11310/variant.h index ba3d4fed7..f9dcbd91a 100644 --- a/variants/rak11310/variant.h +++ b/variants/rak11310/variant.h @@ -14,7 +14,7 @@ #define BATTERY_PIN 26 #define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION // ratio of voltage divider = 3.0 (R17=200k, R18=100k) -#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic +#define ADC_MULTIPLIER 1.84 #define DETECTION_SENSOR_EN 28 @@ -47,4 +47,4 @@ // DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#endif \ No newline at end of file +#endif diff --git a/variants/unphone/platformio.ini b/variants/unphone/platformio.ini index dad9a7177..e4a92fe4c 100644 --- a/variants/unphone/platformio.ini +++ b/variants/unphone/platformio.ini @@ -13,6 +13,7 @@ build_unflags = -D ARDUINO_USB_MODE build_flags = ${esp32_base.build_flags} + ;-D BOARD_HAS_PSRAM // what's up with this - doesn't seem to be recognised at boot -D UNPHONE -I variants/unphone -D ARDUINO_USB_MODE=0 @@ -27,4 +28,5 @@ build_src_filter = ${esp32_base.build_src_filter} +<../variants/unphone> lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX @ ^1.1.8 - https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic @ ^9.0.0 \ No newline at end of file + https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic @ ^9.0.0 + adafruit/Adafruit NeoPixel @ ^1.12.0 \ No newline at end of file diff --git a/variants/unphone/variant.cpp b/variants/unphone/variant.cpp index 3f6d1c54d..7884f82e3 100644 --- a/variants/unphone/variant.cpp +++ b/variants/unphone/variant.cpp @@ -10,6 +10,7 @@ void initVariant() unphone.printWakeupReason(); // what woke us up? (stored, not printed :|) unphone.checkPowerSwitch(); // if power switch is off, shutdown unphone.backlight(false); // setup backlight and make sure its off + unphone.expanderPower(true); // enable power to expander / hat / sheild for (int i = 0; i < 3; i++) { // buzz a bit unphone.vibe(true); diff --git a/variants/unphone/variant.h b/variants/unphone/variant.h index 180fdfe2c..7d5c30f79 100644 --- a/variants/unphone/variant.h +++ b/variants/unphone/variant.h @@ -48,7 +48,7 @@ #undef GPS_RX_PIN #undef GPS_TX_PIN -#define HAS_SDCARD 1 +// #define HAS_SDCARD 1 // causes hang if defined #define SDCARD_CS 43 #define LED_PIN 13 // the red part of the RGB LED diff --git a/variants/xiao_ble/variant.h b/variants/xiao_ble/variant.h index e2b8eb613..77af08278 100644 --- a/variants/xiao_ble/variant.h +++ b/variants/xiao_ble/variant.h @@ -181,6 +181,7 @@ static const uint8_t SCL = PIN_WIRE_SCL; #define BAT_READ \ 14 // P0_14 = 14 Reads battery voltage from divider on signal board. (PIN_VBAT is reading voltage divider on XIAO and is // program pin 32 / or P0.31) +#define BATTERY_SENSE_RESOLUTION_BITS 10 #define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED #define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge diff --git a/version.properties b/version.properties index 485f55130..36607a956 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 7 +build = 8