mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-31 23:21:06 +00:00
Compare commits
82 Commits
v2.2.14.57
...
v2.2.16.1c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c6acfd734 | ||
|
|
c6ae66dcaa | ||
|
|
fc365a1fee | ||
|
|
6c1db94ae7 | ||
|
|
ded1cbf4dd | ||
|
|
399b9f8f6d | ||
|
|
4720b2874f | ||
|
|
1af3e0ddaa | ||
|
|
9f85279e74 | ||
|
|
dd96848bec | ||
|
|
4932e277f1 | ||
|
|
dad05d7873 | ||
|
|
4b7fbeca29 | ||
|
|
2ebaea317a | ||
|
|
d14d2c89c3 | ||
|
|
35938392f1 | ||
|
|
d952da8b1e | ||
|
|
385b29c977 | ||
|
|
dc309f61e8 | ||
|
|
512399c8f5 | ||
|
|
5d94bb601a | ||
|
|
796592b586 | ||
|
|
d552ee3556 | ||
|
|
14b31d4d14 | ||
|
|
4de6eb2e1d | ||
|
|
abaa37133d | ||
|
|
5eac227550 | ||
|
|
671112f47d | ||
|
|
8ea19d665a | ||
|
|
8f57cfaaf4 | ||
|
|
a54e3826e9 | ||
|
|
9188a9a1f2 | ||
|
|
17f1a450b2 | ||
|
|
ba021c97b2 | ||
|
|
b4ad6b0f41 | ||
|
|
28502a762f | ||
|
|
89f0464233 | ||
|
|
46d02affe8 | ||
|
|
62329ad11f | ||
|
|
72b4fe51b1 | ||
|
|
07fc5df9c1 | ||
|
|
1c22d2c885 | ||
|
|
1f931a5e55 | ||
|
|
31c4693c66 | ||
|
|
6ff61b3e04 | ||
|
|
9e90b4af02 | ||
|
|
2544733ad4 | ||
|
|
1b6c11c5f1 | ||
|
|
4c69d06ac0 | ||
|
|
85cbde75fe | ||
|
|
5e70fb9851 | ||
|
|
6e967421a5 | ||
|
|
a05bab35ad | ||
|
|
ac506a581c | ||
|
|
def4ec5822 | ||
|
|
209fb585b0 | ||
|
|
fb89482129 | ||
|
|
8e742f2f80 | ||
|
|
238cf8cdeb | ||
|
|
5df7f07f95 | ||
|
|
6fa026a78b | ||
|
|
39743832ad | ||
|
|
bd2675caf1 | ||
|
|
c489c251ab | ||
|
|
14d03a2bda | ||
|
|
423b8ad603 | ||
|
|
ce8342d3e5 | ||
|
|
57227c0f85 | ||
|
|
1ca2923658 | ||
|
|
d10b1e1d00 | ||
|
|
d3e64350d9 | ||
|
|
102efd4954 | ||
|
|
18cf8ca4fa | ||
|
|
c7f6071f70 | ||
|
|
c7e3485dd7 | ||
|
|
603e564db3 | ||
|
|
ac318a9850 | ||
|
|
1feb74f525 | ||
|
|
d6fc1c314f | ||
|
|
b3852322ef | ||
|
|
cbb8eb65ba | ||
|
|
4712b1ca65 |
9
.github/workflows/main_matrix.yml
vendored
9
.github/workflows/main_matrix.yml
vendored
@@ -66,6 +66,7 @@ jobs:
|
||||
- board: tlora-v2-1-1_6
|
||||
- board: tlora-v2-1-1_8
|
||||
- board: tbeam
|
||||
- board: heltec-ht62-esp32c3-sx1262
|
||||
- board: heltec-v1
|
||||
- board: heltec-v2_0
|
||||
- board: heltec-v2_1
|
||||
@@ -123,7 +124,9 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- board: pico
|
||||
- board: picow
|
||||
- board: rak11310
|
||||
- board: senselora_rp2040
|
||||
uses: ./.github/workflows/build_rpi2040.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
@@ -210,6 +213,9 @@ jobs:
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
gather-artifacts:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
[
|
||||
@@ -283,14 +289,13 @@ jobs:
|
||||
- name: Create request artifacts
|
||||
continue-on-error: true # FIXME: Why are we getting 502, but things still work?
|
||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||
uses: gavv/pull-request-artifacts@v1.1.0
|
||||
uses: gavv/pull-request-artifacts@v2.1.0
|
||||
with:
|
||||
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
artifacts-token: ${{ secrets.ARTIFACTS_TOKEN }}
|
||||
artifacts-repo: meshtastic/artifacts
|
||||
artifacts-branch: device
|
||||
artifacts-dir: pr
|
||||
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
|
||||
|
||||
release-artifacts:
|
||||
|
||||
4
.github/workflows/package_raspbian.yml
vendored
4
.github/workflows/package_raspbian.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: Package Raspbian
|
||||
|
||||
on: workflow_call
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
version: 0.1
|
||||
cli:
|
||||
version: 1.17.1
|
||||
version: 1.17.2
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v1.2.6
|
||||
ref: v1.3.0
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- bandit@1.7.5
|
||||
- checkov@3.0.16
|
||||
- terrascan@1.18.3
|
||||
- trivy@0.46.1
|
||||
- trufflehog@3.62.1
|
||||
- checkov@3.1.9
|
||||
- terrascan@1.18.5
|
||||
- trivy@0.47.0
|
||||
#- trufflehog@3.63.2-rc0
|
||||
- taplo@0.8.1
|
||||
- ruff@0.1.3
|
||||
- yamllint@1.32.0
|
||||
- ruff@0.1.6
|
||||
- isort@5.12.0
|
||||
- markdownlint@0.37.0
|
||||
- oxipng@9.0.0
|
||||
- svgo@3.0.2
|
||||
- svgo@3.0.5
|
||||
- actionlint@1.6.26
|
||||
- flake8@6.1.0
|
||||
- hadolint@2.12.0
|
||||
@@ -27,9 +26,9 @@ lint:
|
||||
- shellcheck@0.9.0
|
||||
- black@23.9.1
|
||||
- git-diff-check
|
||||
- gitleaks@8.18.0
|
||||
- gitleaks@8.18.1
|
||||
- clang-format@16.0.3
|
||||
- prettier@3.0.3
|
||||
- prettier@3.1.0
|
||||
runtimes:
|
||||
enabled:
|
||||
- python@3.10.8
|
||||
|
||||
@@ -39,7 +39,6 @@ lib_deps =
|
||||
${environmental_base.lib_deps}
|
||||
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
|
||||
h2zero/NimBLE-Arduino@^1.4.1
|
||||
jgromes/RadioLib@^6.1.0
|
||||
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
|
||||
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
|
||||
|
||||
@@ -57,4 +56,4 @@ lib_ignore =
|
||||
|
||||
; customize the partition table
|
||||
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
|
||||
board_build.partitions = partition-table.csv
|
||||
board_build.partitions = partition-table.csv
|
||||
@@ -11,11 +11,10 @@ build_flags =
|
||||
-Isrc/platform/nrf52
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/>
|
||||
|
||||
lib_deps=
|
||||
${arduino_base.lib_deps}
|
||||
jgromes/RadioLib@^6.1.0
|
||||
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
@@ -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#489ff929dca0bb768256ba2de45f95815111490f
|
||||
platform = https://github.com/meshtastic/platform-native.git#8a66ef82cf38a4135d85cbb5043d0e8ebbb8ba17
|
||||
framework = arduino
|
||||
|
||||
build_src_filter =
|
||||
@@ -10,6 +10,7 @@ build_src_filter =
|
||||
-<platform/nrf52/>
|
||||
-<platform/stm32wl/>
|
||||
-<platform/rp2040>
|
||||
-<mesh/wifi/>
|
||||
-<mesh/http/>
|
||||
-<mesh/eth/>
|
||||
-<modules/esp32>
|
||||
@@ -22,9 +23,9 @@ lib_deps =
|
||||
${env.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
rweather/Crypto@^0.4.0
|
||||
jgromes/RadioLib@6.1.0
|
||||
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-fPIC
|
||||
-Isrc/platform/portduino
|
||||
-Isrc/platform/portduino
|
||||
-DRADIOLIB_EEPROM_UNSUPPORTED
|
||||
@@ -1,8 +1,8 @@
|
||||
; Common settings for rp2040 Processor based targets
|
||||
[rp2040_base]
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#0c33219f53faa035e188925ea1324f472e8b93d2
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#612de5399d68b359053f1307ed223d400aea975c
|
||||
extends = arduino_base
|
||||
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.2.2
|
||||
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.2
|
||||
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
@@ -12,7 +12,7 @@ build_flags =
|
||||
-D__PLAT_RP2040__
|
||||
# -D _POSIX_THREADS
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/>
|
||||
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
@@ -20,5 +20,4 @@ lib_ignore =
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
jgromes/RadioLib@^6.1.0
|
||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||
rweather/Crypto
|
||||
@@ -13,17 +13,16 @@ build_flags =
|
||||
-DVECT_TAB_OFFSET=0x08000000
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
|
||||
board_upload.offset_address = 0x08000000
|
||||
upload_protocol = stlink
|
||||
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
jgromes/RadioLib@^6.1.0
|
||||
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
|
||||
https://github.com/littlefs-project/littlefs.git#v2.5.1
|
||||
https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1
|
||||
|
||||
lib_ignore =
|
||||
https://github.com/mathertel/OneButton#2.1.0
|
||||
mathertel/OneButton
|
||||
@@ -1,5 +1,5 @@
|
||||
# Define your devices here using Broadcom pin numbering
|
||||
# Uncomment the block that corresponds to your hardware
|
||||
### Define your devices here using Broadcom pin numbering
|
||||
### Uncomment the block that corresponds to your hardware
|
||||
---
|
||||
Lora:
|
||||
# Module: sx1262 # Waveshare SX126X XXXM
|
||||
@@ -19,3 +19,46 @@ Lora:
|
||||
# CS: 7
|
||||
# IRQ: 22
|
||||
# Busy: 23
|
||||
|
||||
# Module: RF95 # Elecrow Lora RFM95 IOT https://www.elecrow.com/lora-rfm95-iot-board-for-rpi.html
|
||||
# Reset: 22
|
||||
# CS: 7
|
||||
# IRQ: 25
|
||||
|
||||
### Set gpio chip to use in /dev/. Defaults to 0.
|
||||
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
|
||||
# gpiochip: 4
|
||||
|
||||
### Define GPIO buttons here:
|
||||
|
||||
GPIO:
|
||||
# User: 6
|
||||
|
||||
### Define GPS
|
||||
|
||||
GPS:
|
||||
# SerialPath: /dev/ttyS0
|
||||
|
||||
### Set up SPI displays here. Note that I2C displays are generally auto-detected.
|
||||
|
||||
Display:
|
||||
|
||||
### Waveshare 2.8inch RPi LCD
|
||||
# Panel: ST7789
|
||||
# CS: 8
|
||||
# DC: 22 # Data/Command pin
|
||||
# Backlight: 18
|
||||
# Width: 240
|
||||
# Height: 320
|
||||
# Reset: 27
|
||||
# Rotate: true
|
||||
|
||||
Touchscreen:
|
||||
# Module: XPT2046
|
||||
# CS: 7
|
||||
# IRQ: 17
|
||||
|
||||
### Configure device for direct keyboard input
|
||||
|
||||
Input:
|
||||
# KeyboardDevice: /dev/input/event0
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
[unit]
|
||||
description=Meshtastic Native Daemon
|
||||
[Unit]
|
||||
Description=Meshtastic Native Daemon
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
Group=root
|
||||
Type=simple
|
||||
ExecStart=/usr/sbin/meshtasticd
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target
|
||||
@@ -68,8 +68,9 @@ build_flags = -Wno-missing-field-initializers
|
||||
monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
jgromes/RadioLib@^6.3.0
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
|
||||
https://github.com/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce
|
||||
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#076e8d2c8fb702d9be5b08c55b93ff76f8af7e61
|
||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
@@ -93,7 +94,7 @@ lib_deps =
|
||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
|
||||
|
||||
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
|
||||
build_flags = ${env.build_flags} -Os
|
||||
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
|
||||
|
||||
; Common libs for communicating over TCP/IP networks such as MQTT
|
||||
@@ -123,4 +124,4 @@ lib_deps =
|
||||
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
|
||||
adafruit/Adafruit MPU6050@^2.2.4
|
||||
adafruit/Adafruit LIS3DH@^1.2.4
|
||||
https://github.com/lewisxhe/BMA423_Library@^0.0.1
|
||||
https://github.com/lewisxhe/BMA423_Library@^0.0.1
|
||||
|
||||
Submodule protobufs updated: c845b7848e...a34b2c680e
@@ -42,7 +42,7 @@ namespace concurrency
|
||||
class AccelerometerThread : public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
AccelerometerThread(ScanI2C::DeviceType type = ScanI2C::DeviceType::NONE) : OSThread("AccelerometerThread")
|
||||
explicit AccelerometerThread(ScanI2C::DeviceType type) : OSThread("AccelerometerThread")
|
||||
{
|
||||
if (accelerometer_found.port == ScanI2C::I2CPort::NO_I2C) {
|
||||
LOG_DEBUG("AccelerometerThread disabling due to no sensors found\n");
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace concurrency
|
||||
class AmbientLightingThread : public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
|
||||
explicit AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
|
||||
{
|
||||
// Uncomment to test module
|
||||
// moduleConfig.ambient_lighting.led_state = true;
|
||||
|
||||
77
src/AudioThread.h
Normal file
77
src/AudioThread.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
#include "PowerFSM.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#ifdef HAS_I2S
|
||||
#include <AudioFileSourcePROGMEM.h>
|
||||
#include <AudioGeneratorRTTTL.h>
|
||||
#include <AudioOutputI2S.h>
|
||||
#include <ESP8266SAM.h>
|
||||
|
||||
#define AUDIO_THREAD_INTERVAL_MS 100
|
||||
|
||||
class AudioThread : public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
AudioThread() : OSThread("AudioThread") { initOutput(); }
|
||||
|
||||
void beginRttl(const void *data, uint32_t len)
|
||||
{
|
||||
setCPUFast(true);
|
||||
rtttlFile = new AudioFileSourcePROGMEM(data, len);
|
||||
i2sRtttl = new AudioGeneratorRTTTL();
|
||||
i2sRtttl->begin(rtttlFile, audioOut);
|
||||
}
|
||||
|
||||
bool isPlaying()
|
||||
{
|
||||
if (i2sRtttl != nullptr) {
|
||||
return i2sRtttl->isRunning() && i2sRtttl->loop();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (i2sRtttl != nullptr) {
|
||||
i2sRtttl->stop();
|
||||
delete i2sRtttl;
|
||||
i2sRtttl = nullptr;
|
||||
}
|
||||
if (rtttlFile != nullptr) {
|
||||
delete rtttlFile;
|
||||
rtttlFile = nullptr;
|
||||
}
|
||||
|
||||
setCPUFast(false);
|
||||
}
|
||||
|
||||
protected:
|
||||
int32_t runOnce() override
|
||||
{
|
||||
canSleep = true; // Assume we should not keep the board awake
|
||||
|
||||
// if (i2sRtttl != nullptr && i2sRtttl->isRunning()) {
|
||||
// i2sRtttl->loop();
|
||||
// }
|
||||
return AUDIO_THREAD_INTERVAL_MS;
|
||||
}
|
||||
|
||||
private:
|
||||
void initOutput()
|
||||
{
|
||||
audioOut = new AudioOutputI2S(1, AudioOutputI2S::EXTERNAL_I2S);
|
||||
audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT);
|
||||
audioOut->SetGain(0.2);
|
||||
};
|
||||
|
||||
AudioGeneratorRTTTL *i2sRtttl = nullptr;
|
||||
AudioOutputI2S *audioOut;
|
||||
|
||||
AudioFileSourcePROGMEM *rtttlFile;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "configuration.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "power.h"
|
||||
#include <OneButton.h>
|
||||
|
||||
@@ -36,6 +37,9 @@ class ButtonThread : public concurrency::OSThread
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
OneButton userButtonTouch;
|
||||
#endif
|
||||
#if defined(ARCH_RASPBERRY_PI)
|
||||
OneButton userButton;
|
||||
#endif
|
||||
static bool shutdown_on_long_stop;
|
||||
|
||||
@@ -45,8 +49,14 @@ class ButtonThread : public concurrency::OSThread
|
||||
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
|
||||
ButtonThread() : OSThread("Button")
|
||||
{
|
||||
#ifdef BUTTON_PIN
|
||||
#if defined(ARCH_RASPBERRY_PI) || defined(BUTTON_PIN)
|
||||
#if defined(ARCH_RASPBERRY_PI)
|
||||
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC)
|
||||
userButton = OneButton(settingsMap[user], true, true);
|
||||
#elif defined(BUTTON_PIN)
|
||||
|
||||
userButton = OneButton(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, true, true);
|
||||
#endif
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP_SENSE);
|
||||
@@ -58,8 +68,13 @@ class ButtonThread : public concurrency::OSThread
|
||||
userButton.attachMultiClick(userButtonMultiPressed);
|
||||
userButton.attachLongPressStart(userButtonPressedLongStart);
|
||||
userButton.attachLongPressStop(userButtonPressedLongStop);
|
||||
#if defined(ARCH_RASPBERRY_PI)
|
||||
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC)
|
||||
wakeOnIrq(settingsMap[user], FALLING);
|
||||
#else
|
||||
wakeOnIrq(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, FALLING);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
@@ -87,9 +102,14 @@ class ButtonThread : public concurrency::OSThread
|
||||
{
|
||||
canSleep = true; // Assume we should not keep the board awake
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
#if defined(BUTTON_PIN)
|
||||
userButton.tick();
|
||||
canSleep &= userButton.isIdle();
|
||||
#elif defined(ARCH_RASPBERRY_PI)
|
||||
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) {
|
||||
userButton.tick();
|
||||
canSleep &= userButton.isIdle();
|
||||
}
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
userButtonAlt.tick();
|
||||
@@ -121,6 +141,13 @@ class ButtonThread : public concurrency::OSThread
|
||||
!moduleConfig.canned_message.enabled) {
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
}
|
||||
#endif
|
||||
#if defined(ARCH_RASPBERRY_PI)
|
||||
if ((settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) &&
|
||||
(settingsMap[user] != moduleConfig.canned_message.inputbroker_pin_press) ||
|
||||
!moduleConfig.canned_message.enabled) {
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
static void userButtonPressedLong()
|
||||
@@ -179,6 +206,12 @@ class ButtonThread : public concurrency::OSThread
|
||||
|
||||
static void userButtonPressedLongStart()
|
||||
{
|
||||
#ifdef T_DECK
|
||||
// False positive long-press triggered on T-Deck with i2s audio, so short circuit
|
||||
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (millis() > 30 * 1000) {
|
||||
LOG_DEBUG("Long press start!\n");
|
||||
longPressTime = millis();
|
||||
@@ -199,4 +232,4 @@ class ButtonThread : public concurrency::OSThread
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
} // namespace concurrency
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
#include "meshUtils.h"
|
||||
#include "sleep.h"
|
||||
|
||||
// Working USB detection for powered/charging states on the RAK platform
|
||||
#ifdef NRF_APM
|
||||
#include "nrfx_power.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_HEAP_MQTT
|
||||
#include "mqtt/MQTT.h"
|
||||
#include "target_specific.h"
|
||||
@@ -397,11 +402,8 @@ bool Power::analogInit()
|
||||
*/
|
||||
bool Power::setup()
|
||||
{
|
||||
bool found = axpChipInit();
|
||||
bool found = axpChipInit() || analogInit();
|
||||
|
||||
if (!found) {
|
||||
found = analogInit();
|
||||
}
|
||||
enabled = found;
|
||||
low_voltage_counter = 0;
|
||||
|
||||
@@ -430,7 +432,7 @@ void Power::shutdown()
|
||||
ledOff(PIN_LED2);
|
||||
#endif
|
||||
#ifdef PIN_LED3
|
||||
ledOff(PIN_LED2);
|
||||
ledOff(PIN_LED3);
|
||||
#endif
|
||||
doDeepSleep(DELAY_FOREVER, false);
|
||||
#endif
|
||||
@@ -460,10 +462,25 @@ void Power::readPowerStatus()
|
||||
}
|
||||
}
|
||||
|
||||
OptionalBool NRF_USB = OptFalse;
|
||||
|
||||
#ifdef NRF_APM // Section of code detects USB power on the RAK4631 and updates the power states. Takes 20 seconds or so to detect
|
||||
// changes.
|
||||
|
||||
nrfx_power_usb_state_t nrf_usb_state = nrfx_power_usbstatus_get();
|
||||
|
||||
if (nrf_usb_state == NRFX_POWER_USB_STATE_DISCONNECTED) {
|
||||
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
|
||||
NRF_USB = OptFalse;
|
||||
} else {
|
||||
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
||||
NRF_USB = OptTrue;
|
||||
}
|
||||
#endif
|
||||
// Notify any status instances that are observing us
|
||||
const PowerStatus powerStatus2 =
|
||||
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() ? OptTrue : OptFalse,
|
||||
batteryLevel->isCharging() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
|
||||
const PowerStatus powerStatus2 = PowerStatus(
|
||||
hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() || NRF_USB == OptTrue ? OptTrue : OptFalse,
|
||||
batteryLevel->isCharging() || NRF_USB == OptTrue ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
|
||||
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
|
||||
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
|
||||
newStatus.notifyObservers(&powerStatus2);
|
||||
@@ -877,4 +894,4 @@ bool Power::axpChipInit()
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class PowerFSMThread : public OSThread
|
||||
|
||||
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
|
||||
/// cpu for serial rx - FIXME)
|
||||
const auto state = powerFSM.getState();
|
||||
const State *state = powerFSM.getState();
|
||||
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
|
||||
|
||||
if (powerStatus->getHasUSB()) {
|
||||
@@ -33,7 +33,7 @@ class PowerFSMThread : public OSThread
|
||||
powerFSM.trigger(EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
return 10;
|
||||
return 100;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "concurrency/LockGuard.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if defined(ARCH_RASPBERRY_PI)
|
||||
#include "linux/LinuxHardwareI2C.h"
|
||||
#endif
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
#include "main.h" // atecc
|
||||
#endif
|
||||
@@ -162,7 +164,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
|
||||
for (addr.address = 1; addr.address < 127; addr.address++) {
|
||||
i2cBus->beginTransmission(addr.address);
|
||||
#ifdef ARCH_PORTDUINO
|
||||
if (i2cBus->read() != -1)
|
||||
err = 0;
|
||||
else
|
||||
err = 2;
|
||||
#else
|
||||
err = i2cBus->endTransmission();
|
||||
#endif
|
||||
type = NONE;
|
||||
if (err == 0) {
|
||||
LOG_DEBUG("I2C device found at address 0x%x\n", addr.address);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ubx.h"
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "PortduinoGlue.h"
|
||||
#include "meshUtils.h"
|
||||
#include <ctime>
|
||||
#endif
|
||||
@@ -15,11 +16,8 @@
|
||||
#define GPS_RESET_MODE HIGH
|
||||
#endif
|
||||
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32)
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_RASPBERRY_PI)
|
||||
HardwareSerial *GPS::_serial_gps = &Serial1;
|
||||
#elif defined(ARCH_RASPBERRY_PI)
|
||||
// need a translation layer to make _serial_gps work with pigpio https://abyz.me.uk/rpi/pigpio/cif.html#serOpen
|
||||
HardwareSerial *GPS::_serial_gps = NULL;
|
||||
#else
|
||||
HardwareSerial *GPS::_serial_gps = NULL;
|
||||
#endif
|
||||
@@ -264,6 +262,20 @@ bool GPS::setup()
|
||||
isProblematicGPS = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RAK4630) && defined(PIN_3V3_EN)
|
||||
// If we are using the RAK4630 and we have no other peripherals on the I2C bus or module interest in 3V3_S,
|
||||
// then we can safely set en_gpio turn off power to 3V3 (IO2) to hard sleep the GPS
|
||||
if (rtc_found.port == ScanI2C::DeviceType::NONE && rgb_found.type == ScanI2C::DeviceType::NONE &&
|
||||
accelerometer_found.port == ScanI2C::DeviceType::NONE && !moduleConfig.detection_sensor.enabled &&
|
||||
!moduleConfig.telemetry.air_quality_enabled && !moduleConfig.telemetry.environment_measurement_enabled &&
|
||||
config.power.device_battery_ina_address == 0 && en_gpio == 0) {
|
||||
LOG_DEBUG("Since no problematic peripherals or interested modules were found, setting power save GPS_EN to pin %i\n",
|
||||
PIN_3V3_EN);
|
||||
en_gpio = PIN_3V3_EN;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]);
|
||||
gnssModel = probe(serialSpeeds[speedSelect]);
|
||||
@@ -281,7 +293,7 @@ bool GPS::setup()
|
||||
gnssModel = GNSS_MODEL_UNKNOWN;
|
||||
}
|
||||
#else
|
||||
gnssModel = GNSS_MODEL_UC6850;
|
||||
gnssModel = GNSS_MODEL_UC6580;
|
||||
#endif
|
||||
|
||||
if (gnssModel == GNSS_MODEL_MTK) {
|
||||
@@ -299,11 +311,23 @@ bool GPS::setup()
|
||||
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
||||
_serial_gps->write("$PCAS11,3*1E\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_UC6850) {
|
||||
|
||||
// use GPS + GLONASS
|
||||
_serial_gps->write("$CFGSYS,h15\r\n");
|
||||
} else if (gnssModel == GNSS_MODEL_UC6580) {
|
||||
// The Unicore UC6580 can use a lot of sat systems, enable it to
|
||||
// use GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS
|
||||
// This will reset the receiver, so wait a bit afterwards
|
||||
// The paranoid will wait for the OK*04 confirmation response after each command.
|
||||
_serial_gps->write("$CFGSYS,h25155\r\n");
|
||||
delay(750);
|
||||
// Must be done after the CFGSYS command
|
||||
// Turn off GSV messages, we don't really care about which and where the sats are, maybe someday.
|
||||
_serial_gps->write("$CFGMSG,0,3,0\r\n");
|
||||
delay(250);
|
||||
// Turn off NOTICE __TXT messages, these may provide Unicore some info but we don't care.
|
||||
_serial_gps->write("$CFGMSG,6,0,0\r\n");
|
||||
delay(250);
|
||||
_serial_gps->write("$CFGMSG,6,1,0\r\n");
|
||||
delay(250);
|
||||
|
||||
} else if (gnssModel == GNSS_MODEL_UBLOX) {
|
||||
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
|
||||
// We need set it because by default it is GPS only, and we want to use GLONASS too
|
||||
@@ -436,6 +460,7 @@ bool GPS::setup()
|
||||
|
||||
notifyDeepSleepObserver.observe(¬ifyDeepSleep);
|
||||
notifyGPSSleepObserver.observe(¬ifyGPSSleep);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -482,14 +507,14 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime)
|
||||
#ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76K and clones
|
||||
if (on) {
|
||||
LOG_INFO("Waking GPS");
|
||||
digitalWrite(PIN_GPS_STANDBY, 1);
|
||||
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||
digitalWrite(PIN_GPS_STANDBY, 1);
|
||||
return;
|
||||
} else {
|
||||
LOG_INFO("GPS entering sleep");
|
||||
// notifyGPSSleep.notifyObservers(NULL);
|
||||
digitalWrite(PIN_GPS_STANDBY, 0);
|
||||
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||
digitalWrite(PIN_GPS_STANDBY, 0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -550,15 +575,20 @@ void GPS::setAwake(bool on)
|
||||
if ((int32_t)getSleepTime() - averageLockTime >
|
||||
15 * 60 * 1000) { // 15 minutes is probably long enough to make a complete poweroff worth it.
|
||||
setGPSPower(on, false, getSleepTime() - averageLockTime);
|
||||
return;
|
||||
} else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby
|
||||
#ifdef GPS_UC6580
|
||||
setGPSPower(on, false, getSleepTime() - averageLockTime);
|
||||
#else
|
||||
setGPSPower(on, true, getSleepTime() - averageLockTime);
|
||||
#endif
|
||||
} else if (averageLockTime > 20000) {
|
||||
return;
|
||||
}
|
||||
if (averageLockTime > 20000) {
|
||||
averageLockTime -= 1000; // eventually want to sleep again.
|
||||
}
|
||||
if (on)
|
||||
setGPSPower(true, true, 0); // make sure we don't have a fallthrough where GPS is stuck off
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,6 +922,10 @@ GPS *GPS::createGps()
|
||||
#if defined(PIN_GPS_EN)
|
||||
if (!_en_gpio)
|
||||
_en_gpio = PIN_GPS_EN;
|
||||
#endif
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
if (!settingsMap[has_gps])
|
||||
return nullptr;
|
||||
#endif
|
||||
if (!_rx_gpio || !_serial_gps) // Configured to have no GPS at all
|
||||
return nullptr;
|
||||
@@ -903,8 +937,8 @@ GPS *GPS::createGps()
|
||||
|
||||
if (_en_gpio != 0) {
|
||||
LOG_DEBUG("Setting %d to output.\n", _en_gpio);
|
||||
digitalWrite(_en_gpio, !GPS_EN_ACTIVE);
|
||||
pinMode(_en_gpio, OUTPUT);
|
||||
digitalWrite(_en_gpio, !GPS_EN_ACTIVE);
|
||||
}
|
||||
|
||||
#ifdef PIN_GPS_PPS
|
||||
@@ -924,8 +958,8 @@ GPS *GPS::createGps()
|
||||
new_gps->setGPSPower(true, false, 0);
|
||||
|
||||
#ifdef PIN_GPS_RESET
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||
delay(10);
|
||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||
#endif
|
||||
@@ -970,8 +1004,8 @@ bool GPS::factoryReset()
|
||||
{
|
||||
#ifdef PIN_GPS_REINIT
|
||||
// The L76K GNSS on the T-Echo requires the RESET pin to be pulled LOW
|
||||
digitalWrite(PIN_GPS_REINIT, 0);
|
||||
pinMode(PIN_GPS_REINIT, OUTPUT);
|
||||
digitalWrite(PIN_GPS_REINIT, 0);
|
||||
delay(150); // The L76K datasheet calls for at least 100MS delay
|
||||
digitalWrite(PIN_GPS_REINIT, 1);
|
||||
#endif
|
||||
@@ -1251,4 +1285,4 @@ int32_t GPS::disable()
|
||||
setAwake(false);
|
||||
|
||||
return INT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ struct uBloxGnssModelInfo {
|
||||
typedef enum {
|
||||
GNSS_MODEL_MTK,
|
||||
GNSS_MODEL_UBLOX,
|
||||
GNSS_MODEL_UC6850,
|
||||
GNSS_MODEL_UC6580,
|
||||
GNSS_MODEL_UNKNOWN,
|
||||
} GnssModel_t;
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
#endif
|
||||
|
||||
// nrf52 doesn't have a readable RTC (yet - software not written)
|
||||
#ifdef HAS_RTC
|
||||
#if HAS_RTC
|
||||
readFromRTC();
|
||||
#endif
|
||||
|
||||
@@ -208,4 +208,4 @@ uint32_t getTime()
|
||||
uint32_t getValidTime(RTCQuality minQuality)
|
||||
{
|
||||
return (currentQuality >= minQuality) ? getTime() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
//#define TECHO_DISPLAY_MODEL GxEPD2_213_T5D
|
||||
// #define TECHO_DISPLAY_MODEL GxEPD2_213_T5D
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
||||
#endif
|
||||
|
||||
@@ -193,14 +193,14 @@ bool EInkDisplay::connect()
|
||||
LOG_INFO("Doing EInk init\n");
|
||||
|
||||
#ifdef PIN_EINK_PWR_ON
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
pinMode(PIN_EINK_PWR_ON, OUTPUT);
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
#endif
|
||||
|
||||
#ifdef PIN_EINK_EN
|
||||
// backlight power, HIGH is backlight on, LOW is off
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
#endif
|
||||
|
||||
#if defined(TTGO_T_ECHO)
|
||||
|
||||
@@ -43,12 +43,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
|
||||
#if HAS_WIFI && !defined(ARCH_RASPBERRY_PI)
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#endif
|
||||
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_RU
|
||||
#include "fonts/OLEDDisplayFontsRU.h"
|
||||
#endif
|
||||
@@ -906,10 +913,40 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
}
|
||||
|
||||
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
|
||||
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
|
||||
dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
|
||||
ui(&dispdev)
|
||||
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32)
|
||||
{
|
||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||
dispdev = new SH1106Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_SSD1306)
|
||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
|
||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_EINK)
|
||||
dispdev = new EInkDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_ST7567)
|
||||
dispdev = new ST7567Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif ARCH_RASPBERRY_PI
|
||||
if (settingsMap[displayPanel] == st7789) {
|
||||
LOG_DEBUG("Making TFTDisplay!\n");
|
||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
} else {
|
||||
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
isAUTOOled = true;
|
||||
}
|
||||
#else
|
||||
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
isAUTOOled = true;
|
||||
#endif
|
||||
|
||||
ui = new OLEDDisplayUi(dispdev);
|
||||
cmdQueue.setReader(this);
|
||||
}
|
||||
|
||||
@@ -922,8 +959,8 @@ void Screen::doDeepSleep()
|
||||
#ifdef USE_EINK
|
||||
static FrameCallback sleepFrames[] = {drawSleepScreen};
|
||||
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
|
||||
ui.setFrames(sleepFrames, sleepFrameCount);
|
||||
ui.update();
|
||||
ui->setFrames(sleepFrames, sleepFrameCount);
|
||||
ui->update();
|
||||
#endif
|
||||
setOn(false);
|
||||
}
|
||||
@@ -939,14 +976,16 @@ void Screen::handleSetOn(bool on)
|
||||
#ifdef T_WATCH_S3
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||
#endif
|
||||
dispdev.displayOn();
|
||||
dispdev.displayOn();
|
||||
#if !ARCH_RASPBERRY_PI
|
||||
dispdev->displayOn();
|
||||
#endif
|
||||
dispdev->displayOn();
|
||||
enabled = true;
|
||||
setInterval(0); // Draw ASAP
|
||||
runASAP = true;
|
||||
} else {
|
||||
LOG_INFO("Turning off screen\n");
|
||||
dispdev.displayOff();
|
||||
dispdev->displayOff();
|
||||
#ifdef T_WATCH_S3
|
||||
PMU->disablePowerOutput(XPOWERS_ALDO2);
|
||||
#endif
|
||||
@@ -963,32 +1002,33 @@ void Screen::setup()
|
||||
useDisplay = true;
|
||||
|
||||
#ifdef AutoOLEDWire_h
|
||||
dispdev.setDetected(model);
|
||||
if (isAUTOOled)
|
||||
static_cast<AutoOLEDWire *>(dispdev)->setDetected(model);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SH1107_128_64
|
||||
dispdev.setSubtype(7);
|
||||
static_cast<SH1106Wire *>(dispdev)->setSubtype(7);
|
||||
#endif
|
||||
|
||||
// Initialising the UI will init the display too.
|
||||
ui.init();
|
||||
ui->init();
|
||||
|
||||
displayWidth = dispdev.width();
|
||||
displayHeight = dispdev.height();
|
||||
displayWidth = dispdev->width();
|
||||
displayHeight = dispdev->height();
|
||||
|
||||
ui.setTimePerTransition(0);
|
||||
ui->setTimePerTransition(0);
|
||||
|
||||
ui.setIndicatorPosition(BOTTOM);
|
||||
ui->setIndicatorPosition(BOTTOM);
|
||||
// Defines where the first frame is located in the bar.
|
||||
ui.setIndicatorDirection(LEFT_RIGHT);
|
||||
ui.setFrameAnimation(SLIDE_LEFT);
|
||||
ui->setIndicatorDirection(LEFT_RIGHT);
|
||||
ui->setFrameAnimation(SLIDE_LEFT);
|
||||
// Don't show the page swipe dots while in boot screen.
|
||||
ui.disableAllIndicators();
|
||||
ui->disableAllIndicators();
|
||||
// Store a pointer to Screen so we can get to it from static functions.
|
||||
ui.getUiState()->userData = this;
|
||||
ui->getUiState()->userData = this;
|
||||
|
||||
// Set the utf8 conversion function
|
||||
dispdev.setFontTableLookupFunction(customFontTableLookup);
|
||||
dispdev->setFontTableLookupFunction(customFontTableLookup);
|
||||
|
||||
if (strlen(oemStore.oem_text) > 0)
|
||||
logo_timeout *= 2;
|
||||
@@ -996,23 +1036,23 @@ void Screen::setup()
|
||||
// Add frames.
|
||||
static FrameCallback bootFrames[] = {drawBootScreen};
|
||||
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
|
||||
ui.setFrames(bootFrames, bootFrameCount);
|
||||
ui->setFrames(bootFrames, bootFrameCount);
|
||||
// No overlays.
|
||||
ui.setOverlays(nullptr, 0);
|
||||
ui->setOverlays(nullptr, 0);
|
||||
|
||||
// Require presses to switch between frames.
|
||||
ui.disableAutoTransition();
|
||||
ui->disableAutoTransition();
|
||||
|
||||
// Set up a log buffer with 3 lines, 32 chars each.
|
||||
dispdev.setLogBuffer(3, 32);
|
||||
dispdev->setLogBuffer(3, 32);
|
||||
|
||||
#ifdef SCREEN_MIRROR
|
||||
dispdev.mirrorScreen();
|
||||
dispdev->mirrorScreen();
|
||||
#else
|
||||
// Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically
|
||||
// flip it. If you have a headache now, you're welcome.
|
||||
if (!config.display.flip_screen) {
|
||||
dispdev.flipScreenVertically();
|
||||
dispdev->flipScreenVertically();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1020,20 +1060,30 @@ void Screen::setup()
|
||||
uint8_t dmac[6];
|
||||
getMacAddr(dmac);
|
||||
snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]);
|
||||
#if ARCH_RASPBERRY_PI
|
||||
handleSetOn(false); // force clean init
|
||||
#endif
|
||||
|
||||
// Turn on the display.
|
||||
handleSetOn(true);
|
||||
|
||||
// On some ssd1306 clones, the first draw command is discarded, so draw it
|
||||
// twice initially. Skip this for EINK Displays to save a few seconds during boot
|
||||
ui.update();
|
||||
ui->update();
|
||||
#ifndef USE_EINK
|
||||
ui.update();
|
||||
ui->update();
|
||||
#endif
|
||||
serialSinceMsec = millis();
|
||||
|
||||
#if HAS_TOUCHSCREEN
|
||||
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
|
||||
#if ARCH_RASPBERRY_PI
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
touchScreenImpl1->init();
|
||||
}
|
||||
#elif HAS_TOUCHSCREEN
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
touchScreenImpl1->init();
|
||||
#endif
|
||||
|
||||
@@ -1054,7 +1104,7 @@ void Screen::forceDisplay()
|
||||
{
|
||||
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
|
||||
#ifdef USE_EINK
|
||||
dispdev.forceDisplay();
|
||||
static_cast<EInkDisplay *>(dispdev)->forceDisplay();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1085,10 +1135,10 @@ int32_t Screen::runOnce()
|
||||
// Change frames.
|
||||
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
|
||||
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
|
||||
ui.setFrames(bootOEMFrames, bootOEMFrameCount);
|
||||
ui.update();
|
||||
ui->setFrames(bootOEMFrames, bootOEMFrameCount);
|
||||
ui->update();
|
||||
#ifndef USE_EINK
|
||||
ui.update();
|
||||
ui->update();
|
||||
#endif
|
||||
showingOEMBootScreen = false;
|
||||
}
|
||||
@@ -1161,16 +1211,16 @@ int32_t Screen::runOnce()
|
||||
|
||||
// this must be before the frameState == FIXED check, because we always
|
||||
// want to draw at least one FIXED frame before doing forceDisplay
|
||||
ui.update();
|
||||
ui->update();
|
||||
|
||||
// Switch to a low framerate (to save CPU) when we are not in transition
|
||||
// but we should only call setTargetFPS when framestate changes, because
|
||||
// otherwise that breaks animations.
|
||||
if (targetFramerate != IDLE_FRAMERATE && ui.getUiState()->frameState == FIXED) {
|
||||
// oldFrameState = ui.getUiState()->frameState;
|
||||
if (targetFramerate != IDLE_FRAMERATE && ui->getUiState()->frameState == FIXED) {
|
||||
// oldFrameState = ui->getUiState()->frameState;
|
||||
targetFramerate = IDLE_FRAMERATE;
|
||||
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
ui->setTargetFPS(targetFramerate);
|
||||
forceDisplay();
|
||||
}
|
||||
|
||||
@@ -1186,7 +1236,7 @@ int32_t Screen::runOnce()
|
||||
}
|
||||
|
||||
// LOG_DEBUG("want fps %d, fixed=%d\n", targetFramerate,
|
||||
// ui.getUiState()->frameState); If we are scrolling we need to be called
|
||||
// ui->getUiState()->frameState); If we are scrolling we need to be called
|
||||
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
|
||||
// as fast as we really need so that any rounding errors still result with
|
||||
// the correct framerate
|
||||
@@ -1218,8 +1268,8 @@ void Screen::setSSLFrames()
|
||||
if (address_found.address) {
|
||||
// LOG_DEBUG("showing SSL frames\n");
|
||||
static FrameCallback sslFrames[] = {drawSSLScreen};
|
||||
ui.setFrames(sslFrames, 1);
|
||||
ui.update();
|
||||
ui->setFrames(sslFrames, 1);
|
||||
ui->update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1294,7 +1344,7 @@ void Screen::setFrames()
|
||||
// call a method on debugInfoScreen object (for more details)
|
||||
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#if HAS_WIFI && !defined(ARCH_RASPBERRY_PI)
|
||||
if (isWifiAvailable()) {
|
||||
// call a method on debugInfoScreen object (for more details)
|
||||
normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline;
|
||||
@@ -1303,8 +1353,8 @@ void Screen::setFrames()
|
||||
|
||||
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
|
||||
|
||||
ui.setFrames(normalFrames, numframes);
|
||||
ui.enableAllIndicators();
|
||||
ui->setFrames(normalFrames, numframes);
|
||||
ui->enableAllIndicators();
|
||||
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||
// just changed)
|
||||
@@ -1324,8 +1374,8 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
||||
|
||||
void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
|
||||
{
|
||||
ui.disableAllIndicators();
|
||||
ui.setFrames(drawFrames, 1);
|
||||
ui->disableAllIndicators();
|
||||
ui->setFrames(drawFrames, 1);
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
@@ -1367,17 +1417,17 @@ void Screen::blink()
|
||||
{
|
||||
setFastFramerate();
|
||||
uint8_t count = 10;
|
||||
dispdev.setBrightness(254);
|
||||
dispdev->setBrightness(254);
|
||||
while (count > 0) {
|
||||
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
dispdev.display();
|
||||
dispdev->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
dispdev->display();
|
||||
delay(50);
|
||||
dispdev.clear();
|
||||
dispdev.display();
|
||||
dispdev->clear();
|
||||
dispdev->display();
|
||||
delay(50);
|
||||
count = count - 1;
|
||||
}
|
||||
dispdev.setBrightness(brightness);
|
||||
dispdev->setBrightness(brightness);
|
||||
}
|
||||
|
||||
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
|
||||
@@ -1405,15 +1455,15 @@ void Screen::handlePrint(const char *text)
|
||||
if (!useDisplay || !showingNormalScreen)
|
||||
return;
|
||||
|
||||
dispdev.print(text);
|
||||
dispdev->print(text);
|
||||
}
|
||||
|
||||
void Screen::handleOnPress()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise advance to next frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
if (ui->getUiState()->frameState == FIXED) {
|
||||
ui->nextFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
@@ -1423,8 +1473,8 @@ void Screen::handleShowPrevFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise go back to previous frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.previousFrame();
|
||||
if (ui->getUiState()->frameState == FIXED) {
|
||||
ui->previousFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
@@ -1434,8 +1484,8 @@ void Screen::handleShowNextFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise advance to next frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
if (ui->getUiState()->frameState == FIXED) {
|
||||
ui->nextFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
@@ -1450,7 +1500,7 @@ void Screen::setFastFramerate()
|
||||
// We are about to start a transition so speed up fps
|
||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
ui->setTargetFPS(targetFramerate);
|
||||
setInterval(0); // redraw ASAP
|
||||
runASAP = true;
|
||||
}
|
||||
@@ -1537,7 +1587,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
// TODO: Raspberry Pi supports more than just the one screen size
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_RASPBERRY_PI) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgInfoL1);
|
||||
@@ -1564,7 +1615,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
// Jm
|
||||
void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
#if HAS_WIFI
|
||||
#if HAS_WIFI && !defined(ARCH_RASPBERRY_PI)
|
||||
const char *wifiName = config.network.wifi_ssid;
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
@@ -1618,12 +1669,19 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
|
||||
} else if (WiFi.status() == WL_IDLE_STATUS) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
|
||||
} else {
|
||||
}
|
||||
#ifdef ARCH_ESP32
|
||||
else {
|
||||
// Codes:
|
||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
|
||||
WiFi.disconnectReasonName(static_cast<wifi_err_reason_t>(getWifiDisconnectReason())));
|
||||
}
|
||||
#else
|
||||
else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unkown status: " + String(WiFi.status()));
|
||||
}
|
||||
#endif
|
||||
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
|
||||
|
||||
@@ -1770,7 +1828,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
setFastFramerate();
|
||||
// TODO: We might also want switch to corresponding frame,
|
||||
// but we don't know the exact frame number.
|
||||
// ui.switchToFrame(0);
|
||||
// ui->switchToFrame(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -324,6 +324,8 @@ class Screen : public concurrency::OSThread
|
||||
// Called periodically from the main loop.
|
||||
int32_t runOnce() final;
|
||||
|
||||
bool isAUTOOled = false;
|
||||
|
||||
private:
|
||||
struct ScreenCmd {
|
||||
Cmd cmd;
|
||||
@@ -385,22 +387,10 @@ class Screen : public concurrency::OSThread
|
||||
DebugInfo debugInfo;
|
||||
|
||||
/// Display device
|
||||
OLEDDisplay *dispdev;
|
||||
|
||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||
SH1106Wire dispdev;
|
||||
#elif defined(USE_SSD1306)
|
||||
SSD1306Wire dispdev;
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
|
||||
TFTDisplay dispdev;
|
||||
#elif defined(USE_EINK)
|
||||
EInkDisplay dispdev;
|
||||
#elif defined(USE_ST7567)
|
||||
ST7567Wire dispdev;
|
||||
#else
|
||||
AutoOLEDWire dispdev;
|
||||
#endif
|
||||
/// UI helper for rendering to frames and switching between them
|
||||
OLEDDisplayUi ui;
|
||||
OLEDDisplayUi *ui;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
#ifndef TFT_BACKLIGHT_ON
|
||||
#define TFT_BACKLIGHT_ON HIGH
|
||||
@@ -103,11 +106,11 @@ class LGFX : public lgfx::LGFX_Device
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX tft;
|
||||
static LGFX *tft = nullptr;
|
||||
|
||||
#elif defined(RAK14014)
|
||||
#include <TFT_eSPI.h>
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSPI *tft = nullptr;
|
||||
|
||||
#elif defined(ST7789_CS)
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
@@ -233,7 +236,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX tft;
|
||||
static LGFX *tft = nullptr;
|
||||
|
||||
#elif defined(ILI9341_DRIVER)
|
||||
|
||||
@@ -322,23 +325,96 @@ class LGFX : public lgfx::LGFX_Device
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX tft;
|
||||
static LGFX *tft = nullptr;
|
||||
|
||||
#elif defined(ST7735_CS)
|
||||
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
||||
|
||||
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
||||
static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
|
||||
#elif ARCH_RASPBERRY_PI
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_LCD *_panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
|
||||
lgfx::ITouch *_touch_instance;
|
||||
|
||||
public:
|
||||
LGFX(void)
|
||||
{
|
||||
|
||||
_panel_instance = new lgfx::Panel_ST7789;
|
||||
auto buscfg = _bus_instance.config();
|
||||
buscfg.spi_mode = 0;
|
||||
|
||||
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(buscfg); // applies the set value to the bus.
|
||||
_panel_instance->setBus(&_bus_instance); // set the bus on the panel.
|
||||
|
||||
auto cfg = _panel_instance->config(); // Gets a structure for display panel settings.
|
||||
LOG_DEBUG("Height: %d, Width: %d \n", settingsMap[displayHeight], settingsMap[displayWidth]);
|
||||
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
|
||||
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
|
||||
cfg.offset_x = 0; // Panel offset amount in X direction
|
||||
cfg.offset_y = 0; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit = false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
|
||||
_panel_instance->config(cfg);
|
||||
|
||||
// Configure settings for touch control.
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
if (settingsMap[touchscreenModule] == xpt2046) {
|
||||
_touch_instance = new lgfx::Touch_XPT2046;
|
||||
}
|
||||
auto touch_cfg = _touch_instance->config();
|
||||
|
||||
touch_cfg.pin_cs = settingsMap[touchscreenCS];
|
||||
touch_cfg.x_min = 0;
|
||||
touch_cfg.x_max = settingsMap[displayHeight] - 1;
|
||||
touch_cfg.y_min = 0;
|
||||
touch_cfg.y_max = settingsMap[displayWidth] - 1;
|
||||
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
|
||||
touch_cfg.bus_shared = true;
|
||||
touch_cfg.offset_rotation = 1;
|
||||
|
||||
_touch_instance->config(touch_cfg);
|
||||
_panel_instance->setTouch(_touch_instance);
|
||||
}
|
||||
|
||||
setPanel(_panel_instance); // Sets the panel to use.
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX *tft = nullptr;
|
||||
#endif
|
||||
|
||||
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014)
|
||||
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014) || ARCH_RASPBERRY_PI
|
||||
#include "SPILock.h"
|
||||
#include "TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
|
||||
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||
{
|
||||
#ifdef SCREEN_ROTATE
|
||||
LOG_DEBUG("TFTDisplay!\n");
|
||||
#if ARCH_RASPBERRY_PI
|
||||
if (settingsMap[displayRotate]) {
|
||||
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayHeight], settingsMap[configNames::displayWidth]);
|
||||
} else {
|
||||
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayWidth], settingsMap[configNames::displayHeight]);
|
||||
}
|
||||
|
||||
#elif defined(SCREEN_ROTATE)
|
||||
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
|
||||
#else
|
||||
setGeometry(GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
||||
@@ -346,19 +422,25 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
|
||||
}
|
||||
|
||||
// Write the buffer to the display memory
|
||||
void TFTDisplay::display(void)
|
||||
void TFTDisplay::display(bool fromBlank)
|
||||
{
|
||||
if (fromBlank)
|
||||
tft->clear();
|
||||
concurrency::LockGuard g(spiLock);
|
||||
|
||||
uint16_t x, y;
|
||||
|
||||
for (y = 0; y < displayHeight; y++) {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
if (isset != dblbuf_isset) {
|
||||
tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
||||
if (!fromBlank) {
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
if (isset != dblbuf_isset) {
|
||||
tft->drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
||||
}
|
||||
} else if (isset) {
|
||||
tft->drawPixel(x, y, TFT_MESH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -377,7 +459,11 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
// handle display on/off directly
|
||||
switch (com) {
|
||||
case DISPLAYON: {
|
||||
#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||
#if ARCH_RASPBERRY_PI
|
||||
display(true);
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON);
|
||||
#elif defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||
if (heltec_version == 3) {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
|
||||
} else {
|
||||
@@ -400,12 +486,16 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
tft.setBrightness(128);
|
||||
tft->setBrightness(128);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case DISPLAYOFF: {
|
||||
#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||
#if ARCH_RASPBERRY_PI
|
||||
tft->clear();
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
digitalWrite(settingsMap[displayBacklight], !TFT_BACKLIGHT_ON);
|
||||
#elif defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||
if (heltec_version == 3) {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON);
|
||||
} else {
|
||||
@@ -427,7 +517,7 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
#endif
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
tft.setBrightness(0);
|
||||
tft->setBrightness(0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -442,7 +532,7 @@ void TFTDisplay::flipScreenVertically()
|
||||
{
|
||||
#if defined(T_WATCH_S3)
|
||||
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
|
||||
tft.setRotation(0);
|
||||
tft->setRotation(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -450,7 +540,7 @@ bool TFTDisplay::hasTouch(void)
|
||||
{
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
return tft.touch() != nullptr;
|
||||
return tft->touch() != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -460,7 +550,7 @@ bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
|
||||
{
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
return tft.getTouch(x, y);
|
||||
return tft->getTouch(x, y);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -476,10 +566,15 @@ bool TFTDisplay::connect()
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
LOG_INFO("Doing TFT init\n");
|
||||
#ifdef RAK14014
|
||||
tft = new TFT_eSPI;
|
||||
#else
|
||||
tft = new LGFX;
|
||||
#endif
|
||||
|
||||
#ifdef TFT_BL
|
||||
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
|
||||
pinMode(TFT_BL, OUTPUT);
|
||||
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
|
||||
// pinMode(PIN_3V3_EN, OUTPUT);
|
||||
// digitalWrite(PIN_3V3_EN, HIGH);
|
||||
LOG_INFO("Power to TFT Backlight\n");
|
||||
@@ -487,30 +582,30 @@ bool TFTDisplay::connect()
|
||||
|
||||
#ifdef ST7735_BACKLIGHT_EN_V03
|
||||
if (heltec_version == 3) {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
|
||||
pinMode(ST7735_BACKLIGHT_EN_V03, OUTPUT);
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
|
||||
} else {
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
|
||||
pinMode(ST7735_BACKLIGHT_EN_V05, OUTPUT);
|
||||
digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
|
||||
}
|
||||
#endif
|
||||
|
||||
tft.init();
|
||||
tft->init();
|
||||
|
||||
#if defined(M5STACK)
|
||||
tft.setRotation(0);
|
||||
tft->setRotation(0);
|
||||
#elif defined(RAK14014)
|
||||
tft.setRotation(1);
|
||||
tft.setSwapBytes(true);
|
||||
// tft.fillScreen(TFT_BLACK);
|
||||
tft->setRotation(1);
|
||||
tft->setSwapBytes(true);
|
||||
// tft->fillScreen(TFT_BLACK);
|
||||
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
|
||||
tft.setRotation(1); // T-Deck has the TFT in landscape
|
||||
tft->setRotation(1); // T-Deck has the TFT in landscape
|
||||
#elif defined(T_WATCH_S3)
|
||||
tft.setRotation(2); // T-Watch S3 left-handed orientation
|
||||
tft->setRotation(2); // T-Watch S3 left-handed orientation
|
||||
#else
|
||||
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||
#endif
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft->fillScreen(TFT_BLACK);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ class TFTDisplay : public OLEDDisplay
|
||||
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
||||
|
||||
// Write the buffer to the display memory
|
||||
virtual void display(void) override;
|
||||
virtual void display() override { display(false); };
|
||||
virtual void display(bool fromBlank);
|
||||
|
||||
// Turn the display upside down
|
||||
virtual void flipScreenVertically();
|
||||
|
||||
@@ -14,7 +14,7 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
|
||||
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
|
||||
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_RASPBERRY_PI) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||
@@ -30,4 +30,4 @@ const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1,
|
||||
const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
|
||||
#endif
|
||||
|
||||
#include "img/icon.xbm"
|
||||
#include "img/icon.xbm"
|
||||
184
src/input/LinuxInput.cpp
Normal file
184
src/input/LinuxInput.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "LinuxInput.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Inspired by https://github.com/librerpi/rpi-tools/blob/master/keyboard-proxy/main.c which is GPL-v2
|
||||
|
||||
LinuxInput::LinuxInput(const char *name) : concurrency::OSThread(name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
void LinuxInput::deInit()
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int32_t LinuxInput::runOnce()
|
||||
{
|
||||
|
||||
if (firstTime) {
|
||||
if (settingsStrings[keyboardDevice] == "")
|
||||
return disable();
|
||||
fd = open(settingsStrings[keyboardDevice].c_str(), O_RDWR);
|
||||
if (fd < 0)
|
||||
return disable();
|
||||
ret = ioctl(fd, EVIOCGRAB, (void *)1);
|
||||
if (ret != 0)
|
||||
return disable();
|
||||
|
||||
epollfd = epoll_create1(0);
|
||||
assert(epollfd >= 0);
|
||||
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = fd;
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
|
||||
perror("unable to epoll add");
|
||||
return disable();
|
||||
}
|
||||
// This is the first time the OSThread library has called this function, so do port setup
|
||||
firstTime = 0;
|
||||
}
|
||||
|
||||
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, 1);
|
||||
if (nfds < 0) {
|
||||
printf("%d ", nfds);
|
||||
perror("epoll_wait failed");
|
||||
return disable();
|
||||
} else if (nfds == 0) {
|
||||
return 50;
|
||||
}
|
||||
|
||||
int keys = 0;
|
||||
memset(report, 0, 8);
|
||||
for (int i = 0; i < nfds; i++) {
|
||||
|
||||
struct input_event ev[64];
|
||||
int rd = read(events[i].data.fd, ev, sizeof(ev));
|
||||
assert(rd > ((signed int)sizeof(struct input_event)));
|
||||
for (int j = 0; j < rd / ((signed int)sizeof(struct input_event)); j++) {
|
||||
InputEvent e;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
e.kbchar = 0;
|
||||
unsigned int type, code;
|
||||
type = ev[j].type;
|
||||
code = ev[j].code;
|
||||
int value = ev[j].value;
|
||||
// printf("Event: time %ld.%06ld, ", ev[j].time.tv_sec, ev[j].time.tv_usec);
|
||||
|
||||
if (type == EV_KEY) {
|
||||
uint8_t mod = 0;
|
||||
|
||||
switch (code) {
|
||||
case KEY_LEFTCTRL:
|
||||
mod = 0x01;
|
||||
break;
|
||||
case KEY_RIGHTCTRL:
|
||||
mod = 0x10;
|
||||
break;
|
||||
case KEY_LEFTSHIFT:
|
||||
mod = 0x02;
|
||||
break;
|
||||
case KEY_RIGHTSHIFT:
|
||||
mod = 0x20;
|
||||
break;
|
||||
case KEY_LEFTALT:
|
||||
mod = 0x04;
|
||||
break;
|
||||
case KEY_RIGHTALT:
|
||||
mod = 0x40;
|
||||
break;
|
||||
case KEY_LEFTMETA:
|
||||
mod = 0x08;
|
||||
break;
|
||||
}
|
||||
if (value == 1) {
|
||||
switch (code) {
|
||||
case KEY_LEFTCTRL:
|
||||
mod = 0x01;
|
||||
break;
|
||||
case KEY_RIGHTCTRL:
|
||||
mod = 0x10;
|
||||
break;
|
||||
case KEY_LEFTSHIFT:
|
||||
mod = 0x02;
|
||||
break;
|
||||
case KEY_RIGHTSHIFT:
|
||||
mod = 0x20;
|
||||
break;
|
||||
case KEY_LEFTALT:
|
||||
mod = 0x04;
|
||||
break;
|
||||
case KEY_RIGHTALT:
|
||||
mod = 0x40;
|
||||
break;
|
||||
case KEY_LEFTMETA:
|
||||
mod = 0x08;
|
||||
break;
|
||||
case KEY_ESC: // ESC
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
break;
|
||||
case KEY_BACK: // Back
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||
// e.kbchar = key;
|
||||
break;
|
||||
|
||||
case KEY_UP: // Up
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||
break;
|
||||
case KEY_DOWN: // Down
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||
break;
|
||||
case KEY_LEFT: // Left
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||
break;
|
||||
e.kbchar = 0xb4;
|
||||
case KEY_RIGHT: // Right
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
break;
|
||||
e.kbchar = 0xb7;
|
||||
case KEY_ENTER: // Enter
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
break;
|
||||
default: // all other keys
|
||||
if (keymap[code]) {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = keymap[code];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ev[j].value) {
|
||||
modifiers |= mod;
|
||||
} else {
|
||||
modifiers &= ~mod;
|
||||
}
|
||||
report[0] = modifiers;
|
||||
}
|
||||
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||
if (e.inputEvent == ANYKEY && (modifiers && 0x22))
|
||||
e.kbchar = uppers[e.kbchar]; // doesn't get punctuation. Meh.
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 50; // Keyscan every 50msec to avoid key bounce
|
||||
}
|
||||
|
||||
#endif
|
||||
65
src/input/LinuxInput.h
Normal file
65
src/input/LinuxInput.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_EVENTS 10
|
||||
|
||||
class LinuxInput : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit LinuxInput(const char *name);
|
||||
void deInit(); // Strictly for cleanly "rebooting" the binary on native
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
const char *_originName;
|
||||
bool firstTime = 1;
|
||||
int shift = 0;
|
||||
char key = 0;
|
||||
char prevkey = 0;
|
||||
|
||||
InputEvent eventqueue[50]; // The Linux API will return multiple keypresses at a time. Queue them to not miss any.
|
||||
int queue_length = 0;
|
||||
int queue_progress = 0;
|
||||
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
int fd;
|
||||
int ret;
|
||||
uint8_t report[8];
|
||||
int epollfd;
|
||||
struct epoll_event ev;
|
||||
uint8_t modifiers = 0;
|
||||
std::map<int, char> keymap{
|
||||
{KEY_A, 'a'}, {KEY_B, 'b'}, {KEY_C, 'c'}, {KEY_D, 'd'}, {KEY_E, 'e'},
|
||||
{KEY_F, 'f'}, {KEY_G, 'g'}, {KEY_H, 'h'}, {KEY_I, 'i'}, {KEY_J, 'j'},
|
||||
{KEY_K, 'k'}, {KEY_L, 'l'}, {KEY_M, 'm'}, {KEY_N, 'n'}, {KEY_O, 'o'},
|
||||
{KEY_P, 'p'}, {KEY_Q, 'q'}, {KEY_R, 'r'}, {KEY_S, 's'}, {KEY_T, 't'},
|
||||
{KEY_U, 'u'}, {KEY_V, 'v'}, {KEY_W, 'w'}, {KEY_X, 'x'}, {KEY_Y, 'y'},
|
||||
{KEY_Z, 'z'}, {KEY_BACKSPACE, 0x08}, {KEY_SPACE, ' '}, {KEY_1, '1'}, {KEY_2, '2'},
|
||||
{KEY_3, '3'}, {KEY_4, '4'}, {KEY_5, '5'}, {KEY_6, '6'}, {KEY_7, '7'},
|
||||
{KEY_8, '8'}, {KEY_9, '9'}, {KEY_0, '0'}, {KEY_DOT, '.'}, {KEY_COMMA, ','},
|
||||
{KEY_MINUS, '-'}, {KEY_EQUAL, '='}, {KEY_LEFTBRACE, '['}, {KEY_RIGHTBRACE, ']'}, {KEY_BACKSLASH, '\\'},
|
||||
{KEY_SEMICOLON, ';'}, {KEY_APOSTROPHE, '\''}, {KEY_SLASH, '/'}, {KEY_TAB, 0x09}};
|
||||
std::map<char, char> uppers{{'a', 'A'}, {'b', 'B'}, {'c', 'C'}, {'d', 'D'}, {'e', 'E'}, {'f', 'F'}, {'g', 'G'}, {'h', 'H'},
|
||||
{'i', 'I'}, {'j', 'J'}, {'k', 'K'}, {'l', 'L'}, {'m', 'M'}, {'n', 'N'}, {'o', 'O'}, {'p', 'P'},
|
||||
{'q', 'Q'}, {'r', 'R'}, {'s', 'S'}, {'t', 'T'}, {'u', 'U'}, {'v', 'V'}, {'w', 'W'}, {'x', 'X'},
|
||||
{'y', 'Y'}, {'z', 'Z'}, {'1', '!'}, {'2', '@'}, {'3', '#'}, {'4', '$'}, {'5', '%'}, {'6', '^'},
|
||||
{'7', '&'}, {'8', '*'}, {'9', '('}, {'0', ')'}, {'.', '>'}, {',', '<'}, {'-', '_'}, {'=', '+'},
|
||||
{'[', '{'}, {']', '}'}, {'\\', '|'}, {';', ':'}, {'\'', '"'}, {'/', '?'}};
|
||||
};
|
||||
#endif
|
||||
14
src/input/LinuxInputImpl.cpp
Normal file
14
src/input/LinuxInputImpl.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "LinuxInputImpl.h"
|
||||
#include "InputBroker.h"
|
||||
|
||||
LinuxInputImpl *aLinuxInputImpl;
|
||||
|
||||
LinuxInputImpl::LinuxInputImpl() : LinuxInput("LinuxInput") {}
|
||||
|
||||
void LinuxInputImpl::init()
|
||||
{
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
#endif
|
||||
21
src/input/LinuxInputImpl.h
Normal file
21
src/input/LinuxInputImpl.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
#pragma once
|
||||
#include "LinuxInput.h"
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* @brief The idea behind this class to have static methods for the event handlers.
|
||||
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
|
||||
* Technically you can have as many rotary encoders hardver attached
|
||||
* to your device as you wish, but you always need to have separate event
|
||||
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
|
||||
*/
|
||||
|
||||
class LinuxInputImpl : public LinuxInput
|
||||
{
|
||||
public:
|
||||
LinuxInputImpl();
|
||||
void init();
|
||||
};
|
||||
extern LinuxInputImpl *aLinuxInputImpl;
|
||||
#endif
|
||||
@@ -2,6 +2,11 @@
|
||||
#include "InputBroker.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
TouchScreenImpl1 *touchScreenImpl1;
|
||||
|
||||
@@ -12,7 +17,14 @@ TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTo
|
||||
|
||||
void TouchScreenImpl1::init()
|
||||
{
|
||||
#if !HAS_TOUCHSCREEN
|
||||
#if ARCH_RASPBERRY_PI
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
TouchScreenBase::init(true);
|
||||
inputBroker->registerSource(this);
|
||||
} else {
|
||||
TouchScreenBase::init(false);
|
||||
}
|
||||
#elif !HAS_TOUCHSCREEN
|
||||
TouchScreenBase::init(false);
|
||||
return;
|
||||
#else
|
||||
@@ -63,7 +75,11 @@ void TouchScreenImpl1::onEvent(const TouchEvent &event)
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_TAP: {
|
||||
powerFSM.trigger(EVENT_INPUT);
|
||||
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
|
||||
externalNotificationModule->stopNow();
|
||||
} else {
|
||||
powerFSM.trigger(EVENT_INPUT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
79
src/main.cpp
79
src/main.cpp
@@ -32,9 +32,6 @@
|
||||
#include <utility>
|
||||
// #include <driver/rtc_io.h>
|
||||
|
||||
#include "mesh/eth/ethClient.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "mesh/http/WebServer.h"
|
||||
#include "nimble/NimbleBluetooth.h"
|
||||
@@ -48,10 +45,12 @@ NRF52Bluetooth *nrf52Bluetooth;
|
||||
|
||||
#if HAS_WIFI
|
||||
#include "mesh/api/WiFiServerAPI.h"
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
|
||||
#if HAS_ETHERNET
|
||||
#include "mesh/api/ethServerAPI.h"
|
||||
#include "mesh/eth/ethClient.h"
|
||||
#endif
|
||||
#include "mqtt/MQTT.h"
|
||||
|
||||
@@ -68,14 +67,14 @@ NRF52Bluetooth *nrf52Bluetooth;
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
#include "platform/portduino/PiHal.h"
|
||||
#include "linux/LinuxHardwareI2C.h"
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#if HAS_BUTTON
|
||||
#if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
|
||||
#include "ButtonThread.h"
|
||||
#endif
|
||||
#include "PowerFSMThread.h"
|
||||
@@ -85,6 +84,11 @@ NRF52Bluetooth *nrf52Bluetooth;
|
||||
#include "AmbientLightingThread.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_I2S
|
||||
#include "AudioThread.h"
|
||||
AudioThread *audioThread;
|
||||
#endif
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
// We always create a screen object, but we only init it if we find the hardware
|
||||
@@ -123,6 +127,7 @@ ATECCX08A atecc;
|
||||
#ifdef T_WATCH_S3
|
||||
Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
|
||||
bool isVibrating = false;
|
||||
|
||||
bool eink_found = true;
|
||||
@@ -206,13 +211,13 @@ static int32_t ledBlinker()
|
||||
|
||||
uint32_t timeLastPowered = 0;
|
||||
|
||||
#if HAS_BUTTON
|
||||
#if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
|
||||
bool ButtonThread::shutdown_on_long_stop = false;
|
||||
#endif
|
||||
|
||||
static Periodic *ledPeriodic;
|
||||
static OSThread *powerFSMthread;
|
||||
#if HAS_BUTTON
|
||||
#if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
|
||||
static OSThread *buttonThread;
|
||||
uint32_t ButtonThread::longPressTime = 0;
|
||||
#endif
|
||||
@@ -433,6 +438,10 @@ void setup()
|
||||
auto i2cCount = i2cScanner->countDevices();
|
||||
if (i2cCount == 0) {
|
||||
LOG_INFO("No I2C devices found\n");
|
||||
Wire.end();
|
||||
#ifdef I2C_SDA1
|
||||
Wire1.end();
|
||||
#endif
|
||||
} else {
|
||||
LOG_INFO("%i I2C devices found\n", i2cCount);
|
||||
}
|
||||
@@ -577,13 +586,16 @@ void setup()
|
||||
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
||||
nodeDB.init();
|
||||
|
||||
// If we're taking on the repeater role, use flood router
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
|
||||
// If we're taking on the repeater role, use flood router and turn off 3V3_S rail because peripherals are not needed
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
router = new FloodingRouter();
|
||||
else
|
||||
#ifdef PIN_3V3_EN
|
||||
digitalWrite(PIN_3V3_EN, LOW);
|
||||
#endif
|
||||
} else
|
||||
router = new ReliableRouter();
|
||||
|
||||
#if HAS_BUTTON
|
||||
#if HAS_BUTTON || defined(ARCH_RASPBERRY_PI)
|
||||
// Buttons. Moved here cause we need NodeDB to be initialized
|
||||
buttonThread = new ButtonThread();
|
||||
#endif
|
||||
@@ -628,24 +640,24 @@ void setup()
|
||||
initSPI();
|
||||
#ifdef ARCH_RP2040
|
||||
#ifdef HW_SPI1_DEVICE
|
||||
SPI1.setSCK(RF95_SCK);
|
||||
SPI1.setTX(RF95_MOSI);
|
||||
SPI1.setRX(RF95_MISO);
|
||||
pinMode(RF95_NSS, OUTPUT);
|
||||
digitalWrite(RF95_NSS, HIGH);
|
||||
SPI1.setSCK(LORA_SCK);
|
||||
SPI1.setTX(LORA_MOSI);
|
||||
SPI1.setRX(LORA_MISO);
|
||||
pinMode(LORA_CS, OUTPUT);
|
||||
digitalWrite(LORA_CS, HIGH);
|
||||
SPI1.begin(false);
|
||||
#else // HW_SPI1_DEVICE
|
||||
SPI.setSCK(RF95_SCK);
|
||||
SPI.setTX(RF95_MOSI);
|
||||
SPI.setRX(RF95_MISO);
|
||||
SPI.setSCK(LORA_SCK);
|
||||
SPI.setTX(LORA_MOSI);
|
||||
SPI.setRX(LORA_MISO);
|
||||
SPI.begin(false);
|
||||
#endif // HW_SPI1_DEVICE
|
||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||
SPI.begin();
|
||||
#else
|
||||
// ESP32
|
||||
SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
LOG_WARN("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)\n", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
SPI.setFrequency(4000000);
|
||||
#endif
|
||||
|
||||
@@ -654,7 +666,10 @@ void setup()
|
||||
|
||||
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
|
||||
|
||||
gps = GPS::createGps();
|
||||
// If we're taking on the repeater role, ignore GPS
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
gps = GPS::createGps();
|
||||
}
|
||||
if (gps) {
|
||||
gpsStatus->observe(&gps->newStatus);
|
||||
} else {
|
||||
@@ -662,6 +677,11 @@ void setup()
|
||||
}
|
||||
nodeStatus->observe(&nodeDB.newStatus);
|
||||
|
||||
#ifdef HAS_I2S
|
||||
LOG_DEBUG("Starting audio thread\n");
|
||||
audioThread = new AudioThread();
|
||||
#endif
|
||||
|
||||
service.init();
|
||||
|
||||
// Now that the mesh service is created, create any modules
|
||||
@@ -677,6 +697,10 @@ void setup()
|
||||
// the current region name)
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
screen->setup();
|
||||
#elif ARCH_RASPBERRY_PI
|
||||
if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) {
|
||||
screen->setup();
|
||||
}
|
||||
#else
|
||||
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
|
||||
screen->setup();
|
||||
@@ -693,7 +717,7 @@ void setup()
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
if (settingsMap[use_sx1262]) {
|
||||
if (!rIf) {
|
||||
PiHal *RadioLibHAL = new PiHal(1);
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
@@ -706,7 +730,7 @@ void setup()
|
||||
}
|
||||
} else if (settingsMap[use_rf95]) {
|
||||
if (!rIf) {
|
||||
PiHal *RadioLibHAL = new PiHal(1);
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
@@ -755,7 +779,7 @@ void setup()
|
||||
|
||||
#if defined(RF95_IRQ)
|
||||
if (!rIf) {
|
||||
rIf = new RF95Interface(RadioLibHAL, RF95_NSS, RF95_IRQ, RF95_RESET, RF95_DIO1);
|
||||
rIf = new RF95Interface(RadioLibHAL, LORA_CS, RF95_IRQ, RF95_RESET, RF95_DIO1);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("Failed to find RF95 radio\n");
|
||||
delete rIf;
|
||||
@@ -835,11 +859,15 @@ void setup()
|
||||
|
||||
#ifndef ARCH_PORTDUINO
|
||||
// Initialize Wifi
|
||||
#if HAS_WIFI
|
||||
initWifi();
|
||||
#endif
|
||||
|
||||
#if HAS_ETHERNET
|
||||
// Initialize Ethernet
|
||||
initEthernet();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Start web server thread.
|
||||
@@ -867,7 +895,6 @@ void setup()
|
||||
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
|
||||
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
|
||||
powerFSMthread = new PowerFSMThread();
|
||||
|
||||
setCPUFast(false); // 80MHz is fine for our slow peripherals
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,12 @@ extern ATECCX08A atecc;
|
||||
#include <Adafruit_DRV2605.h>
|
||||
extern Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_I2S
|
||||
#include "AudioThread.h"
|
||||
extern AudioThread *audioThread;
|
||||
#endif
|
||||
|
||||
extern bool isVibrating;
|
||||
|
||||
extern int TCPPort; // set by Portduino
|
||||
|
||||
@@ -184,7 +184,7 @@ void Channels::onConfigChanged()
|
||||
{
|
||||
// Make sure the phone hasn't mucked anything up
|
||||
for (int i = 0; i < channelFile.channels_count; i++) {
|
||||
meshtastic_Channel &ch = fixupChannel(i);
|
||||
const meshtastic_Channel &ch = fixupChannel(i);
|
||||
|
||||
if (ch.role == meshtastic_Channel_Role_PRIMARY)
|
||||
primaryIndex = i;
|
||||
|
||||
@@ -73,58 +73,3 @@ template <class T> class MemoryDynamic : public Allocator<T>
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A pool based allocator
|
||||
*
|
||||
*/
|
||||
template <class T> class MemoryPool : public Allocator<T>
|
||||
{
|
||||
PointerQueue<T> dead;
|
||||
|
||||
T *buf; // our large raw block of memory
|
||||
|
||||
size_t maxElements;
|
||||
|
||||
public:
|
||||
explicit MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
|
||||
{
|
||||
buf = new T[maxElements];
|
||||
|
||||
// prefill dead
|
||||
for (size_t i = 0; i < maxElements; i++)
|
||||
release(&buf[i]);
|
||||
}
|
||||
|
||||
~MemoryPool() { delete[] buf; }
|
||||
|
||||
/// Return a buffer for use by others
|
||||
void release(T *p)
|
||||
{
|
||||
assert(p >= buf &&
|
||||
(size_t)(p - buf) <
|
||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
assert(dead.enqueue(p, 0));
|
||||
}
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
|
||||
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
|
||||
{
|
||||
assert(p >= buf &&
|
||||
(size_t)(p - buf) <
|
||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
assert(dead.enqueueFromISR(p, higherPriWoken));
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you
|
||||
/// probably don't want this version).
|
||||
virtual T *alloc(TickType_t maxWait)
|
||||
{
|
||||
T *p = dead.dequeuePtr(maxWait);
|
||||
assert(p);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -140,6 +140,22 @@ void MeshService::reloadOwner(bool shouldSave)
|
||||
}
|
||||
}
|
||||
|
||||
// search the queue for a request id and return the matching nodenum
|
||||
NodeNum MeshService::getNodenumFromRequestId(uint32_t request_id)
|
||||
{
|
||||
NodeNum nodenum = 0;
|
||||
for (int i = 0; i < toPhoneQueue.numUsed(); i++) {
|
||||
meshtastic_MeshPacket *p = toPhoneQueue.dequeuePtr(0);
|
||||
if (p->id == request_id) {
|
||||
nodenum = p->to;
|
||||
// make sure to continue this to make one full loop
|
||||
}
|
||||
// put it right back on the queue
|
||||
toPhoneQueue.enqueue(p, 0);
|
||||
}
|
||||
return nodenum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
|
||||
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep a
|
||||
@@ -320,7 +336,9 @@ meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode()
|
||||
|
||||
position.time = getValidTime(RTCQualityFromNet);
|
||||
|
||||
updateBatteryLevel(powerStatus->getBatteryChargePercent());
|
||||
if (powerStatus->getHasBattery() == 1) {
|
||||
updateBatteryLevel(powerStatus->getBatteryChargePercent());
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,9 @@ class MeshService
|
||||
/// Return the next MqttClientProxyMessage packet destined to the phone.
|
||||
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
|
||||
|
||||
// search the queue for a request id and return the matching nodenum
|
||||
NodeNum getNodenumFromRequestId(uint32_t request_id);
|
||||
|
||||
// Release QueueStatus packet to pool
|
||||
void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); }
|
||||
|
||||
|
||||
@@ -21,12 +21,16 @@
|
||||
#include <pb_encode.h>
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#include <Preferences.h>
|
||||
#include <nvs_flash.h>
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_NRF52
|
||||
#include <bluefruit.h>
|
||||
#include <utility/bonding.h>
|
||||
@@ -191,6 +195,12 @@ void NodeDB::installDefaultConfig()
|
||||
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
bool hasScreen = true;
|
||||
#elif ARCH_RASPBERRY_PI
|
||||
bool hasScreen = false;
|
||||
if (settingsMap[displayPanel])
|
||||
hasScreen = true;
|
||||
else
|
||||
hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||
#else
|
||||
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||
#endif
|
||||
@@ -200,7 +210,7 @@ void NodeDB::installDefaultConfig()
|
||||
config.position.position_flags =
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_DOP);
|
||||
meshtastic_Config_PositionConfig_PositionFlags_DOP | meshtastic_Config_PositionConfig_PositionFlags_SATINVIEW);
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
config.display.screen_on_secs = 30;
|
||||
@@ -245,9 +255,18 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.output_ms = 1000;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
#endif
|
||||
#ifdef T_WATCH_S3
|
||||
// Don't worry about the other settings, we'll use the DRV2056 behavior for notifications
|
||||
#ifdef HAS_I2S
|
||||
// Don't worry about the other settings for T-Watch, we'll also use the DRV2056 behavior for notifications
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.use_i2s_as_buzzer = true;
|
||||
moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
#endif
|
||||
#ifdef NANO_G2_ULTRA
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 100;
|
||||
moduleConfig.external_notification.active = true;
|
||||
#endif
|
||||
moduleConfig.has_canned_message = true;
|
||||
|
||||
@@ -287,6 +306,9 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
|
||||
moduleConfig.telemetry.environment_measurement_enabled = true;
|
||||
moduleConfig.telemetry.environment_update_interval = 300;
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND) {
|
||||
config.position.position_broadcast_smart_enabled = false;
|
||||
config.position.position_broadcast_secs = 300; // Every 5 minutes
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_TAK) {
|
||||
config.device.node_info_broadcast_secs = ONE_DAY;
|
||||
config.position.position_broadcast_smart_enabled = false;
|
||||
@@ -296,6 +318,15 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_SPEED |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_HEADING | meshtastic_Config_PositionConfig_PositionFlags_DOP);
|
||||
moduleConfig.telemetry.device_update_interval = ONE_DAY;
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
|
||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
|
||||
config.device.node_info_broadcast_secs = UINT32_MAX;
|
||||
config.position.position_broadcast_smart_enabled = false;
|
||||
config.position.position_broadcast_secs = UINT32_MAX;
|
||||
moduleConfig.neighbor_info.update_interval = UINT32_MAX;
|
||||
moduleConfig.telemetry.device_update_interval = UINT32_MAX;
|
||||
moduleConfig.telemetry.environment_update_interval = UINT32_MAX;
|
||||
moduleConfig.telemetry.air_quality_interval = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,7 +401,6 @@ void NodeDB::installDefaultDeviceState()
|
||||
pickNewNodeNum(); // based on macaddr now
|
||||
snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]);
|
||||
snprintf(owner.short_name, sizeof(owner.short_name), "%02x%02x", ourMacAddr[4], ourMacAddr[5]);
|
||||
|
||||
snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); // Default node ID now based on nodenum
|
||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||
}
|
||||
@@ -395,6 +425,8 @@ void NodeDB::init()
|
||||
|
||||
// Set our board type so we can share it with others
|
||||
owner.hw_model = HW_VENDOR;
|
||||
// Ensure user (nodeinfo) role is set to whatever we're configured to
|
||||
owner.role = config.device.role;
|
||||
|
||||
// Include our owner in the node db under our nodenum
|
||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "RadioLibRF95.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#define RF95_CHIP_VERSION 0x12
|
||||
#define RF95_ALT_VERSION 0x11 // Supposedly some versions of the chip have id 0x11
|
||||
|
||||
// From datasheet but radiolib doesn't know anything about this
|
||||
#define SX127X_REG_TCXO 0x4B
|
||||
|
||||
@@ -13,9 +10,8 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
|
||||
uint8_t gain)
|
||||
{
|
||||
// execute common part
|
||||
int16_t state = SX127x::begin(RF95_CHIP_VERSION, syncWord, preambleLength);
|
||||
if (state != RADIOLIB_ERR_NONE)
|
||||
state = SX127x::begin(RF95_ALT_VERSION, syncWord, preambleLength);
|
||||
uint8_t rf95versions[2] = {0x12, 0x11};
|
||||
int16_t state = SX127x::begin(rf95versions, sizeof(rf95versions), syncWord, preambleLength);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// current limit was removed from module' ctor
|
||||
@@ -80,4 +76,4 @@ bool RadioLibRF95::isReceiving()
|
||||
uint8_t RadioLibRF95::readReg(uint8_t addr)
|
||||
{
|
||||
return mod->SPIreadRegister(addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +299,12 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
|
||||
config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING)
|
||||
return false;
|
||||
|
||||
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY &&
|
||||
!nodeDB.getMeshNode(p->from)->has_user) {
|
||||
LOG_DEBUG("Node 0x%x not in NodeDB. Rebroadcast mode KNOWN_ONLY will ignore packet\n", p->from);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)
|
||||
return true; // If packet was already decoded just return
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ SX126xInterface<T>::SX126xInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs
|
||||
template <typename T> bool SX126xInterface<T>::init()
|
||||
{
|
||||
#ifdef SX126X_POWER_EN
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
#endif
|
||||
|
||||
// FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE
|
||||
@@ -250,7 +250,7 @@ template <typename T> void SX126xInterface<T>::startReceive()
|
||||
// We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly.
|
||||
// Furthermore, we need the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving
|
||||
int err = lora.startReceiveDutyCycleAuto(preambleLength, 8,
|
||||
RADIOLIB_SX126X_IRQ_RX_DEFAULT | RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED |
|
||||
RADIOLIB_SX126X_IRQ_RX_DEFAULT | RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED |
|
||||
RADIOLIB_SX126X_IRQ_HEADER_VALID);
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
|
||||
@@ -284,7 +284,7 @@ template <typename T> bool SX126xInterface<T>::isActivelyReceiving()
|
||||
// received and handled the interrupt for reading the packet/handling errors.
|
||||
|
||||
uint16_t irq = lora.getIrqStatus();
|
||||
bool detected = (irq & (RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED));
|
||||
bool detected = (irq & (RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED));
|
||||
// Handle false detections
|
||||
if (detected) {
|
||||
uint32_t now = millis();
|
||||
|
||||
@@ -22,8 +22,8 @@ SX128xInterface<T>::SX128xInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs
|
||||
template <typename T> bool SX128xInterface<T>::init()
|
||||
{
|
||||
#ifdef SX128X_POWER_EN
|
||||
digitalWrite(SX128X_POWER_EN, HIGH);
|
||||
pinMode(SX128X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX128X_POWER_EN, HIGH);
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
@@ -32,12 +32,12 @@ template <typename T> bool SX128xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode
|
||||
digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
|
||||
pinMode(SX128X_RXEN, OUTPUT);
|
||||
digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
|
||||
#endif
|
||||
#if defined(SX128X_TXEN) && (SX128X_TXEN != RADIOLIB_NC)
|
||||
digitalWrite(SX128X_TXEN, LOW);
|
||||
pinMode(SX128X_TXEN, OUTPUT);
|
||||
digitalWrite(SX128X_TXEN, LOW);
|
||||
#endif
|
||||
|
||||
RadioLibInterface::init();
|
||||
|
||||
@@ -27,6 +27,8 @@ template <class T> class TypedQueue
|
||||
|
||||
bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; }
|
||||
|
||||
int numUsed() { return uxQueueMessagesWaiting(h); }
|
||||
|
||||
/** euqueue a packet. Also, maxWait used to default to portMAX_DELAY, but we now want to callers to THINK about what blocking
|
||||
* they want */
|
||||
bool enqueue(T x, TickType_t maxWait)
|
||||
@@ -80,6 +82,8 @@ template <class T> class TypedQueue
|
||||
|
||||
bool isEmpty() { return q.empty(); }
|
||||
|
||||
int numUsed() { return q.size(); }
|
||||
|
||||
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
if (reader) {
|
||||
|
||||
@@ -15,6 +15,10 @@ void initApiServer(int port)
|
||||
apiPort->init();
|
||||
}
|
||||
}
|
||||
void deInitApiServer()
|
||||
{
|
||||
delete apiPort;
|
||||
}
|
||||
|
||||
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client)
|
||||
{
|
||||
@@ -22,4 +26,4 @@ WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client)
|
||||
}
|
||||
|
||||
WiFiServerPort::WiFiServerPort(int port) : APIServerPort(port) {}
|
||||
#endif
|
||||
#endif
|
||||
@@ -23,3 +23,4 @@ class WiFiServerPort : public APIServerPort<WiFiServerAPI, WiFiServer>
|
||||
};
|
||||
|
||||
void initApiServer(int port = 4403);
|
||||
void deInitApiServer();
|
||||
@@ -43,7 +43,18 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
|
||||
Used for nodes dedicated for connection to an ATAK EUD.
|
||||
Turns off many of the routine broadcasts to favor CoT packet stream
|
||||
from the Meshtastic ATAK plugin -> IMeshService -> Node */
|
||||
meshtastic_Config_DeviceConfig_Role_TAK = 7
|
||||
meshtastic_Config_DeviceConfig_Role_TAK = 7,
|
||||
/* Client Hidden device role
|
||||
Used for nodes that "only speak when spoken to"
|
||||
Turns all of the routine broadcasts but allows for ad-hoc communication
|
||||
Still rebroadcasts, but with local only rebroadcast mode (known meshes only)
|
||||
Can be used for clandestine operation or to dramatically reduce airtime / power consumption */
|
||||
meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN = 8,
|
||||
/* Lost and Found device role
|
||||
Used to automatically send a text message to the mesh
|
||||
with the current position of the device on a frequent interval:
|
||||
"I'm lost! Position: lat / long" */
|
||||
meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND = 9
|
||||
} meshtastic_Config_DeviceConfig_Role;
|
||||
|
||||
/* Defines the device's behavior for how messages are rebroadcast */
|
||||
@@ -56,7 +67,10 @@ typedef enum _meshtastic_Config_DeviceConfig_RebroadcastMode {
|
||||
meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING = 1,
|
||||
/* Ignores observed messages from foreign meshes that are open or those which it cannot decrypt.
|
||||
Only rebroadcasts message on the nodes local primary / secondary channels. */
|
||||
meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY = 2
|
||||
meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY = 2,
|
||||
/* Ignores observed messages from foreign meshes like LOCAL_ONLY,
|
||||
but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB) */
|
||||
meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY = 3
|
||||
} meshtastic_Config_DeviceConfig_RebroadcastMode;
|
||||
|
||||
/* Bit field of boolean configuration options, indicating which optional
|
||||
@@ -479,12 +493,12 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_TAK
|
||||
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_TAK+1))
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND
|
||||
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND+1))
|
||||
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY+1))
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY+1))
|
||||
|
||||
#define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET
|
||||
#define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED
|
||||
|
||||
@@ -313,8 +313,8 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_ChannelFile_size 638
|
||||
#define meshtastic_DeviceState_size 16854
|
||||
#define meshtastic_NodeInfoLite_size 151
|
||||
#define meshtastic_DeviceState_size 17056
|
||||
#define meshtastic_NodeInfoLite_size 153
|
||||
#define meshtastic_NodeRemoteHardwarePin_size 29
|
||||
#define meshtastic_OEMStore_size 3231
|
||||
#define meshtastic_PositionLite_size 28
|
||||
|
||||
@@ -67,6 +67,10 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_STATION_G1 = 25,
|
||||
/* RAK11310 (RP2040 + SX1262) */
|
||||
meshtastic_HardwareModel_RAK11310 = 26,
|
||||
/* Makerfabs SenseLoRA Receiver (RP2040 + RFM96) */
|
||||
meshtastic_HardwareModel_SENSELORA_RP2040 = 27,
|
||||
/* Makerfabs SenseLoRA Industrial Monitor (ESP32-S3 + RFM96) */
|
||||
meshtastic_HardwareModel_SENSELORA_S3 = 28,
|
||||
/* ---------------------------------------------------------------------------
|
||||
Less common/prototype boards listed here (needs one more byte over the air)
|
||||
--------------------------------------------------------------------------- */
|
||||
@@ -402,6 +406,8 @@ typedef struct _meshtastic_User {
|
||||
If this user is a licensed operator, set this flag.
|
||||
Also, "long_name" should be their licence number. */
|
||||
bool is_licensed;
|
||||
/* Indicates that the user's role in the mesh */
|
||||
meshtastic_Config_DeviceConfig_Role role;
|
||||
} meshtastic_User;
|
||||
|
||||
/* A message used in our Dynamic Source Routing protocol (RFC 4728 based) */
|
||||
@@ -826,6 +832,7 @@ extern "C" {
|
||||
#define meshtastic_Position_altitude_source_ENUMTYPE meshtastic_Position_AltSource
|
||||
|
||||
#define meshtastic_User_hw_model_ENUMTYPE meshtastic_HardwareModel
|
||||
#define meshtastic_User_role_ENUMTYPE meshtastic_Config_DeviceConfig_Role
|
||||
|
||||
|
||||
#define meshtastic_Routing_variant_error_reason_ENUMTYPE meshtastic_Routing_Error
|
||||
@@ -854,7 +861,7 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0}
|
||||
#define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
|
||||
#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
|
||||
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
|
||||
@@ -872,7 +879,7 @@ extern "C" {
|
||||
#define meshtastic_Neighbor_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
|
||||
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0}
|
||||
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
|
||||
#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
|
||||
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
|
||||
@@ -919,6 +926,7 @@ extern "C" {
|
||||
#define meshtastic_User_macaddr_tag 4
|
||||
#define meshtastic_User_hw_model_tag 5
|
||||
#define meshtastic_User_is_licensed_tag 6
|
||||
#define meshtastic_User_role_tag 7
|
||||
#define meshtastic_RouteDiscovery_route_tag 1
|
||||
#define meshtastic_Routing_route_request_tag 1
|
||||
#define meshtastic_Routing_route_reply_tag 2
|
||||
@@ -1047,7 +1055,8 @@ X(a, STATIC, SINGULAR, STRING, long_name, 2) \
|
||||
X(a, STATIC, SINGULAR, STRING, short_name, 3) \
|
||||
X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) \
|
||||
X(a, STATIC, SINGULAR, UENUM, hw_model, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_licensed, 6)
|
||||
X(a, STATIC, SINGULAR, BOOL, is_licensed, 6) \
|
||||
X(a, STATIC, SINGULAR, UENUM, role, 7)
|
||||
#define meshtastic_User_CALLBACK NULL
|
||||
#define meshtastic_User_DEFAULT NULL
|
||||
|
||||
@@ -1280,13 +1289,13 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
#define meshtastic_MyNodeInfo_size 18
|
||||
#define meshtastic_NeighborInfo_size 258
|
||||
#define meshtastic_Neighbor_size 22
|
||||
#define meshtastic_NodeInfo_size 261
|
||||
#define meshtastic_NodeInfo_size 263
|
||||
#define meshtastic_Position_size 137
|
||||
#define meshtastic_QueueStatus_size 23
|
||||
#define meshtastic_RouteDiscovery_size 40
|
||||
#define meshtastic_Routing_size 42
|
||||
#define meshtastic_ToRadio_size 504
|
||||
#define meshtastic_User_size 77
|
||||
#define meshtastic_User_size 79
|
||||
#define meshtastic_Waypoint_size 165
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "main.h"
|
||||
#include "mesh/http/ContentHelper.h"
|
||||
#include "mesh/http/WebServer.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#include "mqtt/JSON.h"
|
||||
#include "power.h"
|
||||
#include "sleep.h"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer);
|
||||
|
||||
// Declare some handler functions for the various URLs on the server
|
||||
@@ -34,4 +33,4 @@ class HttpAPI : public PhoneAPI
|
||||
protected:
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() override { return true; } // FIXME, be smarter about this
|
||||
};
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "mesh/http/ContentHelper.h"
|
||||
//#include <Arduino.h>
|
||||
//#include "main.h"
|
||||
// #include <Arduino.h>
|
||||
// #include "main.h"
|
||||
|
||||
void replaceAll(std::string &str, const std::string &from, const std::string &to)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "NodeDB.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#include "sleep.h"
|
||||
#include <HTTPBodyParser.hpp>
|
||||
#include <HTTPMultipartBodyParser.hpp>
|
||||
@@ -210,4 +210,4 @@ void initWebServer()
|
||||
} else {
|
||||
LOG_ERROR("Web Servers Failed! ;-( \n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,20 @@
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "concurrency/Periodic.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "mesh/api/WiFiServerAPI.h"
|
||||
#include "mesh/http/WebServer.h"
|
||||
#include "mqtt/MQTT.h"
|
||||
#include "target_specific.h"
|
||||
#include <ESPmDNS.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
#ifdef ARCH_ESP32
|
||||
#include "mesh/http/WebServer.h"
|
||||
#include <ESPmDNS.h>
|
||||
#include <esp_wifi.h>
|
||||
static void WiFiEvent(WiFiEvent_t event);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_NTP
|
||||
#include <NTPClient.h>
|
||||
@@ -19,8 +22,6 @@
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
static void WiFiEvent(WiFiEvent_t event);
|
||||
|
||||
// NTP
|
||||
WiFiUDP ntpUDP;
|
||||
|
||||
@@ -44,6 +45,65 @@ Syslog syslog(syslogClient);
|
||||
|
||||
Periodic *wifiReconnect;
|
||||
|
||||
static void onNetworkConnected()
|
||||
{
|
||||
if (!APStartupComplete) {
|
||||
// Start web server
|
||||
LOG_INFO("Starting network services\n");
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// start mdns
|
||||
if (!MDNS.begin("Meshtastic")) {
|
||||
LOG_ERROR("Error setting up MDNS responder!\n");
|
||||
} else {
|
||||
LOG_INFO("mDNS responder started\n");
|
||||
LOG_INFO("mDNS Host: Meshtastic.local\n");
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("https", "tcp", 443);
|
||||
}
|
||||
#else // ESP32 handles this in WiFiEvent
|
||||
LOG_INFO("Obtained IP address: %s\n", WiFi.localIP().toString().c_str());
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_NTP
|
||||
LOG_INFO("Starting NTP time client\n");
|
||||
timeClient.begin();
|
||||
timeClient.setUpdateInterval(60 * 60); // Update once an hour
|
||||
#endif
|
||||
|
||||
if (config.network.rsyslog_server[0]) {
|
||||
LOG_INFO("Starting Syslog client\n");
|
||||
// Defaults
|
||||
int serverPort = 514;
|
||||
const char *serverAddr = config.network.rsyslog_server;
|
||||
String server = String(serverAddr);
|
||||
int delimIndex = server.indexOf(':');
|
||||
if (delimIndex > 0) {
|
||||
String port = server.substring(delimIndex + 1, server.length());
|
||||
server[delimIndex] = 0;
|
||||
serverPort = port.toInt();
|
||||
serverAddr = server.c_str();
|
||||
}
|
||||
syslog.server(serverAddr, serverPort);
|
||||
syslog.deviceHostname(getDeviceName());
|
||||
syslog.appName("Meshtastic");
|
||||
syslog.defaultPriority(LOGLEVEL_USER);
|
||||
syslog.enable();
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
initWebServer();
|
||||
#endif
|
||||
initApiServer();
|
||||
|
||||
APStartupComplete = true;
|
||||
}
|
||||
|
||||
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
||||
if (mqtt)
|
||||
mqtt->reconnect();
|
||||
}
|
||||
|
||||
static int32_t reconnectWiFi()
|
||||
{
|
||||
const char *wifiName = config.network.wifi_ssid;
|
||||
@@ -57,7 +117,11 @@ static int32_t reconnectWiFi()
|
||||
needReconnect = false;
|
||||
|
||||
// Make sure we clear old connection credentials
|
||||
#ifdef ARCH_ESP32
|
||||
WiFi.disconnect(false, true);
|
||||
#else
|
||||
WiFi.disconnect(false);
|
||||
#endif
|
||||
LOG_INFO("Reconnecting to WiFi access point %s\n", wifiName);
|
||||
|
||||
delay(5000);
|
||||
@@ -87,8 +151,16 @@ static int32_t reconnectWiFi()
|
||||
#endif
|
||||
|
||||
if (config.network.wifi_enabled && !WiFi.isConnected()) {
|
||||
#ifdef ARCH_RP2040 // (ESP32 handles this in WiFiEvent)
|
||||
/* If APStartupComplete, but we're not connected, try again.
|
||||
Shouldn't try again before APStartupComplete. */
|
||||
needReconnect = APStartupComplete;
|
||||
#endif
|
||||
return 1000; // check once per second
|
||||
} else {
|
||||
#ifdef ARCH_RP2040
|
||||
onNetworkConnected(); // will only do anything once
|
||||
#endif
|
||||
return 300000; // every 5 minutes
|
||||
}
|
||||
}
|
||||
@@ -109,66 +181,17 @@ void deinitWifi()
|
||||
LOG_INFO("WiFi deinit\n");
|
||||
|
||||
if (isWifiAvailable()) {
|
||||
#ifdef ARCH_ESP32
|
||||
WiFi.disconnect(true, false);
|
||||
#else
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
#endif
|
||||
WiFi.mode(WIFI_OFF);
|
||||
LOG_INFO("WiFi Turned Off\n");
|
||||
// WiFi.printDiag(Serial);
|
||||
}
|
||||
}
|
||||
|
||||
static void onNetworkConnected()
|
||||
{
|
||||
if (!APStartupComplete) {
|
||||
// Start web server
|
||||
LOG_INFO("Starting network services\n");
|
||||
|
||||
// start mdns
|
||||
if (!MDNS.begin("Meshtastic")) {
|
||||
LOG_ERROR("Error setting up MDNS responder!\n");
|
||||
} else {
|
||||
LOG_INFO("mDNS responder started\n");
|
||||
LOG_INFO("mDNS Host: Meshtastic.local\n");
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("https", "tcp", 443);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_NTP
|
||||
LOG_INFO("Starting NTP time client\n");
|
||||
timeClient.begin();
|
||||
timeClient.setUpdateInterval(60 * 60); // Update once an hour
|
||||
#endif
|
||||
|
||||
if (config.network.rsyslog_server[0]) {
|
||||
LOG_INFO("Starting Syslog client\n");
|
||||
// Defaults
|
||||
int serverPort = 514;
|
||||
const char *serverAddr = config.network.rsyslog_server;
|
||||
String server = String(serverAddr);
|
||||
int delimIndex = server.indexOf(':');
|
||||
if (delimIndex > 0) {
|
||||
String port = server.substring(delimIndex + 1, server.length());
|
||||
server[delimIndex] = 0;
|
||||
serverPort = port.toInt();
|
||||
serverAddr = server.c_str();
|
||||
}
|
||||
syslog.server(serverAddr, serverPort);
|
||||
syslog.deviceHostname(getDeviceName());
|
||||
syslog.appName("Meshtastic");
|
||||
syslog.defaultPriority(LOGLEVEL_USER);
|
||||
syslog.enable();
|
||||
}
|
||||
|
||||
initWebServer();
|
||||
initApiServer();
|
||||
|
||||
APStartupComplete = true;
|
||||
}
|
||||
|
||||
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
||||
if (mqtt)
|
||||
mqtt->reconnect();
|
||||
}
|
||||
|
||||
// Startup WiFi
|
||||
bool initWifi()
|
||||
{
|
||||
@@ -177,10 +200,10 @@ bool initWifi()
|
||||
const char *wifiName = config.network.wifi_ssid;
|
||||
const char *wifiPsw = config.network.wifi_psk;
|
||||
|
||||
createSSLCert();
|
||||
|
||||
#ifndef ARCH_RP2040
|
||||
createSSLCert(); // For WebServer
|
||||
esp_wifi_set_storage(WIFI_STORAGE_RAM); // Disable flash storage for WiFi credentials
|
||||
|
||||
#endif
|
||||
if (!*wifiPsw) // Treat empty password as no password
|
||||
wifiPsw = NULL;
|
||||
|
||||
@@ -189,17 +212,17 @@ bool initWifi()
|
||||
getMacAddr(dmac);
|
||||
snprintf(ourHost, sizeof(ourHost), "Meshtastic-%02x%02x", dmac[4], dmac[5]);
|
||||
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setHostname(ourHost);
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.setSleep(false);
|
||||
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC &&
|
||||
config.network.ipv4_config.ip != 0) {
|
||||
WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet,
|
||||
config.network.ipv4_config.dns,
|
||||
config.network.ipv4_config.dns); // Wifi wants two DNS servers... set both to the same value
|
||||
config.network.ipv4_config.dns);
|
||||
}
|
||||
#ifndef ARCH_RP2040
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.setSleep(false);
|
||||
|
||||
// This is needed to improve performance.
|
||||
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
|
||||
@@ -218,7 +241,7 @@ bool initWifi()
|
||||
wifiDisconnectReason = info.wifi_sta_disconnected.reason;
|
||||
},
|
||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
||||
|
||||
#endif
|
||||
LOG_DEBUG("JOINING WIFI soon: ssid=%s\n", wifiName);
|
||||
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
|
||||
}
|
||||
@@ -229,6 +252,7 @@ bool initWifi()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Called by the Espressif SDK to
|
||||
static void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
@@ -262,11 +286,11 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
LOG_INFO("Authentication mode of access point has changed\n");
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
LOG_INFO("Obtained IP address: ", WiFi.localIPv6());
|
||||
LOG_INFO("Obtained IP address: %s\n", WiFi.localIP().toString().c_str());
|
||||
onNetworkConnected();
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
LOG_INFO("Obtained IP6 address: %s", WiFi.localIPv6());
|
||||
LOG_INFO("Obtained IP6 address: %s\n", WiFi.localIPv6().toString().c_str());
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
|
||||
LOG_INFO("Lost IP address and IP address is reset to 0\n");
|
||||
@@ -369,6 +393,7 @@ static void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t getWifiDisconnectReason()
|
||||
{
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#if defined(HAS_WIFI) && !defined(ARCH_PORTDUINO)
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
@@ -19,4 +19,4 @@ void deinitWifi();
|
||||
|
||||
bool isWifiAvailable();
|
||||
|
||||
uint8_t getWifiDisconnectReason();
|
||||
uint8_t getWifiDisconnectReason();
|
||||
@@ -39,10 +39,11 @@
|
||||
*/
|
||||
char *strnstr(const char *s, const char *find, size_t slen)
|
||||
{
|
||||
char c, sc;
|
||||
size_t len;
|
||||
|
||||
char c;
|
||||
if ((c = *find++) != '\0') {
|
||||
char sc;
|
||||
size_t len;
|
||||
|
||||
len = strlen(find);
|
||||
do {
|
||||
do {
|
||||
|
||||
@@ -622,12 +622,12 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r
|
||||
#if HAS_BLUETOOTH
|
||||
conn.has_bluetooth = true;
|
||||
conn.bluetooth.pin = config.bluetooth.fixed_pin;
|
||||
#endif
|
||||
#ifdef ARCH_ESP32
|
||||
conn.bluetooth.is_connected = nimbleBluetooth->isConnected();
|
||||
conn.bluetooth.rssi = nimbleBluetooth->getRssi();
|
||||
#elif defined(ARCH_NRF52)
|
||||
conn.bluetooth.is_connected = nrf52Bluetooth->isConnected();
|
||||
#endif
|
||||
#endif
|
||||
conn.has_serial = true; // No serial-less devices
|
||||
conn.serial.is_connected = powerFSM.getState() == &stateSERIAL;
|
||||
@@ -699,4 +699,4 @@ AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_AP
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::adminChannel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "ProtobufModule.h"
|
||||
#ifdef ARCH_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#if HAS_WIFI
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -50,4 +50,4 @@ class AdminModule : public ProtobufModule<meshtastic_AdminMessage>
|
||||
void reboot(int32_t seconds);
|
||||
};
|
||||
|
||||
extern AdminModule *adminModule;
|
||||
extern AdminModule *adminModule;
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "configuration.h"
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "PortduinoGlue.h"
|
||||
#endif
|
||||
#if HAS_SCREEN
|
||||
#include "CannedMessageModule.h"
|
||||
#include "Channels.h"
|
||||
#include "FSCommon.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -141,14 +145,18 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
|
||||
bool validEvent = false;
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP)) {
|
||||
// LOG_DEBUG("Canned message event UP\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP;
|
||||
validEvent = true;
|
||||
if (this->messagesCount > 0) {
|
||||
// LOG_DEBUG("Canned message event UP\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP;
|
||||
validEvent = true;
|
||||
}
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN)) {
|
||||
// LOG_DEBUG("Canned message event DOWN\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN;
|
||||
validEvent = true;
|
||||
if (this->messagesCount > 0) {
|
||||
// LOG_DEBUG("Canned message event DOWN\n");
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN;
|
||||
validEvent = true;
|
||||
}
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) {
|
||||
LOG_DEBUG("Canned message event Select\n");
|
||||
@@ -163,9 +171,14 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) {
|
||||
LOG_DEBUG("Canned message event Cancel\n");
|
||||
// emulate a timeout. Same result
|
||||
this->lastTouchMillis = 0;
|
||||
validEvent = true;
|
||||
UIFrameEvent e = {false, true};
|
||||
e.frameChanged = true;
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
if ((event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
||||
@@ -175,10 +188,10 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
if (!event->kbchar) {
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
this->payload = 0xb4;
|
||||
this->destSelect = true;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
this->payload = 0xb7;
|
||||
this->destSelect = true;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||
}
|
||||
} else {
|
||||
// pass the pressed key
|
||||
@@ -212,16 +225,21 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
|
||||
if (validEvent) {
|
||||
// Let runOnce to be called immediately.
|
||||
setIntervalFromNow(0);
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
|
||||
setIntervalFromNow(0); // on fast keypresses, this isn't fast enough.
|
||||
} else {
|
||||
runOnce();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantReplies)
|
||||
void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const char *message, bool wantReplies)
|
||||
{
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
p->to = dest;
|
||||
p->channel = channel;
|
||||
p->want_ack = true;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
@@ -233,7 +251,9 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
|
||||
|
||||
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
|
||||
service.sendToMesh(p);
|
||||
service.sendToMesh(
|
||||
p, RX_SRC_LOCAL,
|
||||
true); // send to mesh, cc to phone. Even if there's no phone connected, this stores the message to match ACKs
|
||||
}
|
||||
|
||||
int32_t CannedMessageModule::runOnce()
|
||||
@@ -244,14 +264,15 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
// LOG_DEBUG("Check status\n");
|
||||
UIFrameEvent e = {false, true};
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
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_INACTIVE;
|
||||
e.frameChanged = true;
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
this->notifyObservers(&e);
|
||||
} else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) &&
|
||||
((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) {
|
||||
@@ -261,13 +282,13 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
this->notifyObservers(&e);
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
|
||||
if (this->payload == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
if (this->freetext.length() > 0) {
|
||||
sendText(this->dest, this->freetext.c_str(), true);
|
||||
sendText(this->dest, indexChannels[this->channel], this->freetext.c_str(), true);
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
|
||||
} else {
|
||||
LOG_DEBUG("Reset message is empty.\n");
|
||||
@@ -279,7 +300,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
return INT32_MAX;
|
||||
} else {
|
||||
sendText(NODENUM_BROADCAST, this->messages[this->currentMessageIndex], true);
|
||||
sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true);
|
||||
}
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
|
||||
} else {
|
||||
@@ -291,7 +312,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
this->notifyObservers(&e);
|
||||
return 2000;
|
||||
} else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) {
|
||||
@@ -304,7 +325,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->currentMessageIndex = getPrevIndex();
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
LOG_DEBUG("MOVE UP (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
}
|
||||
@@ -313,14 +334,14 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->currentMessageIndex = this->getNextIndex();
|
||||
this->freetext = ""; // clear freetext
|
||||
this->cursor = 0;
|
||||
this->destSelect = false;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
}
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) {
|
||||
switch (this->payload) {
|
||||
case 0xb4: // left
|
||||
if (this->destSelect) {
|
||||
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
|
||||
size_t numMeshNodes = nodeDB.getNumMeshNodes();
|
||||
if (this->dest == NODENUM_BROADCAST) {
|
||||
this->dest = nodeDB.getNodeNum();
|
||||
@@ -335,6 +356,19 @@ int32_t CannedMessageModule::runOnce()
|
||||
if (this->dest == nodeDB.getNodeNum()) {
|
||||
this->dest = NODENUM_BROADCAST;
|
||||
}
|
||||
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
|
||||
for (unsigned int i = 0; i < channels.getNumChannels(); i++) {
|
||||
if ((channels.getByIndex(i).role == meshtastic_Channel_Role_SECONDARY) ||
|
||||
(channels.getByIndex(i).role == meshtastic_Channel_Role_PRIMARY)) {
|
||||
indexChannels[numChannels] = i;
|
||||
numChannels++;
|
||||
}
|
||||
}
|
||||
if (this->channel == 0) {
|
||||
this->channel = numChannels - 1;
|
||||
} else {
|
||||
this->channel--;
|
||||
}
|
||||
} else {
|
||||
if (this->cursor > 0) {
|
||||
this->cursor--;
|
||||
@@ -342,7 +376,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
break;
|
||||
case 0xb7: // right
|
||||
if (this->destSelect) {
|
||||
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
|
||||
size_t numMeshNodes = nodeDB.getNumMeshNodes();
|
||||
if (this->dest == NODENUM_BROADCAST) {
|
||||
this->dest = nodeDB.getNodeNum();
|
||||
@@ -357,6 +391,19 @@ int32_t CannedMessageModule::runOnce()
|
||||
if (this->dest == nodeDB.getNodeNum()) {
|
||||
this->dest = NODENUM_BROADCAST;
|
||||
}
|
||||
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
|
||||
for (unsigned int i = 0; i < channels.getNumChannels(); i++) {
|
||||
if ((channels.getByIndex(i).role == meshtastic_Channel_Role_SECONDARY) ||
|
||||
(channels.getByIndex(i).role == meshtastic_Channel_Role_PRIMARY)) {
|
||||
indexChannels[numChannels] = i;
|
||||
numChannels++;
|
||||
}
|
||||
}
|
||||
if (this->channel == numChannels - 1) {
|
||||
this->channel = 0;
|
||||
} else {
|
||||
this->channel++;
|
||||
}
|
||||
} else {
|
||||
if (this->cursor < this->freetext.length()) {
|
||||
this->cursor++;
|
||||
@@ -381,10 +428,12 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
break;
|
||||
case 0x09: // tab
|
||||
if (this->destSelect) {
|
||||
this->destSelect = false;
|
||||
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL;
|
||||
} else {
|
||||
this->destSelect = true;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||
}
|
||||
break;
|
||||
case 0xb4: // left
|
||||
@@ -483,7 +532,18 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
String displayString;
|
||||
if (this->ack) {
|
||||
displayString = "Delivered to\n%s";
|
||||
} else {
|
||||
displayString = "Delivery failed\nto %s";
|
||||
}
|
||||
display->drawStringf(display->getWidth() / 2 + x, 0 + y + 12, buffer, displayString,
|
||||
cannedMessageModule->getNodeName(this->incoming));
|
||||
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending...");
|
||||
@@ -494,19 +554,39 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
if (this->destSelect) {
|
||||
if (this->destSelect != CANNED_MESSAGE_DESTINATION_TYPE_NONE) {
|
||||
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawStringf(1 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
}
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
// used chars right aligned
|
||||
uint16_t charsLeft =
|
||||
meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length() - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||
snprintf(buffer, sizeof(buffer), "%d left", charsLeft);
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
|
||||
if (this->destSelect) {
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer) - 1, y + 0, buffer);
|
||||
switch (this->destSelect) {
|
||||
case CANNED_MESSAGE_DESTINATION_TYPE_NODE:
|
||||
display->drawStringf(1 + x, 0 + y, buffer, "To: >%s<@%s", cannedMessageModule->getNodeName(this->dest),
|
||||
channels.getName(indexChannels[this->channel]));
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: >%s<@%s", cannedMessageModule->getNodeName(this->dest),
|
||||
channels.getName(indexChannels[this->channel]));
|
||||
break;
|
||||
case CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL:
|
||||
display->drawStringf(1 + x, 0 + y, buffer, "To: %s@>%s<", cannedMessageModule->getNodeName(this->dest),
|
||||
channels.getName(indexChannels[this->channel]));
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s@>%s<", cannedMessageModule->getNodeName(this->dest),
|
||||
channels.getName(indexChannels[this->channel]));
|
||||
break;
|
||||
default:
|
||||
if (display->getWidth() > 128) {
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s@%s", cannedMessageModule->getNodeName(this->dest),
|
||||
channels.getName(indexChannels[this->channel]));
|
||||
} else {
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %.5s@%.5s", cannedMessageModule->getNodeName(this->dest),
|
||||
channels.getName(indexChannels[this->channel]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
// used chars right aligned, only when not editing the destination
|
||||
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NONE) {
|
||||
uint16_t charsLeft =
|
||||
meshtastic_Constants_DATA_PAYLOAD_LEN - this->freetext.length() - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||
snprintf(buffer, sizeof(buffer), "%d left", charsLeft);
|
||||
display->drawString(x + display->getWidth() - display->getStringWidth(buffer), y + 0, buffer);
|
||||
}
|
||||
display->setColor(WHITE);
|
||||
display->drawStringMaxWidth(
|
||||
@@ -546,6 +626,27 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
}
|
||||
|
||||
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP) {
|
||||
// look for a request_id
|
||||
if (mp.decoded.request_id != 0) {
|
||||
UIFrameEvent e = {false, true};
|
||||
e.frameChanged = true;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED;
|
||||
this->incoming = service.getNodenumFromRequestId(mp.decoded.request_id);
|
||||
meshtastic_Routing decoded = meshtastic_Routing_init_default;
|
||||
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded);
|
||||
this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE;
|
||||
this->notifyObservers(&e);
|
||||
// run the next time 2 seconds later
|
||||
setIntervalFromNow(2000);
|
||||
}
|
||||
}
|
||||
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
void CannedMessageModule::loadProtoForModule()
|
||||
{
|
||||
if (!nodeDB.loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
|
||||
@@ -650,4 +751,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -9,11 +9,18 @@ enum cannedMessageModuleRunState {
|
||||
CANNED_MESSAGE_RUN_STATE_ACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_FREETEXT,
|
||||
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_UP,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_DOWN,
|
||||
};
|
||||
|
||||
enum cannedMessageDestinationType {
|
||||
CANNED_MESSAGE_DESTINATION_TYPE_NONE,
|
||||
CANNED_MESSAGE_DESTINATION_TYPE_NODE,
|
||||
CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL
|
||||
};
|
||||
|
||||
#define CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT 50
|
||||
/**
|
||||
* Sum of CannedMessageModuleConfig part sizes.
|
||||
@@ -37,19 +44,33 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
const char *getMessageByIndex(int index);
|
||||
const char *getNodeName(NodeNum node);
|
||||
bool shouldDraw();
|
||||
void eventUp();
|
||||
void eventDown();
|
||||
void eventSelect();
|
||||
// void eventUp();
|
||||
// void eventDown();
|
||||
// void eventSelect();
|
||||
|
||||
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
|
||||
void handleSetCannedMessageModuleMessages(const char *from_msg);
|
||||
|
||||
String drawWithCursor(String text, int cursor);
|
||||
|
||||
/*
|
||||
-Override the wantPacket method. We need the Routing Messages to look for ACKs.
|
||||
*/
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
||||
{
|
||||
switch (p->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP:
|
||||
case meshtastic_PortNum_ROUTING_APP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
void sendText(NodeNum dest, const char *message, bool wantReplies);
|
||||
void sendText(NodeNum dest, ChannelIndex channel, const char *message, bool wantReplies);
|
||||
|
||||
int splitConfiguredMessages();
|
||||
int getNextIndex();
|
||||
@@ -63,6 +84,12 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response) override;
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered
|
||||
* for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||
|
||||
void loadProtoForModule();
|
||||
bool saveProtoForModule();
|
||||
|
||||
@@ -72,9 +99,14 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
cannedMessageModuleRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
char payload = 0x00;
|
||||
unsigned int cursor = 0;
|
||||
String freetext = ""; // Text Buffer for Freetext Editor
|
||||
bool destSelect = false; // Freetext Editor Mode
|
||||
String freetext = ""; // Text Buffer for Freetext Editor
|
||||
NodeNum dest = NODENUM_BROADCAST;
|
||||
ChannelIndex channel = 0;
|
||||
cannedMessageDestinationType destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
uint8_t numChannels = 0;
|
||||
ChannelIndex indexChannels[MAX_NUM_CHANNELS] = {0};
|
||||
NodeNum incoming = NODENUM_BROADCAST;
|
||||
bool ack = false; // True means ACK, false means NAK (error_reason != NONE)
|
||||
|
||||
char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE + 1];
|
||||
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
|
||||
@@ -83,4 +115,4 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
};
|
||||
|
||||
extern CannedMessageModule *cannedMessageModule;
|
||||
#endif
|
||||
#endif
|
||||
@@ -20,11 +20,10 @@
|
||||
#include "Router.h"
|
||||
#include "buzz/buzz.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "mesh/generated/meshtastic/rtttl.pb.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#ifdef HAS_NCP5623
|
||||
#include <graphics/RAKled.h>
|
||||
|
||||
@@ -54,6 +53,8 @@ bool ascending = true;
|
||||
#endif
|
||||
#define EXT_NOTIFICATION_MODULE_OUTPUT_MS 1000
|
||||
|
||||
#define EXT_NOTIFICATION_DEFAULT_THREAD_MS 25
|
||||
|
||||
#define ASCII_BELL 0x07
|
||||
|
||||
meshtastic_RTTTLConfig rtttlConfig;
|
||||
@@ -71,7 +72,12 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
if (!moduleConfig.external_notification.enabled) {
|
||||
return INT32_MAX; // we don't need this thread here...
|
||||
} else {
|
||||
if ((nagCycleCutoff < millis()) && !rtttl::isPlaying()) {
|
||||
|
||||
bool isPlaying = rtttl::isPlaying();
|
||||
#ifdef HAS_I2S
|
||||
isPlaying = rtttl::isPlaying() || audioThread->isPlaying();
|
||||
#endif
|
||||
if ((nagCycleCutoff < millis()) && !isPlaying) {
|
||||
// let the song finish if we reach timeout
|
||||
nagCycleCutoff = UINT32_MAX;
|
||||
LOG_INFO("Turning off external notification: ");
|
||||
@@ -132,6 +138,16 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
#endif
|
||||
}
|
||||
|
||||
// Play RTTTL over i2s audio interface if enabled as buzzer
|
||||
#ifdef HAS_I2S
|
||||
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
|
||||
if (audioThread->isPlaying()) {
|
||||
// Continue playing
|
||||
} else if (isNagging && (nagCycleCutoff >= millis())) {
|
||||
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// now let the PWM buzzer play
|
||||
if (moduleConfig.external_notification.use_pwm) {
|
||||
if (rtttl::isPlaying()) {
|
||||
@@ -142,7 +158,7 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
return 25;
|
||||
return EXT_NOTIFICATION_DEFAULT_THREAD_MS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +191,7 @@ void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||
digitalWrite(output, (moduleConfig.external_notification.active ? true : false));
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HAS_NCP5623
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
rgb.setColor(red, green, blue);
|
||||
@@ -226,6 +243,9 @@ bool ExternalNotificationModule::getExternal(uint8_t index)
|
||||
void ExternalNotificationModule::stopNow()
|
||||
{
|
||||
rtttl::stop();
|
||||
#ifdef HAS_I2S
|
||||
audioThread->stop();
|
||||
#endif
|
||||
nagCycleCutoff = 1; // small value
|
||||
isNagging = false;
|
||||
setIntervalFromNow(0);
|
||||
@@ -246,6 +266,7 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
// moduleConfig.external_notification.alert_message = true;
|
||||
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
// moduleConfig.external_notification.alert_message_vibra = true;
|
||||
// moduleConfig.external_notification.use_i2s_as_buzzer = true;
|
||||
|
||||
// moduleConfig.external_notification.active = true;
|
||||
// moduleConfig.external_notification.alert_bell = 1;
|
||||
@@ -255,6 +276,13 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
// moduleConfig.external_notification.output_vibra = 28; // RAK4631 IO7
|
||||
// moduleConfig.external_notification.nag_timeout = 300;
|
||||
|
||||
// T-Watch / T-Deck i2s audio as buzzer:
|
||||
// moduleConfig.external_notification.enabled = true;
|
||||
// moduleConfig.external_notification.nag_timeout = 300;
|
||||
// moduleConfig.external_notification.output_ms = 1000;
|
||||
// moduleConfig.external_notification.use_i2s_as_buzzer = true;
|
||||
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
if (!nodeDB.loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
|
||||
&meshtastic_RTTTLConfig_msg, &rtttlConfig)) {
|
||||
@@ -309,14 +337,13 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
#if T_WATCH_S3
|
||||
#ifdef T_WATCH_S3
|
||||
drv.setWaveform(0, 75);
|
||||
drv.setWaveform(1, 56);
|
||||
drv.setWaveform(2, 0);
|
||||
drv.go();
|
||||
#endif
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
|
||||
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
|
||||
auto &p = mp.decoded;
|
||||
bool containsBell = false;
|
||||
@@ -359,7 +386,11 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn(2);
|
||||
} else {
|
||||
#ifdef HAS_I2S
|
||||
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
|
||||
#else
|
||||
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
||||
#endif
|
||||
}
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
@@ -394,10 +425,16 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
if (moduleConfig.external_notification.alert_message_buzzer) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)\n");
|
||||
isNagging = true;
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) {
|
||||
setExternalOn(2);
|
||||
} else {
|
||||
#ifdef HAS_I2S
|
||||
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
|
||||
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
|
||||
}
|
||||
#else
|
||||
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
||||
#endif
|
||||
}
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "modules/TraceRouteModule.h"
|
||||
#include "modules/WaypointModule.h"
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "input/LinuxInputImpl.h"
|
||||
#endif
|
||||
#if HAS_TELEMETRY
|
||||
#include "modules/Telemetry/DeviceTelemetry.h"
|
||||
#endif
|
||||
@@ -44,7 +47,7 @@
|
||||
void setupModules()
|
||||
{
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
#if HAS_BUTTON
|
||||
#if HAS_BUTTON || ARCH_RASPBERRY_PI
|
||||
inputBroker = new InputBroker();
|
||||
#endif
|
||||
adminModule = new AdminModule();
|
||||
@@ -61,7 +64,7 @@ void setupModules()
|
||||
|
||||
new RemoteHardwareModule();
|
||||
new ReplyModule();
|
||||
#if HAS_BUTTON
|
||||
#if HAS_BUTTON || ARCH_RASPBERRY_PI
|
||||
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
||||
if (!rotaryEncoderInterruptImpl1->init()) {
|
||||
delete rotaryEncoderInterruptImpl1;
|
||||
@@ -79,6 +82,10 @@ void setupModules()
|
||||
kbMatrixImpl->init();
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
#endif // HAS_BUTTON
|
||||
#if ARCH_RASPBERRY_PI
|
||||
aLinuxInputImpl = new LinuxInputImpl();
|
||||
aLinuxInputImpl->init();
|
||||
#endif
|
||||
#if HAS_TRACKBALL
|
||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||
trackballInterruptImpl1->init();
|
||||
|
||||
@@ -118,7 +118,7 @@ uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighb
|
||||
int num_neighbors = cleanUpNeighbors();
|
||||
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (dbEntry->node_id != my_node_id)) {
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = dbEntry->node_id;
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = dbEntry->snr;
|
||||
@@ -146,7 +146,7 @@ size_t NeighborInfoModule::cleanUpNeighbors()
|
||||
// Find neighbors to remove
|
||||
std::vector<int> indices_to_remove;
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
||||
if ((now - dbEntry->last_rx_time > dbEntry->node_broadcast_interval_secs * 2) && (dbEntry->node_id != my_node_id)) {
|
||||
indices_to_remove.push_back(i);
|
||||
|
||||
@@ -89,7 +89,7 @@ int32_t NodeInfoModule::runOnce()
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
if (airTime->isTxAllowedAirUtil()) {
|
||||
if (airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
|
||||
LOG_INFO("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
|
||||
sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
|
||||
}
|
||||
|
||||
@@ -225,6 +225,9 @@ int32_t PositionModule::runOnce()
|
||||
|
||||
LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND) {
|
||||
sendLostAndFoundText();
|
||||
}
|
||||
}
|
||||
} else if (config.position.position_broadcast_smart_enabled) {
|
||||
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
@@ -261,6 +264,21 @@ int32_t PositionModule::runOnce()
|
||||
return RUNONCE_INTERVAL; // to save power only wake for our callback occasionally
|
||||
}
|
||||
|
||||
void PositionModule::sendLostAndFoundText()
|
||||
{
|
||||
meshtastic_MeshPacket *p = allocDataPacket();
|
||||
p->to = NODENUM_BROADCAST;
|
||||
char *message = new char[60];
|
||||
sprintf(message, "🚨I'm lost! Lat / Lon: %f, %f\a", (lastGpsLatitude * 1e-7), (lastGpsLongitude * 1e-7));
|
||||
p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
|
||||
p->want_ack = false;
|
||||
p->decoded.payload.size = strlen(message);
|
||||
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
|
||||
|
||||
service.sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
delete[] message;
|
||||
}
|
||||
|
||||
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
|
||||
{
|
||||
// The minimum distance to travel before we are able to send a new position packet.
|
||||
|
||||
@@ -52,6 +52,7 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
|
||||
|
||||
/** Only used in power saving trackers for now */
|
||||
void clearPosition();
|
||||
void sendLostAndFoundText();
|
||||
};
|
||||
|
||||
struct SmartPosition {
|
||||
|
||||
@@ -46,5 +46,6 @@ void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketI
|
||||
RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg)
|
||||
{
|
||||
isPromiscuous = true;
|
||||
encryptedOk = config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
|
||||
encryptedOk = config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY &&
|
||||
config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ int32_t DeviceTelemetryModule::runOnce()
|
||||
if (((lastSentToMesh == 0) ||
|
||||
((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) &&
|
||||
airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil() &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
|
||||
sendTelemetry();
|
||||
lastSentToMesh = now;
|
||||
} else if (service.isToPhoneQueueEmpty()) {
|
||||
|
||||
@@ -97,9 +97,9 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
result = lps22hbSensor.runOnce();
|
||||
if (sht31Sensor.hasSensor())
|
||||
result = sht31Sensor.runOnce();
|
||||
if (ina219Sensor.hasSensor() && !ina219Sensor.isInitialized())
|
||||
if (ina219Sensor.hasSensor())
|
||||
result = ina219Sensor.runOnce();
|
||||
if (ina260Sensor.hasSensor() && !ina260Sensor.isInitialized())
|
||||
if (ina260Sensor.hasSensor())
|
||||
result = ina260Sensor.runOnce();
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include "mesh/Router.h"
|
||||
#include "mesh/generated/meshtastic/mqtt.pb.h"
|
||||
#include "mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "sleep.h"
|
||||
#if HAS_WIFI
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include "mqtt/JSON.h"
|
||||
@@ -519,10 +519,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
|
||||
// the created jsonObj is immutable after creation, so
|
||||
// we need to do the heavy lifting before assembling it.
|
||||
std::string msgType;
|
||||
JSONObject msgPayload;
|
||||
JSONObject jsonObj;
|
||||
|
||||
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
JSONObject msgPayload;
|
||||
switch (mp->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
|
||||
msgType = "text";
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
NimBLECharacteristic *fromNumCharacteristic;
|
||||
NimBLECharacteristic *BatteryCharacteristic;
|
||||
NimBLEServer *bleServer;
|
||||
|
||||
static bool passkeyShowing;
|
||||
@@ -181,6 +182,18 @@ void NimbleBluetooth::setupService()
|
||||
FromRadioCharacteristic->setCallbacks(fromRadioCallbacks);
|
||||
|
||||
bleService->start();
|
||||
|
||||
// Setup the battery service
|
||||
NimBLEService *batteryService = bleServer->createService(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
||||
BatteryCharacteristic = batteryService->createCharacteristic( // 0x2A19 is the Battery Level characteristic)
|
||||
(uint16_t)0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY, 1);
|
||||
|
||||
NimBLE2904 *batteryLevelDescriptor = (NimBLE2904 *)BatteryCharacteristic->createDescriptor((uint16_t)0x2904);
|
||||
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
||||
batteryLevelDescriptor->setNamespace(1);
|
||||
batteryLevelDescriptor->setUnit(0x27ad);
|
||||
|
||||
batteryService->start();
|
||||
}
|
||||
|
||||
void NimbleBluetooth::startAdvertising()
|
||||
@@ -188,13 +201,17 @@ void NimbleBluetooth::startAdvertising()
|
||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->reset();
|
||||
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
|
||||
pAdvertising->addServiceUUID(NimBLEUUID((uint16_t)0x180f)); // 0x180F is the Battery Service
|
||||
pAdvertising->start(0);
|
||||
}
|
||||
|
||||
/// Given a level between 0-100, update the BLE attribute
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
// blebas.write(level);
|
||||
if ((config.bluetooth.enabled == true) && bleServer && nimbleBluetooth->isConnected()) {
|
||||
BatteryCharacteristic->setValue(&level, 1);
|
||||
BatteryCharacteristic->notify();
|
||||
}
|
||||
}
|
||||
|
||||
void NimbleBluetooth::clearBonds()
|
||||
|
||||
@@ -121,18 +121,30 @@
|
||||
#define HW_VENDOR meshtastic_HardwareModel_PICOMPUTER_S3
|
||||
#elif defined(HELTEC_HT62)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HT62
|
||||
#elif defined(SENSELORA_S3)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_SENSELORA_S3
|
||||
#elif defined(HELTEC_HT62)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HT62
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// LoRa SPI
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// NRF52 boards will define this in variant.h
|
||||
#ifndef RF95_SCK
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS 18
|
||||
// If an SPI-related pin used by the LoRa module isn't defined, use the conventional pin number for it.
|
||||
// FIXME: these pins should really be defined in each variant.h file to prevent breakages if the defaults change, currently many
|
||||
// ESP32 variants don't define these pins in their variant.h file.
|
||||
#ifndef LORA_SCK
|
||||
#define LORA_SCK 5
|
||||
#endif
|
||||
#ifndef LORA_MISO
|
||||
#define LORA_MISO 19
|
||||
#endif
|
||||
#ifndef LORA_MOSI
|
||||
#define LORA_MOSI 27
|
||||
#endif
|
||||
#ifndef LORA_CS
|
||||
#define LORA_CS 18
|
||||
#endif
|
||||
|
||||
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
|
||||
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32 // FIXME: may be different on ESP32-S3, etc.
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "nimble/NimbleBluetooth.h"
|
||||
#endif
|
||||
#include "BleOta.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
|
||||
#include "meshUtils.h"
|
||||
#include "sleep.h"
|
||||
|
||||
@@ -211,6 +211,7 @@ void NRF52Bluetooth::shutdown()
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
LOG_INFO("Disable NRF52 bluetooth\n");
|
||||
Bluefruit.Advertising.stop();
|
||||
Bluefruit.setTxPower(0); // Minimum power
|
||||
}
|
||||
|
||||
bool NRF52Bluetooth::isConnected()
|
||||
@@ -333,4 +334,4 @@ void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_statu
|
||||
LOG_INFO("BLE pairing failed\n");
|
||||
|
||||
screen->stopBluetoothPinScreen();
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ void getMacAddr(uint8_t *dmac)
|
||||
|
||||
static void initBrownout()
|
||||
{
|
||||
auto vccthresh = POWER_POFCON_THRESHOLD_V17;
|
||||
auto vccthresh = POWER_POFCON_THRESHOLD_V24;
|
||||
|
||||
auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled);
|
||||
assert(err_code == NRF_SUCCESS);
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
#ifndef PI_HAL_H
|
||||
#define PI_HAL_H
|
||||
|
||||
// include RadioLib
|
||||
#include <RadioLib.h>
|
||||
|
||||
// include the library for Raspberry GPIO pins
|
||||
#include "pigpio.h"
|
||||
|
||||
// create a new Raspberry Pi hardware abstraction layer
|
||||
// using the pigpio library
|
||||
// the HAL must inherit from the base RadioLibHal class
|
||||
// and implement all of its virtual methods
|
||||
class PiHal : public RadioLibHal
|
||||
{
|
||||
public:
|
||||
// default constructor - initializes the base HAL and any needed private members
|
||||
PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000)
|
||||
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), _spiChannel(spiChannel),
|
||||
_spiSpeed(spiSpeed)
|
||||
{
|
||||
}
|
||||
|
||||
void init() override
|
||||
{
|
||||
// first initialise pigpio library
|
||||
gpioInitialise();
|
||||
|
||||
// now the SPI
|
||||
spiBegin();
|
||||
|
||||
// Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio
|
||||
// gpioSetMode(18, PI_OUTPUT);
|
||||
// gpioWrite(18, PI_HIGH);
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
// stop the SPI
|
||||
spiEnd();
|
||||
|
||||
// pull the enable pin low
|
||||
// gpioSetMode(18, PI_OUTPUT);
|
||||
// gpioWrite(18, PI_LOW);
|
||||
|
||||
// finally, stop the pigpio library
|
||||
gpioTerminate();
|
||||
}
|
||||
|
||||
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||
// RADIOLIB_NC as an alias for non-connected pins
|
||||
void pinMode(uint32_t pin, uint32_t mode) override
|
||||
{
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetMode(pin, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override
|
||||
{
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioWrite(pin, value);
|
||||
}
|
||||
|
||||
uint32_t digitalRead(uint32_t pin) override
|
||||
{
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (gpioRead(pin));
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override
|
||||
{
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
if (gpioRead(interruptNum) == 1) {
|
||||
interruptCb();
|
||||
} else {
|
||||
gpioSetAlertFunc(interruptNum, (gpioISRFunc_t)interruptCb);
|
||||
}
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t interruptNum) override
|
||||
{
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetAlertFunc(interruptNum, NULL);
|
||||
}
|
||||
|
||||
void delay(unsigned long ms) override { gpioDelay(ms * 1000); }
|
||||
|
||||
void delayMicroseconds(unsigned long us) override { gpioDelay(us); }
|
||||
|
||||
unsigned long millis() override { return (gpioTick() / 1000); }
|
||||
|
||||
unsigned long micros() override { return (gpioTick()); }
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
|
||||
{
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
this->pinMode(pin, PI_INPUT);
|
||||
uint32_t start = this->micros();
|
||||
uint32_t curtick = this->micros();
|
||||
|
||||
while (this->digitalRead(pin) == state) {
|
||||
if ((this->micros() - curtick) > timeout) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (this->micros() - start);
|
||||
}
|
||||
|
||||
void spiBegin()
|
||||
{
|
||||
if (_spiHandle < 0) {
|
||||
_spiHandle = spiOpen(_spiChannel, _spiSpeed, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void spiBeginTransaction() {}
|
||||
|
||||
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) { spiXfer(_spiHandle, (char *)out, (char *)in, len); }
|
||||
|
||||
void spiEndTransaction() {}
|
||||
|
||||
void spiEnd()
|
||||
{
|
||||
if (_spiHandle >= 0) {
|
||||
spiClose(_spiHandle);
|
||||
_spiHandle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// the HAL can contain any additional private members
|
||||
const unsigned int _spiSpeed;
|
||||
const uint8_t _spiChannel;
|
||||
int _spiHandle = -1;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,13 +10,15 @@
|
||||
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
#include "PortduinoGlue.h"
|
||||
#include "linux/gpio/LinuxGPIOPin.h"
|
||||
#include "pigpio.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <unistd.h>
|
||||
|
||||
std::map<int, int> settingsMap;
|
||||
std::map<configNames, int> settingsMap;
|
||||
std::map<configNames, std::string> settingsStrings;
|
||||
|
||||
#else
|
||||
#include <linux/gpio/LinuxGPIOPin.h>
|
||||
@@ -101,6 +103,9 @@ void portduinoSetup()
|
||||
printf("Setting up Meshtastic on Portduino...\n");
|
||||
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
gpioInit();
|
||||
|
||||
std::string gpioChipName = "gpiochip";
|
||||
YAML::Node yamlConfig;
|
||||
|
||||
if (access("config.yaml", R_OK) == 0) {
|
||||
@@ -137,6 +142,40 @@ void portduinoSetup()
|
||||
settingsMap[irq] = yamlConfig["Lora"]["IRQ"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[busy] = yamlConfig["Lora"]["Busy"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[reset] = yamlConfig["Lora"]["Reset"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
||||
gpioChipName += std::to_string(settingsMap[gpiochip]);
|
||||
}
|
||||
if (yamlConfig["GPIO"]) {
|
||||
settingsMap[user] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
|
||||
}
|
||||
if (yamlConfig["GPS"]) {
|
||||
std::string serialPath = yamlConfig["GPS"]["SerialPath"].as<std::string>("");
|
||||
if (serialPath != "") {
|
||||
Serial1.setPath(serialPath);
|
||||
settingsMap[has_gps] = 1;
|
||||
}
|
||||
}
|
||||
settingsMap[displayPanel] = no_screen;
|
||||
if (yamlConfig["Display"]) {
|
||||
if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7789")
|
||||
settingsMap[displayPanel] = st7789;
|
||||
settingsMap[displayHeight] = yamlConfig["Display"]["Height"].as<int>(0);
|
||||
settingsMap[displayWidth] = yamlConfig["Display"]["Width"].as<int>(0);
|
||||
settingsMap[displayDC] = yamlConfig["Display"]["DC"].as<int>(-1);
|
||||
settingsMap[displayCS] = yamlConfig["Display"]["CS"].as<int>(-1);
|
||||
settingsMap[displayBacklight] = yamlConfig["Display"]["Backlight"].as<int>(-1);
|
||||
settingsMap[displayReset] = yamlConfig["Display"]["Reset"].as<int>(-1);
|
||||
settingsMap[displayRotate] = yamlConfig["Display"]["Rotate"].as<bool>(false);
|
||||
}
|
||||
settingsMap[touchscreenModule] = no_touchscreen;
|
||||
if (yamlConfig["Touchscreen"]) {
|
||||
if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "XPT2046")
|
||||
settingsMap[touchscreenModule] = xpt2046;
|
||||
settingsMap[touchscreenCS] = yamlConfig["Touchscreen"]["CS"].as<int>(-1);
|
||||
settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as<int>(-1);
|
||||
}
|
||||
if (yamlConfig["Input"]) {
|
||||
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as<std::string>("");
|
||||
}
|
||||
|
||||
} catch (YAML::Exception e) {
|
||||
@@ -147,6 +186,51 @@ void portduinoSetup()
|
||||
std::cout << "Cannot read Bluetooth MAC Address. Please run as root" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Need to bind all the configured GPIO pins so they're not simulated
|
||||
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[cs] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(irq) > 0 && settingsMap[irq] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[irq], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[irq] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(busy) > 0 && settingsMap[busy] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[busy], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[busy] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(reset) > 0 && settingsMap[reset] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[reset], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[reset] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[user] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsMap[displayPanel] != no_screen) {
|
||||
if (settingsMap[displayCS] > 0)
|
||||
initGPIOPin(settingsMap[displayCS], gpioChipName);
|
||||
if (settingsMap[displayDC] > 0)
|
||||
initGPIOPin(settingsMap[displayDC], gpioChipName);
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
initGPIOPin(settingsMap[displayBacklight], gpioChipName);
|
||||
if (settingsMap[displayReset] > 0)
|
||||
initGPIOPin(settingsMap[displayReset], gpioChipName);
|
||||
}
|
||||
if (settingsMap[touchscreenModule] != no_touchscreen) {
|
||||
if (settingsMap[touchscreenCS] > 0)
|
||||
initGPIOPin(settingsMap[touchscreenCS], gpioChipName);
|
||||
if (settingsMap[touchscreenIRQ] > 0)
|
||||
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
|
||||
}
|
||||
|
||||
return;
|
||||
#endif
|
||||
|
||||
@@ -192,6 +276,24 @@ void portduinoSetup()
|
||||
gpioBind(new SimGPIOPin(LORA_DIO1, "fakeLoraIrq"));
|
||||
}
|
||||
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
|
||||
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
|
||||
// gpioBind((new SimGPIOPin(LORA_CS, "LORA_CS"))->setSilent());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
int initGPIOPin(int pinNum, std::string gpioChipName)
|
||||
{
|
||||
std::string gpio_name = "GPIO" + std::to_string(pinNum);
|
||||
try {
|
||||
GPIOPin *csPin;
|
||||
csPin = new LinuxGPIOPin(pinNum, gpioChipName.c_str(), pinNum, gpio_name.c_str());
|
||||
csPin->setSilent();
|
||||
gpioBind(csPin);
|
||||
return ERRNO_OK;
|
||||
} catch (...) {
|
||||
std::exception_ptr p = std::current_exception();
|
||||
std::cout << "Warning, cannot claim pin " << gpio_name << (p ? p.__cxa_exception_type()->name() : "null") << std::endl;
|
||||
return ERRNO_DISABLED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2,8 +2,35 @@
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
#include <map>
|
||||
|
||||
extern std::map<int, int> settingsMap;
|
||||
enum configNames {
|
||||
use_sx1262,
|
||||
cs,
|
||||
irq,
|
||||
busy,
|
||||
reset,
|
||||
dio2_as_rf_switch,
|
||||
use_rf95,
|
||||
user,
|
||||
gpiochip,
|
||||
has_gps,
|
||||
touchscreenModule,
|
||||
touchscreenCS,
|
||||
touchscreenIRQ,
|
||||
displayPanel,
|
||||
displayWidth,
|
||||
displayHeight,
|
||||
displayCS,
|
||||
displayDC,
|
||||
displayBacklight,
|
||||
displayReset,
|
||||
displayRotate,
|
||||
keyboardDevice
|
||||
};
|
||||
enum { no_screen, st7789 };
|
||||
enum { no_touchscreen, xpt2046 };
|
||||
|
||||
enum { use_sx1262, cs, irq, busy, reset, dio2_as_rf_switch, use_rf95 };
|
||||
extern std::map<configNames, int> settingsMap;
|
||||
extern std::map<configNames, std::string> settingsStrings;
|
||||
int initGPIOPin(int pinNum, std::string gpioChipname);
|
||||
|
||||
#endif
|
||||
@@ -16,4 +16,4 @@
|
||||
#endif
|
||||
#ifndef HAS_TELEMETRY
|
||||
#define HAS_TELEMETRY 1
|
||||
#endif
|
||||
#endif
|
||||
@@ -25,4 +25,6 @@
|
||||
#define HW_VENDOR meshtastic_HardwareModel_RPI_PICO
|
||||
#elif defined(RAK11310)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_RAK11310
|
||||
#elif defined(SENSELORA_RP2040)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_SENSELORA_RP2040
|
||||
#endif
|
||||
@@ -1,33 +1,63 @@
|
||||
#include "AES.h"
|
||||
#include "CTR.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "aes.hpp"
|
||||
#include "configuration.h"
|
||||
|
||||
class RP2040CryptoEngine : public CryptoEngine
|
||||
{
|
||||
|
||||
CTRCommon *ctr = NULL;
|
||||
|
||||
public:
|
||||
RP2040CryptoEngine() {}
|
||||
|
||||
~RP2040CryptoEngine() {}
|
||||
|
||||
virtual void setKey(const CryptoKey &k) override
|
||||
{
|
||||
CryptoEngine::setKey(k);
|
||||
LOG_DEBUG("Installing AES%d key!\n", key.length * 8);
|
||||
if (ctr) {
|
||||
delete ctr;
|
||||
ctr = NULL;
|
||||
}
|
||||
if (key.length != 0) {
|
||||
if (key.length == 16)
|
||||
ctr = new CTR<AES128>();
|
||||
else
|
||||
ctr = new CTR<AES256>();
|
||||
|
||||
ctr->setKey(key.bytes, key.length);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encrypt a packet
|
||||
*
|
||||
* @param bytes is updated in place
|
||||
*/
|
||||
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
|
||||
virtual void encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override
|
||||
{
|
||||
if (key.length > 0) {
|
||||
AES_ctx ctx;
|
||||
initNonce(fromNode, packetNum);
|
||||
AES_init_ctx_iv(&ctx, key.bytes, nonce);
|
||||
AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes);
|
||||
initNonce(fromNode, packetId);
|
||||
if (numBytes <= MAX_BLOCKSIZE) {
|
||||
static uint8_t scratch[MAX_BLOCKSIZE];
|
||||
memcpy(scratch, bytes, numBytes);
|
||||
memset(scratch + numBytes, 0,
|
||||
sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it)
|
||||
|
||||
ctr->setIV(nonce, sizeof(nonce));
|
||||
ctr->setCounterSize(4);
|
||||
ctr->encrypt(bytes, scratch, numBytes);
|
||||
} else {
|
||||
LOG_ERROR("Packet too large for crypto engine: %d. noop encryption!\n", numBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
|
||||
virtual void decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override
|
||||
{
|
||||
// For CTR, the implementation is the same
|
||||
encrypt(fromNode, packetNum, numBytes, bytes);
|
||||
encrypt(fromNode, packetId, numBytes, bytes);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
#if ARCH_RASPBERRY_PI
|
||||
#include "api/WiFiServerAPI.h"
|
||||
#include "input/LinuxInputImpl.h"
|
||||
|
||||
#endif
|
||||
|
||||
void powerCommandsCheck()
|
||||
{
|
||||
@@ -15,7 +20,13 @@ void powerCommandsCheck()
|
||||
#elif defined(ARCH_RP2040)
|
||||
rp2040.reboot();
|
||||
#elif defined(ARCH_RASPBERRY_PI)
|
||||
exit(EXIT_SUCCESS);
|
||||
deInitApiServer();
|
||||
if (aLinuxInputImpl)
|
||||
aLinuxInputImpl->deInit();
|
||||
SPI.end();
|
||||
Wire.end();
|
||||
Serial1.end();
|
||||
reboot();
|
||||
#else
|
||||
rebootAtMsec = -1;
|
||||
LOG_WARN("FIXME implement reboot for this platform. Note that some settings require a restart to be applied.\n");
|
||||
@@ -33,6 +44,8 @@ void powerCommandsCheck()
|
||||
#if defined(ARCH_NRF52) || defined(ARCH_ESP32)
|
||||
playShutdownMelody();
|
||||
power->shutdown();
|
||||
#elif ARCH_RASPBERRY_PI
|
||||
exit(EXIT_SUCCESS);
|
||||
#else
|
||||
LOG_WARN("FIXME implement shutdown for this platform");
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp32/pm.h"
|
||||
#include "esp_pm.h"
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#include "rom/rtc.h"
|
||||
#include <driver/rtc_io.h>
|
||||
#include <driver/uart.h>
|
||||
|
||||
@@ -49,4 +49,8 @@ virtualCallInConstructor
|
||||
|
||||
passedByValue:*/RedirectablePrint.h
|
||||
|
||||
internalAstError:*/CrossPlatformCryptoEngine.cpp
|
||||
internalAstError:*/CrossPlatformCryptoEngine.cpp
|
||||
uninitMemberVar:*/AudioThread.h
|
||||
// False positive
|
||||
constVariableReference:*/Channels.cpp
|
||||
constParameterPointer:*/unishox2.c
|
||||
@@ -7,10 +7,10 @@
|
||||
#define LED_PIN 30 // RGB LED
|
||||
|
||||
#define USE_RF95
|
||||
#define RF95_SCK 4
|
||||
#define RF95_MISO 5
|
||||
#define RF95_MOSI 6
|
||||
#define RF95_NSS 7
|
||||
#define LORA_SCK 4
|
||||
#define LORA_MISO 5
|
||||
#define LORA_MOSI 6
|
||||
#define LORA_CS 7
|
||||
|
||||
#define LORA_DIO0 10
|
||||
#define LORA_DIO1 3
|
||||
@@ -19,7 +19,7 @@
|
||||
// WaveShare Core1262-868M
|
||||
// https://www.waveshare.com/wiki/Core1262-868M
|
||||
#define USE_SX1262
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY 10
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#define RF95_SCK 18
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 23
|
||||
#define RF95_NSS 5
|
||||
#define LORA_SCK 18
|
||||
#define LORA_MISO 19
|
||||
#define LORA_MOSI 23
|
||||
#define LORA_CS 5
|
||||
#define RF95_FAN_EN 17
|
||||
|
||||
#define LED_PIN 16 // This is a LED_WS2812 not a standard LED
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
#define USE_RF95
|
||||
|
||||
#define RF95_SCK 18
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 23
|
||||
#define RF95_NSS 5
|
||||
#define LORA_SCK 18
|
||||
#define LORA_MISO 19
|
||||
#define LORA_MOSI 23
|
||||
#define LORA_CS 5
|
||||
|
||||
#define LORA_DIO0 4
|
||||
#define LORA_RESET 14
|
||||
|
||||
@@ -22,24 +22,24 @@
|
||||
|
||||
// #define USE_RF95 // RFM95/SX127x
|
||||
|
||||
#undef RF95_SCK
|
||||
#undef RF95_MISO
|
||||
#undef RF95_MOSI
|
||||
#undef RF95_NSS
|
||||
#undef LORA_SCK
|
||||
#undef LORA_MISO
|
||||
#undef LORA_MOSI
|
||||
#undef LORA_CS
|
||||
|
||||
// WaveShare Core1262-868M OK
|
||||
// https://www.waveshare.com/wiki/Core1262-868M
|
||||
#define USE_SX1262
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define RF95_MISO 39
|
||||
#define RF95_SCK 21
|
||||
#define RF95_MOSI 38
|
||||
#define RF95_NSS 17
|
||||
#define LORA_MISO 39
|
||||
#define LORA_SCK 21
|
||||
#define LORA_MOSI 38
|
||||
#define LORA_CS 17
|
||||
#define LORA_RESET 42
|
||||
#define LORA_DIO1 5
|
||||
#define LORA_BUSY 47
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_BUSY
|
||||
#define SX126X_RESET LORA_RESET
|
||||
@@ -49,14 +49,14 @@
|
||||
|
||||
// #define USE_SX1280
|
||||
#ifdef USE_SX1280
|
||||
#define RF95_MISO 1
|
||||
#define RF95_SCK 3
|
||||
#define RF95_MOSI 4
|
||||
#define RF95_NSS 2
|
||||
#define LORA_MISO 1
|
||||
#define LORA_SCK 3
|
||||
#define LORA_MOSI 4
|
||||
#define LORA_CS 2
|
||||
#define LORA_RESET 17
|
||||
#define LORA_DIO1 12
|
||||
#define LORA_BUSY 47
|
||||
#define SX128X_CS RF95_NSS
|
||||
#define SX128X_CS LORA_CS
|
||||
#define SX128X_DIO1 LORA_DIO1
|
||||
#define SX128X_BUSY LORA_BUSY
|
||||
#define SX128X_RESET LORA_RESET
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
// In receiving, set RXEN as high communication level, TXEN is lowlevel;
|
||||
// Before powering off, set TXEN、RXEN as low level.
|
||||
|
||||
#undef RF95_SCK
|
||||
#define RF95_SCK 18
|
||||
#undef RF95_MISO
|
||||
#define RF95_MISO 19
|
||||
#undef RF95_MOSI
|
||||
#define RF95_MOSI 23
|
||||
#undef LORA_SCK
|
||||
#define LORA_SCK 18
|
||||
#undef LORA_MISO
|
||||
#define LORA_MISO 19
|
||||
#undef LORA_MOSI
|
||||
#define LORA_MOSI 23
|
||||
|
||||
// PINS FOR THE 900M22S
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
// E22_TXEN_CONNECTED_TO_DIO2 wasn't defined, so RXEN wasn't controlled. Commented it out to maintain behavior, but shouldn't be.
|
||||
// Need to comment out defining SX126X_RXEN as LORA_RXEN too
|
||||
// #define LORA_RXEN 17 // Input - RF switch RX control, connecting external MCU IO, valid in high level
|
||||
#undef RF95_NSS
|
||||
#define RF95_NSS 16
|
||||
#undef LORA_CS
|
||||
#define LORA_CS 16
|
||||
#define SX126X_BUSY 22
|
||||
#define SX126X_CS 16
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
#define LORA_DIO2 35 // BUSY for SX1262/SX1268
|
||||
#define LORA_TXEN NOT_A_PIN // Input - RF switch TX control, connecting external MCU IO or DIO2, valid in high level
|
||||
#define LORA_RXEN 21 // Input - RF switch RX control, connecting external MCU IO, valid in high level
|
||||
#undef RF95_NSS
|
||||
#define RF95_NSS 33
|
||||
#undef LORA_CS
|
||||
#define LORA_CS 33
|
||||
#define SX126X_BUSY 35
|
||||
#define SX126X_CS 33
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
// Radio
|
||||
#define USE_SX1262 // E22-900M30S uses SX1262
|
||||
#define USE_SX1268 // E22-400M30S uses SX1268
|
||||
#define SX126X_MAX_POWER \
|
||||
22 // Outputting 22dBm from SX1262 results in ~30dBm E22-900M30S output (module only uses last stage of the YP2233W PA)
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // E22 series TCXO reference voltage is 1.8V
|
||||
@@ -33,8 +34,8 @@
|
||||
#define SX126X_TXEN 13 // Schematic connects EBYTE module's TXEN pin to MCU
|
||||
#define SX126X_RXEN 14 // Schematic connects EBYTE module's RXEN pin to MCU
|
||||
|
||||
#define RF95_NSS SX126X_CS // Compatibility with variant file configuration structure
|
||||
#define RF95_SCK SX126X_SCK // Compatibility with variant file configuration structure
|
||||
#define RF95_MOSI SX126X_MOSI // Compatibility with variant file configuration structure
|
||||
#define RF95_MISO SX126X_MISO // Compatibility with variant file configuration structure
|
||||
#define LORA_CS SX126X_CS // Compatibility with variant file configuration structure
|
||||
#define LORA_SCK SX126X_SCK // Compatibility with variant file configuration structure
|
||||
#define LORA_MOSI SX126X_MOSI // Compatibility with variant file configuration structure
|
||||
#define LORA_MISO SX126X_MISO // Compatibility with variant file configuration structure
|
||||
#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
#define LORA_DIO2 32 // BUSY for SX1262/SX1268
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 19
|
||||
#define RF95_MOSI 27
|
||||
#define RF95_NSS 18
|
||||
#define LORA_SCK 5
|
||||
#define LORA_MISO 19
|
||||
#define LORA_MOSI 27
|
||||
#define LORA_CS 18
|
||||
|
||||
// supported modules list
|
||||
#define USE_RF95 // RFM95/SX127x
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
#define LORA_RXEN 14 // Input - RF switch RX control, connecting external MCU IO, valid in high level
|
||||
#define LORA_TXEN 13 // Input - RF switch TX control, connecting external MCU IO or DIO2, valid in high level
|
||||
|
||||
#undef RF95_SCK
|
||||
#define RF95_SCK 18
|
||||
#undef RF95_MISO
|
||||
#define RF95_MISO 19
|
||||
#undef RF95_MOSI
|
||||
#define RF95_MOSI 23
|
||||
#undef RF95_NSS
|
||||
#define RF95_NSS 5
|
||||
#undef LORA_SCK
|
||||
#define LORA_SCK 18
|
||||
#undef LORA_MISO
|
||||
#define LORA_MISO 19
|
||||
#undef LORA_MOSI
|
||||
#define LORA_MOSI 23
|
||||
#undef LORA_CS
|
||||
#define LORA_CS 5
|
||||
|
||||
// RX/TX for RFM95/SX127x
|
||||
#define RF95_RXEN LORA_RXEN
|
||||
|
||||
@@ -81,10 +81,10 @@ extern "C" {
|
||||
#define LORA_DIO2 (0 + 8) // P0.08 12 // BUSY for SX1262/SX1268
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK SCK
|
||||
#define RF95_MISO MI
|
||||
#define RF95_MOSI MO
|
||||
#define RF95_NSS SS
|
||||
#define LORA_SCK SCK
|
||||
#define LORA_MISO MI
|
||||
#define LORA_MOSI MO
|
||||
#define LORA_CS SS
|
||||
|
||||
// enables 3.3V periphery like GPS or IO Module
|
||||
#define PIN_3V3_EN (-1)
|
||||
@@ -95,7 +95,7 @@ extern "C" {
|
||||
#define USE_SX1262
|
||||
|
||||
// common pinouts for SX126X modules
|
||||
#define SX126X_CS RF95_NSS // NSS for SX126X
|
||||
#define SX126X_CS LORA_CS // NSS for SX126X
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
@@ -14,22 +14,22 @@
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#undef RF95_SCK
|
||||
#undef RF95_MISO
|
||||
#undef RF95_MOSI
|
||||
#undef RF95_NSS
|
||||
#undef LORA_SCK
|
||||
#undef LORA_MISO
|
||||
#undef LORA_MOSI
|
||||
#undef LORA_CS
|
||||
|
||||
#define USE_SX1262
|
||||
#define RF95_SCK 10
|
||||
#define RF95_MISO 6
|
||||
#define RF95_MOSI 7
|
||||
#define RF95_NSS 8
|
||||
#define LORA_SCK 10
|
||||
#define LORA_MISO 6
|
||||
#define LORA_MOSI 7
|
||||
#define LORA_CS 8
|
||||
#define LORA_DIO0 RADIOLIB_NC
|
||||
#define LORA_RESET 5
|
||||
#define LORA_DIO1 3
|
||||
#define LORA_DIO2 RADIOLIB_NC
|
||||
#define LORA_BUSY 4
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_BUSY
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 9
|
||||
#define RF95_MISO 11
|
||||
#define RF95_MOSI 10
|
||||
#define RF95_NSS 8
|
||||
#define LORA_SCK 9
|
||||
#define LORA_MISO 11
|
||||
#define LORA_MOSI 10
|
||||
#define LORA_CS 8
|
||||
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 9
|
||||
#define RF95_MISO 11
|
||||
#define RF95_MOSI 10
|
||||
#define RF95_NSS 8
|
||||
#define LORA_SCK 9
|
||||
#define LORA_MISO 11
|
||||
#define LORA_MOSI 10
|
||||
#define LORA_CS 8
|
||||
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
@@ -58,12 +58,12 @@
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 9
|
||||
#define RF95_MISO 11
|
||||
#define RF95_MOSI 10
|
||||
#define RF95_NSS 8
|
||||
#define LORA_SCK 9
|
||||
#define LORA_MISO 11
|
||||
#define LORA_MOSI 10
|
||||
#define LORA_CS 8
|
||||
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define RF95_SCK 9
|
||||
#define RF95_MISO 11
|
||||
#define RF95_MOSI 10
|
||||
#define RF95_NSS 8
|
||||
#define LORA_SCK 9
|
||||
#define LORA_MISO 11
|
||||
#define LORA_MOSI 10
|
||||
#define LORA_CS 8
|
||||
|
||||
#define SX126X_CS RF95_NSS
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#undef RF95_SCK
|
||||
#undef RF95_MISO
|
||||
#undef RF95_MOSI
|
||||
#undef RF95_NSS
|
||||
#undef LORA_SCK
|
||||
#undef LORA_MISO
|
||||
#undef LORA_MOSI
|
||||
#undef LORA_CS
|
||||
|
||||
// Adafruit RFM95W OK
|
||||
// https://www.adafruit.com/product/3072
|
||||
#define USE_RF95
|
||||
#define RF95_SCK 4
|
||||
#define RF95_MISO 5
|
||||
#define RF95_MOSI 6
|
||||
#define RF95_NSS 7
|
||||
#define LORA_SCK 4
|
||||
#define LORA_MISO 5
|
||||
#define LORA_MOSI 6
|
||||
#define LORA_CS 7
|
||||
#define LORA_DIO0 10
|
||||
#define LORA_RESET 8
|
||||
#define LORA_DIO1 RADIOLIB_NC
|
||||
@@ -29,16 +29,16 @@
|
||||
// WaveShare Core1262-868M OK
|
||||
// https://www.waveshare.com/wiki/Core1262-868M
|
||||
// #define USE_SX1262
|
||||
// #define RF95_SCK 4
|
||||
// #define RF95_MISO 5
|
||||
// #define RF95_MOSI 6
|
||||
// #define RF95_NSS 7
|
||||
// #define LORA_SCK 4
|
||||
// #define LORA_MISO 5
|
||||
// #define LORA_MOSI 6
|
||||
// #define LORA_CS 7
|
||||
// #define LORA_DIO0 RADIOLIB_NC
|
||||
// #define LORA_RESET 8
|
||||
// #define LORA_DIO1 10
|
||||
// #define LORA_DIO2 RADIOLIB_NC
|
||||
// #define LORA_BUSY 18
|
||||
// #define SX126X_CS RF95_NSS
|
||||
// #define SX126X_CS LORA_CS
|
||||
// #define SX126X_DIO1 LORA_DIO1
|
||||
// #define SX126X_BUSY LORA_BUSY
|
||||
// #define SX126X_RESET LORA_RESET
|
||||
@@ -47,16 +47,16 @@
|
||||
|
||||
// SX128X 2.4 Ghz LoRa module Not OK - RadioLib issue ? still to confirm
|
||||
// #define USE_SX1280
|
||||
// #define RF95_SCK 4
|
||||
// #define RF95_MISO 5
|
||||
// #define RF95_MOSI 6
|
||||
// #define RF95_NSS 7
|
||||
// #define LORA_SCK 4
|
||||
// #define LORA_MISO 5
|
||||
// #define LORA_MOSI 6
|
||||
// #define LORA_CS 7
|
||||
// #define LORA_DIO0 -1
|
||||
// #define LORA_DIO1 10
|
||||
// #define LORA_DIO2 21
|
||||
// #define LORA_RESET 8
|
||||
// #define LORA_BUSY 1
|
||||
// #define SX128X_CS RF95_NSS
|
||||
// #define SX128X_CS LORA_CS
|
||||
// #define SX128X_DIO1 LORA_DIO1
|
||||
// #define SX128X_BUSY LORA_BUSY
|
||||
// #define SX128X_RESET LORA_RESET
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user