diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml
index 2b6ffce0a..b027a36cc 100644
--- a/.github/ISSUE_TEMPLATE/feature.yml
+++ b/.github/ISSUE_TEMPLATE/feature.yml
@@ -16,6 +16,9 @@ body:
options:
- NRF52
- ESP32
+ - RP2040
+ - Linux Native
+ - other
validations:
required: true
- type: textarea
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index 999e57076..0af49fc80 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -3,7 +3,7 @@
platform = platformio/nordicnrf52@^10.4.0
extends = arduino_base
-build_type = release
+build_type = debug
build_flags =
${arduino_base.build_flags}
-DSERIAL_BUFFER_SIZE=1024
diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml
index 05b4a7b0a..333d6eadc 100644
--- a/bin/config-dist.yaml
+++ b/bin/config-dist.yaml
@@ -52,6 +52,8 @@ Lora:
# TXen: x # TX and RX enable pins
# RXen: x
+# ch341_quirk: true # Uncomment this to use the chunked SPI transfer that seems to fix the ch341
+
### Set gpio chip to use in /dev/. Defaults to 0.
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
# gpiochip: 4
diff --git a/boards/promicro-nrf52840.json b/boards/promicro-nrf52840.json
new file mode 100644
index 000000000..99ae3f01e
--- /dev/null
+++ b/boards/promicro-nrf52840.json
@@ -0,0 +1,52 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "nrf52840_s140_v6.ld"
+ },
+ "core": "nRF5",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
+ "f_cpu": "64000000L",
+ "hwids": [
+ ["0x239A", "0x00B3"],
+ ["0x239A", "0x8029"],
+ ["0x239A", "0x0029"],
+ ["0x239A", "0x002A"],
+ ["0x239A", "0x802A"]
+ ],
+ "usb_product": "ProMicro compatible nRF52840",
+ "mcu": "nrf52840",
+ "variant": "promicro_diy",
+ "bsp": {
+ "name": "adafruit"
+ },
+ "softdevice": {
+ "sd_flags": "-DS140",
+ "sd_name": "s140",
+ "sd_version": "6.1.1",
+ "sd_fwid": "0x00B6"
+ },
+ "bootloader": {
+ "settings_addr": "0xFF000"
+ }
+ },
+ "connectivity": ["bluetooth"],
+ "debug": {
+ "jlink_device": "nRF52840_xxAA",
+ "svd_path": "nrf52840.svd"
+ },
+ "frameworks": ["arduino"],
+ "name": "ProMicro compatible nRF52840",
+ "upload": {
+ "maximum_ram_size": 248832,
+ "maximum_size": 815104,
+ "speed": 115200,
+ "protocol": "nrfutil",
+ "protocols": ["nrfutil", "jlink", "nrfjprog", "stlink"],
+ "use_1200bps_touch": true,
+ "require_upload_port": true,
+ "wait_for_upload_port": true
+ },
+ "url": "https://www.nologo.tech/product/otherboard/NRF52840.html",
+ "vendor": "Nologo"
+}
diff --git a/platformio.ini b/platformio.ini
index a6db1c76e..9d7c76fbf 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -133,3 +133,4 @@ lib_deps =
https://github.com/lewisxhe/SensorLib#27fd0f721e20cd09e1f81383f0ba58a54fe84a17
adafruit/Adafruit LSM6DS@^4.7.2
mprograms/QMC5883LCompass@^1.2.0
+ https://github.com/Sensirion/arduino-i2c-sht4x#1.1.0
diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp
index 4566de924..aaead62be 100644
--- a/src/ButtonThread.cpp
+++ b/src/ButtonThread.cpp
@@ -52,8 +52,8 @@ ButtonThread::ButtonThread() : OSThread("Button")
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
userButton.attachClick(userButtonPressed);
- userButton.setClickMs(250);
- userButton.setPressMs(c_longPressTime);
+ userButton.setClickMs(BUTTON_CLICK_MS);
+ userButton.setPressMs(BUTTON_LONGPRESS_MS);
userButton.setDebounceMs(1);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed, this); // Reference to instance: get click count from non-static OneButton
@@ -70,8 +70,8 @@ ButtonThread::ButtonThread() : OSThread("Button")
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
#endif
userButtonAlt.attachClick(userButtonPressed);
- userButtonAlt.setClickMs(250);
- userButtonAlt.setPressMs(c_longPressTime);
+ userButtonAlt.setClickMs(BUTTON_CLICK_MS);
+ userButtonAlt.setPressMs(BUTTON_LONGPRESS_MS);
userButtonAlt.setDebounceMs(1);
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
@@ -80,7 +80,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#ifdef BUTTON_PIN_TOUCH
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
- userButtonTouch.setPressMs(400);
+ userButtonTouch.setPressMs(BUTTON_TOUCH_MS);
userButtonTouch.attachLongPressStart(touchPressedLongStart); // Better handling with longpress than click?
#endif
@@ -214,6 +214,7 @@ int32_t ButtonThread::runOnce()
btnEvent = BUTTON_EVENT_NONE;
}
+ runASAP = false;
return 50;
}
@@ -234,6 +235,7 @@ void ButtonThread::attachButtonInterrupts()
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
ButtonThread::userButton.tick();
+ runASAP = true;
},
CHANGE);
#endif
@@ -280,6 +282,7 @@ void ButtonThread::wakeOnIrq(int irq, int mode)
[] {
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
+ runASAP = true;
},
FALLING);
}
diff --git a/src/ButtonThread.h b/src/ButtonThread.h
index 07c7ccff7..d7a9201a3 100644
--- a/src/ButtonThread.h
+++ b/src/ButtonThread.h
@@ -4,11 +4,22 @@
#include "concurrency/OSThread.h"
#include "configuration.h"
+#ifndef BUTTON_CLICK_MS
+#define BUTTON_CLICK_MS 250
+#endif
+
+#ifndef BUTTON_LONGPRESS_MS
+#define BUTTON_LONGPRESS_MS 5000
+#endif
+
+#ifndef BUTTON_TOUCH_MS
+#define BUTTON_TOCH_MS 400
+#endif
+
class ButtonThread : public concurrency::OSThread
{
public:
- static const uint32_t c_longPressTime = 5000; // shutdown after 5s
- static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot
+ static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot
enum ButtonEventType {
BUTTON_EVENT_NONE,
diff --git a/src/configuration.h b/src/configuration.h
index fb16f3e37..7f38ed35e 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -126,7 +126,7 @@ along with this program. If not, see .
#define SHTC3_ADDR 0x70
#define LPS22HB_ADDR 0x5C
#define LPS22HB_ADDR_ALT 0x5D
-#define SHT31_ADDR 0x44
+#define SHT31_4x_ADDR 0x44
#define PMSA0031_ADDR 0x12
#define RCWL9620_ADDR 0x57
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index 20f22040c..a53df11f3 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -29,6 +29,7 @@ class ScanI2C
INA3221,
MCP9808,
SHT31,
+ SHT4X,
SHTC3,
LPS22HB,
QMC6310,
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index d28d67f83..35a47f77b 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -292,7 +292,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
break;
- SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n")
+ case SHT31_4x_ADDR:
+ registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
+ if (registerValue == 0x11a2) {
+ type = SHT4X;
+ LOG_INFO("SHT4X sensor found\n");
+ } else {
+ type = SHT31;
+ LOG_INFO("SHT31 sensor found\n");
+ }
+
+ break;
+
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n")
SCAN_SIMPLE_CASE(RCWL9620_ADDR, RCWL9620, "RCWL9620 sensor found\n")
@@ -357,4 +368,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
-}
\ No newline at end of file
+}
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 969d98863..7cb4618f9 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -94,6 +94,11 @@ std::vector moduleFrames;
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
static char ourId[5];
+// vector where symbols (string) are displayed in bottom corner of display.
+std::vector functionSymbals;
+// string displayed in bottom right corner of display. Created from elements in functionSymbals vector
+std::string functionSymbalString = "";
+
#if HAS_GPS
// GeoCoord object for the screen
GeoCoord geoCoord;
@@ -260,6 +265,18 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
#endif
}
+// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
+static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
+{
+ // LOG_DEBUG("Drawing function overlay\n");
+ if (functionSymbals.begin() != functionSymbals.end()) {
+ char buf[64];
+ display->setFont(FONT_SMALL);
+ snprintf(buf, sizeof(buf), "%s", functionSymbalString.c_str());
+ display->drawString(SCREEN_WIDTH - display->getStringWidth(buf), SCREEN_HEIGHT - FONT_HEIGHT_SMALL, buf);
+ }
+}
+
#ifdef USE_EINK
/// Used on eink displays while in deep sleep
static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
@@ -1023,7 +1040,14 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
#if !ARCH_PORTDUINO
dispdev->displayOn();
#endif
+
+#if defined(ST7789_CS) && \
+ !defined(M5STACK) // set display brightness when turning on screens. Just moved function from TFTDisplay to here.
+ static_cast(dispdev)->setDisplayBrightness(brightness);
+#endif
+
dispdev->displayOn();
+
enabled = true;
setInterval(0); // Draw ASAP
runASAP = true;
@@ -1490,6 +1514,11 @@ void Screen::setFrames()
ui->setFrames(normalFrames, numframes);
ui->enableAllIndicators();
+ // Add function overlay here. This can show when notifications muted, modifier key is active etc
+ static OverlayCallback functionOverlay[] = {drawFunctionOverlay};
+ static const int functionOverlayCount = sizeof(functionOverlay) / sizeof(functionOverlay[0]);
+ ui->setOverlays(functionOverlay, functionOverlayCount);
+
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed)
@@ -1573,9 +1602,55 @@ void Screen::blink()
delay(50);
count = count - 1;
}
+ // The dispdev->setBrightness does not work for t-deck display, it seems to run the setBrightness function in OLEDDisplay.
dispdev->setBrightness(brightness);
}
+void Screen::increaseBrightness()
+{
+ brightness = ((brightness + 62) > 254) ? brightness : (brightness + 62);
+
+#if defined(ST7789_CS)
+ // run the setDisplayBrightness function. This works on t-decks
+ static_cast(dispdev)->setDisplayBrightness(brightness);
+#endif
+
+ /* TO DO: add little popup in center of screen saying what brightness level it is set to*/
+}
+
+void Screen::decreaseBrightness()
+{
+ brightness = (brightness < 70) ? brightness : (brightness - 62);
+
+#if defined(ST7789_CS)
+ static_cast(dispdev)->setDisplayBrightness(brightness);
+#endif
+
+ /* TO DO: add little popup in center of screen saying what brightness level it is set to*/
+}
+
+void Screen::setFunctionSymbal(std::string sym)
+{
+ if (std::find(functionSymbals.begin(), functionSymbals.end(), sym) == functionSymbals.end()) {
+ functionSymbals.push_back(sym);
+ functionSymbalString = "";
+ for (auto symbol : functionSymbals) {
+ functionSymbalString = symbol + " " + functionSymbalString;
+ }
+ setFastFramerate();
+ }
+}
+
+void Screen::removeFunctionSymbal(std::string sym)
+{
+ functionSymbals.erase(std::remove(functionSymbals.begin(), functionSymbals.end(), sym), functionSymbals.end());
+ functionSymbalString = "";
+ for (auto symbol : functionSymbals) {
+ functionSymbalString = symbol + " " + functionSymbalString;
+ }
+ setFastFramerate();
+}
+
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
{
std::string uptime;
@@ -1998,4 +2073,4 @@ int Screen::handleInputEvent(const InputEvent *event)
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
-#endif // HAS_SCREEN
+#endif // HAS_SCREEN
\ No newline at end of file
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index 2cb1cd5a9..cfb08c0f4 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -166,9 +166,6 @@ class Screen : public concurrency::OSThread
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
- // Implementation to Adjust Brightness
- uint8_t brightness = BRIGHTNESS_DEFAULT;
-
/// Starts showing the Bluetooth PIN screen.
//
// Switches over to a static frame showing the Bluetooth pairing screen
@@ -202,6 +199,13 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd);
}
+ // functions for display brightness
+ void increaseBrightness();
+ void decreaseBrightness();
+
+ void setFunctionSymbal(std::string sym);
+ void removeFunctionSymbal(std::string sym);
+
/// Stops showing the bluetooth PIN screen.
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
@@ -395,6 +399,9 @@ class Screen : public concurrency::OSThread
// Bluetooth PIN screen)
bool showingNormalScreen = false;
+ // Implementation to Adjust Brightness
+ uint8_t brightness = BRIGHTNESS_DEFAULT; // H = 254, MH = 192, ML = 130 L = 103
+
/// Holds state for debug information
DebugInfo debugInfo;
diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp
index c1471745e..eb363260e 100644
--- a/src/graphics/TFTDisplay.cpp
+++ b/src/graphics/TFTDisplay.cpp
@@ -607,7 +607,7 @@ void TFTDisplay::sendCommand(uint8_t com)
unphone.backlight(true); // using unPhone library
#endif
#ifdef RAK14014
-#elif !defined(M5STACK)
+#elif !defined(M5STACK) && !defined(ST7789_CS) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function
tft->setBrightness(172);
#endif
break;
@@ -651,6 +651,12 @@ void TFTDisplay::sendCommand(uint8_t com)
// Drop all other commands to device (we just update the buffer)
}
+void TFTDisplay::setDisplayBrightness(uint8_t _brightness)
+{
+ tft->setBrightness(_brightness);
+ LOG_DEBUG("Brightness is set to value: %i \n", _brightness);
+}
+
void TFTDisplay::flipScreenVertically()
{
#if defined(T_WATCH_S3)
diff --git a/src/graphics/TFTDisplay.h b/src/graphics/TFTDisplay.h
index 3d6ea6cc6..42aa3abff 100644
--- a/src/graphics/TFTDisplay.h
+++ b/src/graphics/TFTDisplay.h
@@ -30,6 +30,9 @@ class TFTDisplay : public OLEDDisplay
static bool hasTouch(void);
static bool getTouch(int16_t *x, int16_t *y);
+ // Functions for changing display brightness
+ void setDisplayBrightness(uint8_t);
+
/**
* shim to make the abstraction happy
*
diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp
index 74a6c718d..af7c96b20 100644
--- a/src/input/kbI2cBase.cpp
+++ b/src/input/kbI2cBase.cpp
@@ -1,5 +1,4 @@
#include "kbI2cBase.h"
-
#include "configuration.h"
#include "detect/ScanI2C.h"
@@ -138,6 +137,9 @@ int32_t KbI2cBase::runOnce()
break;
case 0x13: // Code scanner says the SYM key is 0x13
is_sym = !is_sym;
+ e.inputEvent = ANYKEY;
+ e.kbchar =
+ is_sym ? 0xf1 : 0xf2; // send 0xf1 to tell CannedMessages to display that the modifier key is active
break;
case 0x0a: // apparently Enter on Q10 is a line feed instead of carriage return
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
@@ -193,6 +195,75 @@ int32_t KbI2cBase::runOnce()
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName;
switch (c) {
+ case 0x71: // This is the button q. If modifier and q pressed, it cancels the input
+ if (is_sym) {
+ is_sym = false;
+ e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
+ } else {
+ e.inputEvent = ANYKEY;
+ e.kbchar = c;
+ }
+ break;
+ case 0x74: // letter t. if modifier and t pressed call 'tab'
+ if (is_sym) {
+ is_sym = false;
+ e.inputEvent = ANYKEY;
+ e.kbchar = 0x09; // TAB Scancode
+ } else {
+ e.inputEvent = ANYKEY;
+ e.kbchar = c;
+ }
+ break;
+ case 0x6d: // letter m. Modifier makes it mute notifications
+ if (is_sym) {
+ is_sym = false;
+ e.inputEvent = ANYKEY;
+ e.kbchar = 0xac; // mute notifications
+ } else {
+ e.inputEvent = ANYKEY;
+ e.kbchar = c;
+ }
+ break;
+ case 0x6f: // letter o(+). Modifier makes screen increase in brightness
+ if (is_sym) {
+ is_sym = false;
+ e.inputEvent = ANYKEY;
+ e.kbchar = 0x11; // Increase Brightness code
+ } else {
+ e.inputEvent = ANYKEY;
+ e.kbchar = c;
+ }
+ break;
+ case 0x69: // letter i(-). Modifier makes screen decrease in brightness
+ if (is_sym) {
+ is_sym = false;
+ e.inputEvent = ANYKEY;
+ e.kbchar = 0x12; // Decrease Brightness code
+ } else {
+ e.inputEvent = ANYKEY;
+ e.kbchar = c;
+ }
+ break;
+ case 0x20: // Space. Send network ping like double press does
+ if (is_sym) {
+ is_sym = false;
+ e.inputEvent = ANYKEY;
+ e.kbchar = 0xaf; // (fn + space)
+ } else {
+ e.inputEvent = ANYKEY;
+ e.kbchar = c;
+ }
+ break;
+ case 0x67: // letter g. toggle gps
+ if (is_sym) {
+ is_sym = false;
+ e.inputEvent = ANYKEY;
+ e.kbchar = 0x9e;
+ } else {
+ e.inputEvent = ANYKEY;
+ e.kbchar = c;
+ }
+ break;
case 0x1b: // ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
break;
@@ -216,6 +287,12 @@ int32_t KbI2cBase::runOnce()
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = 0xb7;
break;
+ case 0xc: // Modifier key: 0xc is alt+c (Other options could be: 0xea = shift+mic button or 0x4 shift+$(speaker))
+ // toggle moddifiers button.
+ is_sym = !is_sym;
+ e.inputEvent = ANYKEY;
+ e.kbchar = is_sym ? 0xf1 : 0xf2; // send 0xf1 to tell CannedMessages to display that the modifier key is active
+ break;
case 0x90: // fn+r
case 0x91: // fn+t
case 0x9b: // fn+s
@@ -239,6 +316,7 @@ int32_t KbI2cBase::runOnce()
}
e.inputEvent = ANYKEY;
e.kbchar = c;
+ is_sym = false;
break;
}
diff --git a/src/main.cpp b/src/main.cpp
index 3b3cb6185..9681d80a4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -559,6 +559,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X)
i2cScanner.reset();
@@ -833,7 +834,8 @@ void setup()
if (settingsMap[use_sx1262]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1262 radio on SPI port %s\n", settingsStrings[spidev].c_str());
- LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
+ LockingArduinoHal *RadioLibHAL =
+ new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -847,7 +849,8 @@ void setup()
} else if (settingsMap[use_rf95]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate rf95 radio on SPI port %s\n", settingsStrings[spidev].c_str());
- LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
+ LockingArduinoHal *RadioLibHAL =
+ new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -1154,4 +1157,4 @@ void tft_task_handler(void *param = nullptr)
#endif
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp
index fc1563ee3..a4ceac9f1 100644
--- a/src/mesh/RadioLibInterface.cpp
+++ b/src/mesh/RadioLibInterface.cpp
@@ -25,7 +25,31 @@ void LockingArduinoHal::spiEndTransaction()
#if ARCH_PORTDUINO
void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in)
{
- spi->transfer(out, in, len);
+ if (busy == RADIOLIB_NC) {
+ spi->transfer(out, in, len);
+ } else {
+ uint16_t offset = 0;
+
+ while (len) {
+ uint8_t block_size = (len < 20 ? len : 20);
+ spi->transfer((out != NULL ? out + offset : NULL), (in != NULL ? in + offset : NULL), block_size);
+ if (block_size == len)
+ return;
+
+ // ensure GPIO is low
+
+ uint32_t start = millis();
+ while (digitalRead(busy)) {
+ if (millis() - start >= 2000) {
+ LOG_ERROR("GPIO mid-transfer timeout, is it connected?");
+ return;
+ }
+ }
+
+ offset += block_size;
+ len -= block_size;
+ }
+ }
}
#endif
@@ -414,4 +438,4 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
// bits
enableInterrupt(isrTxLevel0);
}
-}
+}
\ No newline at end of file
diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h
index 62720cfc9..2c841a19e 100644
--- a/src/mesh/RadioLibInterface.h
+++ b/src/mesh/RadioLibInterface.h
@@ -21,12 +21,20 @@
class LockingArduinoHal : public ArduinoHal
{
public:
- LockingArduinoHal(SPIClass &spi, SPISettings spiSettings) : ArduinoHal(spi, spiSettings){};
+ LockingArduinoHal(SPIClass &spi, SPISettings spiSettings, RADIOLIB_PIN_TYPE _busy = RADIOLIB_NC)
+ : ArduinoHal(spi, spiSettings)
+ {
+#if ARCH_PORTDUINO
+ busy = _busy;
+#endif
+ };
void spiBeginTransaction() override;
void spiEndTransaction() override;
#if ARCH_PORTDUINO
+ RADIOLIB_PIN_TYPE busy;
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) override;
+
#endif
};
@@ -179,4 +187,4 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0;
virtual void setStandby() = 0;
-};
+};
\ No newline at end of file
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index 4a181ceb5..f2076eeb2 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -180,11 +180,75 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)) {
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
}
- // pass the pressed key
- // LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
- this->payload = event->kbchar;
- this->lastTouchMillis = millis();
- validEvent = true;
+
+ validEvent = false; // If key is normal than it will be set to true.
+
+ // Run modifier key code below, (doesnt inturrupt typing or reset to start screen page)
+ switch (event->kbchar) {
+ case 0x11: // make screen brighter
+ if (screen)
+ screen->increaseBrightness();
+ LOG_DEBUG("increasing Screen Brightness\n");
+ break;
+ case 0x12: // make screen dimmer
+ if (screen)
+ screen->decreaseBrightness();
+ LOG_DEBUG("Decreasing Screen Brightness\n");
+ break;
+ case 0xf1: // draw modifier (function) symbal
+ if (screen)
+ screen->setFunctionSymbal("Fn");
+ break;
+ case 0xf2: // remove modifier (function) symbal
+ if (screen)
+ screen->removeFunctionSymbal("Fn");
+ break;
+ // mute (switch off/toggle) external notifications on fn+m
+ case 0xac:
+ if (moduleConfig.external_notification.enabled == true) {
+ if (externalNotificationModule->getMute()) {
+ externalNotificationModule->setMute(false);
+ showTemporaryMessage("Notifications \nEnabled");
+ if (screen)
+ screen->removeFunctionSymbal("M"); // remove the mute symbol from the bottom right corner
+ } else {
+ externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
+ externalNotificationModule->setMute(true);
+ showTemporaryMessage("Notifications \nDisabled");
+ if (screen)
+ screen->setFunctionSymbal("M"); // add the mute symbol to the bottom right corner
+ }
+ }
+ break;
+ case 0x9e: // toggle GPS like triple press does
+#if !MESHTASTIC_EXCLUDE_GPS
+ if (gps != nullptr) {
+ gps->toggleGpsMode();
+ }
+ if (screen)
+ screen->forceDisplay();
+ showTemporaryMessage("GPS Toggled");
+#endif
+ break;
+ case 0xaf: // fn+space send network ping like double press does
+ service.refreshLocalMeshNode();
+ if (service.trySendPosition(NODENUM_BROADCAST, true)) {
+ showTemporaryMessage("Position \nUpdate Sent");
+ } else {
+ showTemporaryMessage("Node Info \nUpdate Sent");
+ }
+ break;
+ default:
+ // pass the pressed key
+ // LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
+ this->payload = event->kbchar;
+ this->lastTouchMillis = millis();
+ validEvent = true;
+ break;
+ }
+ if (screen && (event->kbchar != 0xf1)) {
+ screen->removeFunctionSymbal("Fn"); // remove modifier (function) symbal
+ }
}
if (event->inputEvent == static_cast(MATRIXKEY)) {
LOG_DEBUG("Canned message event Matrix key pressed\n");
@@ -390,8 +454,9 @@ int32_t CannedMessageModule::runOnce()
}
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
e.frameChanged = true;
- switch (this->payload) {
- case 0x08: // backspace
+ switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the
+ // display back to the default window
+ case 0x08: // backspace
if (this->freetext.length() > 0) {
if (this->cursor == this->freetext.length()) {
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
@@ -403,7 +468,6 @@ int32_t CannedMessageModule::runOnce()
}
break;
case 0x09: // tab
- case 0x91: // alt+t for T-Deck that doesn't have a tab key
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
@@ -416,7 +480,7 @@ int32_t CannedMessageModule::runOnce()
case 0xb7: // right
// already handled above
break;
- // handle fn+s for shutdown
+ // handle fn+s for shutdown
case 0x9b:
if (screen)
screen->startShutdownScreen();
@@ -430,37 +494,6 @@ int32_t CannedMessageModule::runOnce()
rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000;
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
break;
- case 0x9e: // toggle GPS like triple press does
-#if !MESHTASTIC_EXCLUDE_GPS
- if (gps != nullptr) {
- gps->toggleGpsMode();
- }
- if (screen)
- screen->forceDisplay();
- showTemporaryMessage("GPS Toggled");
-#endif
- break;
- // mute (switch off/toggle) external notifications on fn+m
- case 0xac:
- if (moduleConfig.external_notification.enabled == true) {
- if (externalNotificationModule->getMute()) {
- externalNotificationModule->setMute(false);
- showTemporaryMessage("Notifications \nEnabled");
- } else {
- externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
- externalNotificationModule->setMute(true);
- showTemporaryMessage("Notifications \nDisabled");
- }
- }
- break;
- case 0xaf: // fn+space send network ping like double press does
- service.refreshLocalMeshNode();
- if (service.trySendPosition(NODENUM_BROADCAST, true)) {
- showTemporaryMessage("Position \nUpdate Sent");
- } else {
- showTemporaryMessage("Node Info \nUpdate Sent");
- }
- break;
default:
if (this->cursor == this->freetext.length()) {
this->freetext += this->payload;
@@ -476,6 +509,8 @@ int32_t CannedMessageModule::runOnce()
}
break;
}
+ if (screen)
+ screen->removeFunctionSymbal("Fn");
}
this->lastTouchMillis = millis();
@@ -789,4 +824,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result;
}
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index e6a0e1194..d0aa16057 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -45,7 +45,7 @@
#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
-#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY
+#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY
#include "modules/Telemetry/PowerTelemetry.h"
#endif
#ifdef ARCH_ESP32
@@ -137,7 +137,7 @@ void setupModules()
#if (HAS_SCREEN || HAS_TFT) && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
cannedMessageModule = new CannedMessageModule();
#endif
-#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+#if HAS_TELEMETRY
new DeviceTelemetryModule();
#endif
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
@@ -146,7 +146,7 @@ void setupModules()
new AirQualityTelemetryModule();
}
#endif
-#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
new PowerTelemetryModule();
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 93184069d..62adc9a8c 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -26,6 +26,7 @@
#include "Sensor/MCP9808Sensor.h"
#include "Sensor/RCWL9620Sensor.h"
#include "Sensor/SHT31Sensor.h"
+#include "Sensor/SHT4XSensor.h"
#include "Sensor/SHTC3Sensor.h"
BMP085Sensor bmp085Sensor;
@@ -36,6 +37,7 @@ MCP9808Sensor mcp9808Sensor;
SHTC3Sensor shtc3Sensor;
LPS22HBSensor lps22hbSensor;
SHT31Sensor sht31Sensor;
+SHT4XSensor sht4xSensor;
RCWL9620Sensor rcwl9620Sensor;
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
@@ -91,6 +93,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = lps22hbSensor.runOnce();
if (sht31Sensor.hasSensor())
result = sht31Sensor.runOnce();
+ if (sht4xSensor.hasSensor())
+ result = sht4xSensor.runOnce();
if (ina219Sensor.hasSensor())
result = ina219Sensor.runOnce();
if (ina260Sensor.hasSensor())
@@ -246,6 +250,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
if (sht31Sensor.hasSensor())
valid = sht31Sensor.getMetrics(&m);
+ if (sht4xSensor.hasSensor())
+ valid = sht4xSensor.getMetrics(&m);
if (lps22hbSensor.hasSensor())
valid = lps22hbSensor.getMetrics(&m);
if (shtc3Sensor.hasSensor())
diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.cpp b/src/modules/Telemetry/Sensor/SHT4XSensor.cpp
new file mode 100644
index 000000000..d324b7fd6
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/SHT4XSensor.cpp
@@ -0,0 +1,63 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "SHT4XSensor.h"
+#include "TelemetrySensor.h"
+#include
+
+// macro definitions
+// make sure that we use the proper definition of NO_ERROR
+#ifdef NO_ERROR
+#undef NO_ERROR
+#endif
+#define NO_ERROR 0
+
+static char errorMessage[64];
+static int16_t error;
+
+SHT4XSensor::SHT4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT4X, "SHT4X") {}
+
+int32_t SHT4XSensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+
+ uint32_t serialNumber = 0;
+
+ sht4x.begin(*nodeTelemetrySensorsMap[sensorType].second, 0x44);
+
+ error = sht4x.serialNumber(serialNumber);
+ LOG_DEBUG("serialNumber : %x\n", serialNumber);
+ if (error != NO_ERROR) {
+ LOG_DEBUG("Error trying to execute serialNumber(): ");
+ errorToString(error, errorMessage, sizeof errorMessage);
+ LOG_DEBUG(errorMessage);
+ status = 0;
+ } else {
+ status = 1;
+ }
+
+ return initI2CSensor();
+}
+
+void SHT4XSensor::setup()
+{
+ // Set up oversampling and filter initialization
+}
+
+bool SHT4XSensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ float aTemperature = 0.0;
+ float aHumidity = 0.0;
+ sht4x.measureLowestPrecision(aTemperature, aHumidity);
+ measurement->variant.environment_metrics.temperature = aTemperature;
+ measurement->variant.environment_metrics.relative_humidity = aHumidity;
+
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.h b/src/modules/Telemetry/Sensor/SHT4XSensor.h
new file mode 100644
index 000000000..67045eb2a
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/SHT4XSensor.h
@@ -0,0 +1,23 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class SHT4XSensor : public TelemetrySensor
+{
+ private:
+ SensirionI2cSht4x sht4x;
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ SHT4XSensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h
index 3be3e7e55..68bd87801 100644
--- a/src/platform/nrf52/architecture.h
+++ b/src/platform/nrf52/architecture.h
@@ -54,6 +54,8 @@
#define HW_VENDOR meshtastic_HardwareModel_NRF52840_PCA10059
#elif defined(TWC_MESH_V4)
#define HW_VENDOR meshtastic_HardwareModel_TWC_MESH_V4
+#elif defined(NRF52_PROMICRO_DIY)
+#define HW_VENDOR meshtastic_HardwareModel_NRF52_PROMICRO_DIY
#elif defined(PRIVATE_HW) || defined(FEATHER_DIY)
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
#else
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index 7c5086ac2..4077a27bc 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -168,6 +168,7 @@ void portduinoSetup()
settingsMap[txen] = yamlConfig["Lora"]["TXen"].as(RADIOLIB_NC);
settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as(RADIOLIB_NC);
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as(0);
+ settingsMap[ch341Quirk] = yamlConfig["Lora"]["ch341_quirk"].as(false);
gpioChipName += std::to_string(settingsMap[gpiochip]);
settingsStrings[spidev] = "/dev/" + yamlConfig["Lora"]["spidev"].as("spidev0.0");
diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h
index 995793a21..ca935ea3b 100644
--- a/src/platform/portduino/PortduinoGlue.h
+++ b/src/platform/portduino/PortduinoGlue.h
@@ -11,6 +11,7 @@ enum configNames {
rxen,
dio2_as_rf_switch,
dio3_tcxo_voltage,
+ ch341Quirk,
use_rf95,
use_sx1280,
use_sx1268,
diff --git a/variants/diy/nrf52_promicro_diy_tcxo/variant.cpp b/variants/diy/nrf52_promicro_diy_tcxo/variant.cpp
new file mode 100644
index 000000000..4030122e5
--- /dev/null
+++ b/variants/diy/nrf52_promicro_diy_tcxo/variant.cpp
@@ -0,0 +1,31 @@
+/*
+ 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};
\ No newline at end of file
diff --git a/variants/diy/nrf52_promicro_diy_tcxo/variant.h b/variants/diy/nrf52_promicro_diy_tcxo/variant.h
new file mode 100644
index 000000000..8b957fe12
--- /dev/null
+++ b/variants/diy/nrf52_promicro_diy_tcxo/variant.h
@@ -0,0 +1,154 @@
+#ifndef _VARIANT_PROMICRO_DIY_
+#define _VARIANT_PROMICRO_DIY_
+
+/** Master clock frequency */
+#define VARIANT_MCK (64000000ul)
+
+// #define USE_LFXO // Board uses 32khz crystal for LF
+#define USE_LFRC // Board uses RC for LF
+
+#define PROMICRO_DIY_TCXO
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/*
+NRF52 PRO MICRO PIN ASSIGNMENT
+
+| Pin | Function | | Pin | Function |
+|-------|------------|---|---------|-------------|
+| Gnd | | | vbat | |
+| P0.06 | Serial2 RX | | vbat | |
+| P0.08 | Serial2 TX | | Gnd | |
+| Gnd | | | reset | |
+| Gnd | | | ext_vcc | *see 0.13 |
+| P0.17 | RXEN | | P0.31 | BATTERY_PIN |
+| P0.20 | GPS_RX | | P0.29 | BUSY |
+| P0.22 | GPS_TX | | P0.02 | MISO |
+| P0.24 | GPS_EN | | P1.15 | MOSI |
+| P1.00 | BUTTON_PIN | | P1.13 | CS |
+| P0.11 | SCL | | P1.11 | SCK |
+| P1.04 | SDA | | P0.10 | DIO1/IRQ |
+| P1.06 | Free pin | | P0.09 | RESET |
+| | | | | |
+| | Mid board | | | Internal |
+| P1.01 | Free pin | | 0.15 | LED |
+| P1.02 | Free pin | | 0.13 | 3V3_EN |
+| P1.07 | Free pin | | | |
+*/
+
+// Number of pins defined in PinDescription array
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (1)
+#define NUM_ANALOG_OUTPUTS (0)
+
+// Pin 13 enables 3.3V periphery. If the Lora module is on this pin, then it should stay enabled at all times.
+#define PIN_3V3_EN (0 + 13) // P0.13
+
+// Analog pins
+#define BATTERY_PIN (0 + 31) // P0.31 Battery ADC
+#define ADC_CHANNEL ADC1_GPIO4_CHANNEL
+#define ADC_RESOLUTION 14
+#define BATTERY_SENSE_RESOLUTION_BITS 12
+#define BATTERY_SENSE_RESOLUTION 4096.0
+// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
+#define VBAT_MV_PER_LSB (0.73242188F)
+// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
+#define VBAT_DIVIDER (0.6F)
+// Compensation factor for the VBAT divider
+#define VBAT_DIVIDER_COMP (1.73)
+// Fixed calculation of milliVolt from compensation value
+#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
+#undef AREF_VOLTAGE
+#define AREF_VOLTAGE 3.0
+#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
+#define ADC_MULTIPLIER VBAT_DIVIDER_COMP // REAL_VBAT_MV_PER_LSB
+#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
+
+// WIRE IC AND IIC PINS
+#define WIRE_INTERFACES_COUNT 1
+
+#define PIN_WIRE_SDA (32 + 4) // P1.04
+#define PIN_WIRE_SCL (0 + 11) // P0.11
+
+// LED
+#define PIN_LED1 (0 + 15) // P0.15
+#define LED_BUILTIN PIN_LED1
+// Actually red
+#define LED_BLUE PIN_LED1
+#define LED_STATE_ON 1 // State when LED is lit
+
+// Button
+#define BUTTON_PIN (32 + 0) // P1.00
+
+// GPS
+#define PIN_GPS_TX (0 + 22) // P0.22
+#define PIN_GPS_RX (0 + 20) // P0.20
+
+#define PIN_GPS_EN (0 + 24) // P0.24
+#define GPS_POWER_TOGGLE
+#define GPS_UBLOX
+// define GPS_DEBUG
+
+// UART interfaces
+#define PIN_SERIAL1_RX PIN_GPS_TX
+#define PIN_SERIAL1_TX PIN_GPS_RX
+
+#define PIN_SERIAL2_RX (0 + 6) // P0.06
+#define PIN_SERIAL2_TX (0 + 8) // P0.08
+
+// Serial interfaces
+#define SPI_INTERFACES_COUNT 1
+
+#define PIN_SPI_MISO (0 + 2) // P0.02
+#define PIN_SPI_MOSI (32 + 15) // P1.15
+#define PIN_SPI_SCK (32 + 11) // P1.11
+
+// LORA MODULES
+#define USE_LLCC68
+#define USE_SX1262
+
+// LORA CONFIG
+#define SX126X_CS (32 + 13) // P1.13 FIXME - we really should define LORA_CS instead
+#define SX126X_DIO1 (0 + 10) // P0.10 IRQ
+#define SX126X_DIO2_AS_RF_SWITCH // Note for E22 modules: DIO2 is not attached internally to TXEN for automatic TX/RX switching,
+ // so it needs connecting externally if it is used in this way
+#define SX126X_BUSY (0 + 29) // P0.29
+#define SX126X_RESET (0 + 9) // P0.09
+#define SX126X_RXEN (0 + 17) // P0.17
+#define SX126X_TXEN RADIOLIB_NC // Assuming that DIO2 is connected to TXEN pin. If not, TXEN must be connected.
+
+/*
+On the SX1262, DIO3 sets the voltage for an external TCXO, if one is present. If one is not present, then this should not be used.
+
+Ebyte
+e22-900mm22s has no TCXO
+e22-900m22s has TCXO
+e220-900mm22s has no TCXO, works with/without this definition, looks like DIO3 not connected at all
+
+AI-thinker
+RA-01SH does not have TCXO
+
+Waveshare
+Core1262 has TCXO
+
+*/
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+
+#ifdef __cplusplus
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * Arduino objects - C++ only
+ *----------------------------------------------------------------------------*/
+
+#endif
\ No newline at end of file
diff --git a/variants/diy/nrf52_promicro_diy_xtal/variant.cpp b/variants/diy/nrf52_promicro_diy_xtal/variant.cpp
new file mode 100644
index 000000000..4030122e5
--- /dev/null
+++ b/variants/diy/nrf52_promicro_diy_xtal/variant.cpp
@@ -0,0 +1,31 @@
+/*
+ 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};
\ No newline at end of file
diff --git a/variants/diy/nrf52_promicro_diy_xtal/variant.h b/variants/diy/nrf52_promicro_diy_xtal/variant.h
new file mode 100644
index 000000000..fd0b21681
--- /dev/null
+++ b/variants/diy/nrf52_promicro_diy_xtal/variant.h
@@ -0,0 +1,153 @@
+#ifndef _VARIANT_PROMICRO_DIY_
+#define _VARIANT_PROMICRO_DIY_
+
+/** Master clock frequency */
+#define VARIANT_MCK (64000000ul)
+
+// #define USE_LFXO // Board uses 32khz crystal for LF
+#define USE_LFRC // Board uses RC for LF
+
+#define PROMICRO_DIY_XTAL
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/*
+NRF52 PRO MICRO PIN ASSIGNMENT
+
+| Pin | Function | | Pin | Function |
+|-------|------------|---|---------|-------------|
+| Gnd | | | vbat | |
+| P0.06 | Serial2 RX | | vbat | |
+| P0.08 | Serial2 TX | | Gnd | |
+| Gnd | | | reset | |
+| Gnd | | | ext_vcc | *see 0.13 |
+| P0.17 | RXEN | | P0.31 | BATTERY_PIN |
+| P0.20 | GPS_RX | | P0.29 | BUSY |
+| P0.22 | GPS_TX | | P0.02 | MISO |
+| P0.24 | GPS_EN | | P1.15 | MOSI |
+| P1.00 | BUTTON_PIN | | P1.13 | CS |
+| P0.11 | SCL | | P1.11 | SCK |
+| P1.04 | SDA | | P0.10 | DIO1/IRQ |
+| P1.06 | Free pin | | P0.09 | RESET |
+| | | | | |
+| | Mid board | | | Internal |
+| P1.01 | Free pin | | 0.15 | LED |
+| P1.02 | Free pin | | 0.13 | 3V3_EN |
+| P1.07 | Free pin | | | |
+*/
+
+// Number of pins defined in PinDescription array
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (1)
+#define NUM_ANALOG_OUTPUTS (0)
+
+// Pin 13 enables 3.3V periphery. If the Lora module is on this pin, then it should stay enabled at all times.
+#define PIN_3V3_EN (0 + 13) // P0.13
+
+// Analog pins
+#define BATTERY_PIN (0 + 31) // P0.31 Battery ADC
+#define ADC_CHANNEL ADC1_GPIO4_CHANNEL
+#define ADC_RESOLUTION 14
+#define BATTERY_SENSE_RESOLUTION_BITS 12
+#define BATTERY_SENSE_RESOLUTION 4096.0
+// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
+#define VBAT_MV_PER_LSB (0.73242188F)
+// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
+#define VBAT_DIVIDER (0.6F)
+// Compensation factor for the VBAT divider
+#define VBAT_DIVIDER_COMP (1.73)
+// Fixed calculation of milliVolt from compensation value
+#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
+#undef AREF_VOLTAGE
+#define AREF_VOLTAGE 3.0
+#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
+#define ADC_MULTIPLIER VBAT_DIVIDER_COMP // REAL_VBAT_MV_PER_LSB
+#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
+
+// WIRE IC AND IIC PINS
+#define WIRE_INTERFACES_COUNT 1
+
+#define PIN_WIRE_SDA (32 + 4) // P1.04
+#define PIN_WIRE_SCL (0 + 11) // P0.11
+
+// LED
+#define PIN_LED1 (0 + 15) // P0.15
+#define LED_BUILTIN PIN_LED1
+// Actually red
+#define LED_BLUE PIN_LED1
+#define LED_STATE_ON 1 // State when LED is lit
+
+// Button
+#define BUTTON_PIN (32 + 0) // P1.00
+
+// GPS
+#define PIN_GPS_TX (0 + 22) // P0.22
+#define PIN_GPS_RX (0 + 20) // P0.20
+
+#define PIN_GPS_EN (0 + 24) // P0.24
+#define GPS_POWER_TOGGLE
+#define GPS_UBLOX
+// define GPS_DEBUG
+
+// UART interfaces
+#define PIN_SERIAL1_RX PIN_GPS_TX
+#define PIN_SERIAL1_TX PIN_GPS_RX
+
+#define PIN_SERIAL2_RX (0 + 6) // P0.06
+#define PIN_SERIAL2_TX (0 + 8) // P0.08
+
+// Serial interfaces
+#define SPI_INTERFACES_COUNT 1
+
+#define PIN_SPI_MISO (0 + 2) // P0.02
+#define PIN_SPI_MOSI (32 + 15) // P1.15
+#define PIN_SPI_SCK (32 + 11) // P1.11
+
+// LORA MODULES
+#define USE_LLCC68
+#define USE_SX1262
+
+// LORA CONFIG
+#define SX126X_CS (32 + 13) // P1.13 FIXME - we really should define LORA_CS instead
+#define SX126X_DIO1 (0 + 10) // P0.10 IRQ
+#define SX126X_DIO2_AS_RF_SWITCH // Note for E22 modules: DIO2 is not attached internally to TXEN for automatic TX/RX switching,
+ // so it needs connecting externally if it is used in this way
+#define SX126X_BUSY (0 + 29) // P0.29
+#define SX126X_RESET (0 + 9) // P0.09
+#define SX126X_RXEN (0 + 17) // P0.17
+#define SX126X_TXEN RADIOLIB_NC // Assuming that DIO2 is connected to TXEN pin. If not, TXEN must be connected.
+
+/*
+On the SX1262, DIO3 sets the voltage for an external TCXO, if one is present. If one is not present, then this should not be used.
+
+Ebyte
+e22-900mm22s has no TCXO
+e22-900m22s has TCXO
+e220-900mm22s has no TCXO, works with/without this definition, looks like DIO3 not connected at all
+
+AI-thinker
+RA-01SH does not have TCXO
+
+Waveshare
+Core1262 has TCXO
+
+*/
+// #define SX126X_DIO3_TCXO_VOLTAGE 1.8
+
+#ifdef __cplusplus
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * Arduino objects - C++ only
+ *----------------------------------------------------------------------------*/
+
+#endif
\ No newline at end of file
diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini
index e7d72d13f..5fb0f6421 100644
--- a/variants/diy/platformio.ini
+++ b/variants/diy/platformio.ini
@@ -44,3 +44,35 @@ build_flags =
${esp32_base.build_flags}
-D DIY_V1
-I variants/diy/hydra
+
+
+; Promicro + E22(0)-xxxMM / RA-01SH modules board variant - DIY - without TCXO
+[env:nrf52_promicro_diy_xtal]
+extends = nrf52840_base
+board = promicro-nrf52840
+board_level = extra
+build_flags = ${nrf52840_base.build_flags}
+ -I variants/diy/nrf52_promicro_diy_xtal
+ -D NRF52_PROMICRO_DIY
+ -D OLED_RU
+ -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+build_src_filter = ${nrf52_base.build_src_filter} +<../variants/diy/nrf52_promicro_diy_xtal>
+lib_deps =
+ ${nrf52840_base.lib_deps}
+debug_tool = jlink
+
+
+; Promicro + E22(0)-xxxM / HT-RA62 modules board variant - DIY - with TCXO
+[env:nrf52_promicro_diy_tcxo]
+extends = nrf52840_base
+board = promicro-nrf52840
+board_level = extra
+build_flags = ${nrf52840_base.build_flags}
+ -I variants/diy/nrf52_promicro_diy_tcxo
+ -D NRF52_PROMICRO_DIY
+ -D OLED_RU
+ -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+build_src_filter = ${nrf52_base.build_src_filter} +<../variants/diy/nrf52_promicro_diy_tcxo>
+lib_deps =
+ ${nrf52840_base.lib_deps}
+debug_tool = jlink
\ No newline at end of file
diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h
index 4a0a13a13..ddd1fb402 100644
--- a/variants/t-deck/variant.h
+++ b/variants/t-deck/variant.h
@@ -18,6 +18,7 @@
#define TFT_OFFSET_ROTATION 0
#define SCREEN_ROTATE
#define SCREEN_TRANSITION_FRAMERATE 5
+#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
#define HAS_TOUCHSCREEN 1
#define SCREEN_TOUCH_INT 16
@@ -96,4 +97,4 @@
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
-// code)
+// code)
\ No newline at end of file
diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini
index 9ff60be3f..c036a39a2 100644
--- a/variants/t-echo/platformio.ini
+++ b/variants/t-echo/platformio.ini
@@ -15,7 +15,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
-DEINK_LIMIT_FASTREFRESH=20 ; How many consecutive fast-refreshes are permitted
-DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates
-DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates
- -DEINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated
+; -DEINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated
-DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached.
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo>
lib_deps =
diff --git a/variants/t-echo/variant.h b/variants/t-echo/variant.h
index 2abeed16d..1c263a61a 100644
--- a/variants/t-echo/variant.h
+++ b/variants/t-echo/variant.h
@@ -65,6 +65,9 @@ extern "C" {
#define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular GPIO
#define PIN_BUTTON_TOUCH (0 + 11) // 0.11 is the soft touch button on T-Echo
+#define BUTTON_CLICK_MS 400
+#define BUTTON_TOUCH_MS 200
+
/*
* Analog pins
*/
diff --git a/version.properties b/version.properties
index a7a7fb1bd..69761c0ac 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 3
-build = 9
+build = 10