Merge branch 'master' into apollo

This commit is contained in:
Ben Meadors 2023-12-12 17:39:18 -06:00 committed by GitHub
commit b2a313780f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 477 additions and 128 deletions

View File

@ -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
@ -125,6 +126,7 @@ jobs:
- board: pico
- board: picow
- board: rak11310
- board: senselora_rp2040
uses: ./.github/workflows/build_rpi2040.yml
with:
board: ${{ matrix.board }}
@ -211,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:
[
@ -284,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:

View File

@ -12,10 +12,9 @@ lint:
- checkov@3.1.9
- terrascan@1.18.5
- trivy@0.47.0
- trufflehog@3.63.2-rc0
#- trufflehog@3.63.2-rc0
- taplo@0.8.1
- ruff@0.1.6
- yamllint@1.33.0
- isort@5.12.0
- markdownlint@0.37.0
- oxipng@9.0.0

View File

@ -44,7 +44,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.2.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f

View File

@ -25,7 +25,6 @@ build_src_filter =
lib_deps=
${arduino_base.lib_deps}
jgromes/RadioLib@^6.2.0
lib_ignore =
BluetoothOTA

View File

@ -24,7 +24,6 @@ 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}

View File

@ -2,7 +2,7 @@
[rp2040_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#612de5399d68b359053f1307ed223d400aea975c
extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#d2461a14ad5aa920e44508d236c2f459e3befbf8
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.2
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@ -29,5 +29,4 @@ lib_ignore =
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
jgromes/RadioLib@^6.2.0
rweather/Crypto

View File

@ -34,7 +34,6 @@ upload_protocol = stlink
lib_deps =
${env.lib_deps}
jgromes/RadioLib@^6.2.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

View File

@ -68,6 +68,7 @@ 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
mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159

@ -1 +1 @@
Subproject commit 9148427a3be535c9e3f17e846ecbb64ce04b6521
Subproject commit a34b2c680e2c1c240643c515e57c5532b29c91a7

77
src/AudioThread.h Normal file
View 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

View File

@ -5,6 +5,7 @@
#include "configuration.h"
#include "graphics/Screen.h"
#include "main.h"
#include "modules/ExternalNotificationModule.h"
#include "power.h"
#include <OneButton.h>
@ -205,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();

View File

@ -33,7 +33,7 @@ class PowerFSMThread : public OSThread
powerFSM.trigger(EVENT_SHUTDOWN);
}
return 10;
return 100;
}
};

View File

@ -293,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) {
@ -311,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

View File

@ -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;

View File

@ -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;
}
}

View File

@ -43,9 +43,12 @@ 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/wifi/WiFiAPClient.h"
#include "modules/esp32/StoreForwardModule.h"
#endif
@ -1294,7 +1297,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;

View File

@ -2,6 +2,7 @@
#include "InputBroker.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "modules/ExternalNotificationModule.h"
TouchScreenImpl1 *touchScreenImpl1;
@ -63,7 +64,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:

View File

@ -84,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
@ -122,6 +127,7 @@ ATECCX08A atecc;
#ifdef T_WATCH_S3
Adafruit_DRV2605 drv;
#endif
bool isVibrating = false;
bool eink_found = true;
@ -432,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);
}
@ -576,10 +586,13 @@ 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 || defined(ARCH_RASPBERRY_PI)
@ -656,7 +669,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 {
@ -664,6 +680,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
@ -873,7 +894,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
}
@ -944,4 +964,4 @@ void loop()
mainDelay.delay(delayMsec);
}
// if (didWake) LOG_DEBUG("wake!\n");
}
}

View File

@ -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

View File

@ -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;
}
};

View File

@ -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

View File

@ -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); }

View File

@ -245,9 +245,12 @@ 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;
@ -302,6 +305,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;
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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)
--------------------------------------------------------------------------- */

View File

@ -9,13 +9,11 @@
#include "target_specific.h"
#include <WiFi.h>
#include <WiFiUdp.h>
#ifndef ARCH_RP2040
#ifdef ARCH_ESP32
#include "mesh/http/WebServer.h"
#include <ESPmDNS.h>
#include <esp_wifi.h>
static void WiFiEvent(WiFiEvent_t event);
#else
#include <ESP8266mDNS.h>
#endif
#ifndef DISABLE_NTP
@ -53,6 +51,7 @@ static void onNetworkConnected()
// 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");
@ -62,6 +61,9 @@ static void onNetworkConnected()
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");
@ -89,7 +91,7 @@ static void onNetworkConnected()
syslog.enable();
}
#ifndef ARCH_RP2040
#ifdef ARCH_ESP32
initWebServer();
#endif
initApiServer();
@ -149,6 +151,11 @@ 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
@ -245,7 +252,7 @@ bool initWifi()
}
}
#ifndef ARCH_RP2040
#ifdef ARCH_ESP32
// Called by the Espressif SDK to
static void WiFiEvent(WiFiEvent_t event)
{
@ -279,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");
@ -391,4 +398,4 @@ static void WiFiEvent(WiFiEvent_t event)
uint8_t getWifiDisconnectReason()
{
return wifiDisconnectReason;
}
}

View File

@ -233,7 +233,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,7 +246,8 @@ 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;
@ -483,7 +486,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...");
@ -546,6 +560,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 +685,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result;
}
#endif
#endif

View File

@ -9,6 +9,7 @@ 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,
@ -37,15 +38,29 @@ 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;
@ -63,6 +78,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();
@ -75,6 +96,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
String freetext = ""; // Text Buffer for Freetext Editor
bool destSelect = false; // Freetext Editor Mode
NodeNum dest = NODENUM_BROADCAST;
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 +106,4 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
};
extern CannedMessageModule *cannedMessageModule;
#endif
#endif

View File

@ -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;

View File

@ -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)
}

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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;

View File

@ -121,6 +121,10 @@
#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
// -----------------------------------------------------------------------------

View File

@ -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();
}
}

View File

@ -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

View File

@ -49,4 +49,5 @@ virtualCallInConstructor
passedByValue:*/RedirectablePrint.h
internalAstError:*/CrossPlatformCryptoEngine.cpp
internalAstError:*/CrossPlatformCryptoEngine.cpp
uninitMemberVar:*/AudioThread.h

View File

@ -0,0 +1,50 @@
#pragma once
#define PIN_A0 (26u)
#define PIN_A1 (27u)
#define PIN_A2 (28u)
#define PIN_A3 (29u)
static const uint8_t A0 = PIN_A0;
static const uint8_t A1 = PIN_A1;
static const uint8_t A2 = PIN_A2;
static const uint8_t A3 = PIN_A3;
// LEDs
#define PIN_LED (23u)
#define PIN_LED1 PIN_LED
#define LED_BUILTIN PIN_LED
#define ADC_RESOLUTION 12
// Serial
#define PIN_SERIAL1_TX (0ul)
#define PIN_SERIAL1_RX (1ul)
#define PIN_SERIAL2_TX (4ul)
#define PIN_SERIAL2_RX (5ul)
// SPI
#define PIN_SPI0_MISO (16u)
#define PIN_SPI0_MOSI (19u)
#define PIN_SPI0_SCK (18u)
#define PIN_SPI0_SS (17u)
// Wire
#define PIN_WIRE0_SDA (6u)
#define PIN_WIRE0_SCL (7u)
#define PIN_WIRE1_SDA (-1)
#define PIN_WIRE1_SCL (-1)
#define SERIAL_HOWMANY (3u)
#define SPI_HOWMANY (2u)
#define WIRE_HOWMANY (1u)
static const uint8_t SS = PIN_SPI0_SS;
static const uint8_t MOSI = PIN_SPI0_MOSI;
static const uint8_t MISO = PIN_SPI0_MISO;
static const uint8_t SCK = PIN_SPI0_SCK;
static const uint8_t SDA = PIN_WIRE0_SDA;
static const uint8_t SCL = PIN_WIRE0_SCL;

View File

@ -0,0 +1,13 @@
[env:senselora_rp2040]
extends = rp2040_base
board = rpipico
upload_protocol = picotool
# add our variants files to the include and src paths
build_flags = ${rp2040_base.build_flags}
-DSENSELORA_RP2040
-Ivariants/senselora_rp2040
-DDEBUG_RP2040_PORT=Serial
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}

View File

@ -0,0 +1,26 @@
#define ARDUINO_ARCH_AVR
#define USE_SSD1306
#define BUTTON_PIN 2
#define BUTTON_NEED_PULLUP
#define LED_PIN PIN_LED
#undef BATTERY_PIN
#undef LORA_SCK
#undef LORA_MISO
#undef LORA_MOSI
#undef LORA_CS
#define USE_RF95
#define LORA_SCK PIN_SPI0_SCK
#define LORA_MISO PIN_SPI0_MISO
#define LORA_MOSI PIN_SPI0_MOSI
#define LORA_CS PIN_SPI0_SS
#define LORA_DIO0 21
#define LORA_DIO1 22
#define LORA_DIO2 RADIOLIB_NC
#define LORA_RESET 20

View File

@ -2,8 +2,8 @@
[env:t-deck]
extends = esp32s3_base
board = t-deck
upload_protocol = esp-builtin
debug_tool = esp-builtin
upload_protocol = esptool
#upload_port = COM29
build_flags = ${esp32_base.build_flags}
-DT_DECK
@ -12,4 +12,6 @@ build_flags = ${esp32_base.build_flags}
-Ivariants/t-deck
lib_deps = ${esp32s3_base.lib_deps}
lovyan03/LovyanGFX@^1.1.9
lovyan03/LovyanGFX@^1.1.9
earlephilhower/ESP8266Audio@^1.9.7
earlephilhower/ESP8266SAM@^1.0.1

View File

@ -65,6 +65,12 @@
#define ES7210_LRCK 21
#define ES7210_MCLK 48
// dac / amp
#define HAS_I2S
#define DAC_I2S_BCK 7
#define DAC_I2S_WS 5
#define DAC_I2S_DOUT 6
// LoRa
#define USE_SX1262
#define USE_SX1268

View File

@ -3,6 +3,8 @@
extends = esp32s3_base
board = t-watch-s3
upload_protocol = esptool
upload_speed = 115200
upload_port = /dev/tty.usbmodem3485188D636C1
build_flags = ${esp32_base.build_flags}
-DT_WATCH_S3
@ -12,4 +14,6 @@ build_flags = ${esp32_base.build_flags}
lib_deps = ${esp32s3_base.lib_deps}
lovyan03/LovyanGFX@^1.1.9
lewisxhe/PCF8563_Library@1.0.1
adafruit/Adafruit DRV2605 Library@^1.2.2
adafruit/Adafruit DRV2605 Library@^1.2.2
earlephilhower/ESP8266Audio@^1.9.7
earlephilhower/ESP8266SAM@^1.0.1

View File

@ -30,6 +30,11 @@
#define TFT_BL ST7789_BACKLIGHT_EN
#define HAS_I2S
#define DAC_I2S_BCK 48
#define DAC_I2S_WS 15
#define DAC_I2S_DOUT 46
#define HAS_AXP2101
#define HAS_RTC 1
@ -37,8 +42,6 @@
#define I2C_SDA 10 // For QMC6310 sensors and screens
#define I2C_SCL 11 // For QMC6310 sensors and screens
#define BUTTON_PIN 0
#define BMA4XX_INT 14 // Interrupt for BMA_423 axis sensor
#define HAS_GPS 0