Merge branch 'master' into tft-gui-work

This commit is contained in:
Jonathan Bennett 2024-04-28 19:18:29 -05:00 committed by GitHub
commit 22f6a71e64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 544 additions and 404 deletions

View File

@ -45,6 +45,7 @@ jobs:
- name: build .debpkg
run: |
mkdir -p .debpkg/debian
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
@ -55,6 +56,7 @@ jobs:
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "etc/meshtasticd/config.yaml" > .debpkg/debian/conffiles
- uses: jiro4989/build-deb-action@v3
with:

View File

@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#6fb39b6f94ece9c042141edb4afb91aca94dcaab
platform = https://github.com/meshtastic/platform-native.git#659e49346aa33008b150dfb206b1817ddabc7132
framework = arduino
build_src_filter =
@ -24,7 +24,7 @@ lib_deps =
${env.lib_deps}
${networking_base.lib_deps}
rweather/Crypto@^0.4.0
https://github.com/lovyan03/LovyanGFX.git#a0e0d14df3f6d24e589b77adb524cc3a75dbf8fa ; contains SDL2 fix
https://github.com/lovyan03/LovyanGFX.git#d35e60f269dfecbb18a8cb0fd07d594c2fb7e7a8
build_flags =
${arduino_base.build_flags}
@ -34,4 +34,4 @@ build_flags =
-DPORTDUINO_LINUX_HARDWARE
-lbluetooth
-lgpiod
-lyaml-cpp
-lyaml-cpp

View File

@ -38,6 +38,15 @@ Lora:
# Busy: 20
# Reset: 18
# Module: sx1268 # SX1268-based modules, tested with Ebyte E22 400M33S
# CS: 21
# IRQ: 16
# Busy: 20
# Reset: 18
# TXen: 6
# RXen: 12
# DIO3_TCXO_VOLTAGE: true
# DIO3_TCXO_VOLTAGE: true # the Waveshare Core1262 and others are known to need this setting
# TXen: x # TX and RX enable pins
@ -96,17 +105,21 @@ Display:
# Panel: ILI9341
# CS: 8
# DC: 25
# Backlight: 2
# Width: 320
# Height: 240
# Width: 240
# Height: 320
# Rotate: true
Touchscreen:
### Note, at least for now, the touchscreen must have a CS pin defined, even if you let Linux manage the CS switching.
# Module: STMPE610
# Module: STMPE610 # Option 1 for Adafruit PiTFT 2.8
# CS: 7
# IRQ: 24
# Module: FT5x06 # Option 2 for Adafruit PiTFT 2.8
# IRQ: 24
# I2CAddr: 0x38
# Module: XPT2046 # Waveshare 2.8inch
# CS: 7
# IRQ: 17

View File

@ -78,7 +78,7 @@ lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306
mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#964f75a72cccd6b53cd74e4add1f7a42c6f7344d
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1

@ -1 +1 @@
Subproject commit eade2c6befb65a9c46c5d28ae1e8e24c37a1a3d0
Subproject commit 86640f20db7b9b5be42949d18e8d96ad10d47a68

View File

@ -5,6 +5,16 @@
NCP5623 rgb;
#endif
#ifdef HAS_NEOPIXEL
#include <graphics/NeoPixel.h>
Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_DATA, NEOPIXEL_TYPE);
#endif
#ifdef UNPHONE
#include "unPhone.h"
extern unPhone unphone;
#endif
namespace concurrency
{
class AmbientLightingThread : public concurrency::OSThread
@ -27,15 +37,31 @@ class AmbientLightingThread : public concurrency::OSThread
disable();
return;
}
#endif
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
if (!moduleConfig.ambient_lighting.led_state) {
LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF\n");
disable();
return;
}
LOG_DEBUG("AmbientLightingThread initializing\n");
#ifdef HAS_NCP5623
if (_type == ScanI2C::NCP5623) {
rgb.begin();
#endif
#ifdef RGBLED_RED
pinMode(RGBLED_RED, OUTPUT);
pinMode(RGBLED_GREEN, OUTPUT);
pinMode(RGBLED_BLUE, OUTPUT);
#endif
#ifdef HAS_NEOPIXEL
pixels.begin(); // Initialise the pixel(s)
pixels.clear(); // Set all pixel colors to 'off'
pixels.setBrightness(moduleConfig.ambient_lighting.current);
#endif
setLighting();
#endif
#ifdef HAS_NCP5623
}
#endif
}
@ -43,16 +69,17 @@ class AmbientLightingThread : public concurrency::OSThread
protected:
int32_t runOnce() override
{
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
#ifdef HAS_NCP5623
if (_type == ScanI2C::NCP5623 && moduleConfig.ambient_lighting.led_state) {
#endif
setLighting();
return 30000; // 30 seconds to reset from any animations that may have been running from Ext. Notification
} else {
return disable();
#ifdef HAS_NCP5623
}
#else
return disable();
#endif
#endif
return disable();
}
private:
@ -65,9 +92,36 @@ class AmbientLightingThread : public concurrency::OSThread
rgb.setRed(moduleConfig.ambient_lighting.red);
rgb.setGreen(moduleConfig.ambient_lighting.green);
rgb.setBlue(moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
LOG_DEBUG("Initializing NCP5623 Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue),
0, NEOPIXEL_COUNT);
pixels.show();
LOG_DEBUG("Initializing NeoPixel Ambient lighting w/ brightness(current)=%d, red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red);
analogWrite(RGBLED_GREEN, 255 - moduleConfig.ambient_lighting.green);
analogWrite(RGBLED_BLUE, 255 - moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting RGB Common Anode w/ red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, moduleConfig.ambient_lighting.red);
analogWrite(RGBLED_GREEN, moduleConfig.ambient_lighting.green);
analogWrite(RGBLED_BLUE, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting RGB Common Cathode w/ red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
#ifdef UNPHONE
unphone.rgb(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing unPhone Ambient lighting w/ red=%d, green=%d, blue=%d\n", moduleConfig.ambient_lighting.red,
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
}
};

View File

@ -136,9 +136,12 @@ int32_t ButtonThread::runOnce()
case BUTTON_EVENT_DOUBLE_PRESSED: {
LOG_BUTTON("Double press!\n");
service.refreshLocalMeshNode();
service.sendNetworkPing(NODENUM_BROADCAST, true);
auto sentPosition = service.trySendPosition(NODENUM_BROADCAST, true);
if (screen) {
screen->print("Sent ad-hoc ping\n");
if (sentPosition)
screen->print("Sent ad-hoc position\n");
else
screen->print("Sent ad-hoc nodeinfo\n");
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
}
break;

View File

@ -184,7 +184,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
virtual uint16_t getBattVoltage() override
{
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
if (hasINA()) {
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
return getINAVoltage();
@ -360,7 +360,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
uint32_t last_read_time_ms = 0;
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
uint16_t getINAVoltage()
{
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {

View File

@ -41,9 +41,7 @@ class ScanI2C
BQ24295,
LSM6DS3,
TCA9555,
#ifdef HAS_NCP5623
NCP5623,
#endif
} DeviceType;
// typedef uint8_t DeviceAddress;

View File

@ -223,7 +223,7 @@ int32_t getTZOffset()
now = time(NULL);
gmt = gmtime(&now);
gmt->tm_isdst = -1;
return (int16_t)difftime(now, mktime(gmt));
return (int32_t)difftime(now, mktime(gmt));
}
/**

View File

@ -534,6 +534,10 @@ void EInkDynamicDisplay::checkBusyAsyncRefresh()
return;
}
// Async refresh appears to have stopped, but wasn't caught by onNotify()
else
pollAsyncRefresh(); // Check (and terminate) the async refresh manually
}
// Hold control while an async refresh runs

4
src/graphics/NeoPixel.h Normal file
View File

@ -0,0 +1,4 @@
#ifdef HAS_NEOPIXEL
#include <Adafruit_NeoPixel.h>
extern Adafruit_NeoPixel pixels;
#endif

View File

@ -1,7 +1,6 @@
#include "configuration.h"
#include "main.h"
#if ARCH_PORTDUINO
#include "mesh_bus_spi.h"
#include "platform/portduino/PortduinoGlue.h"
#endif
@ -340,7 +339,7 @@ static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_LCD *_panel_instance;
lgfx::Mesh_Bus_SPI _bus_instance;
lgfx::Bus_SPI _bus_instance;
lgfx::ITouch *_touch_instance;
@ -357,7 +356,7 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance = new lgfx::Panel_ILI9341;
auto buscfg = _bus_instance.config();
buscfg.spi_mode = 0;
_bus_instance.spi_device(DisplaySPI, settingsStrings[displayspidev]);
_bus_instance.spi_device(DisplaySPI);
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
@ -383,6 +382,8 @@ class LGFX : public lgfx::LGFX_Device
_touch_instance = new lgfx::Touch_XPT2046;
} else if (settingsMap[touchscreenModule] == stmpe610) {
_touch_instance = new lgfx::Touch_STMPE610;
} else if (settingsMap[touchscreenModule] == ft5x06) {
_touch_instance = new lgfx::Touch_FT5x06;
}
auto touch_cfg = _touch_instance->config();
@ -394,6 +395,9 @@ class LGFX : public lgfx::LGFX_Device
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
touch_cfg.bus_shared = true;
touch_cfg.offset_rotation = 1;
if (settingsMap[touchscreenI2CAddr] != -1) {
touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr];
}
_touch_instance->config(touch_cfg);
_panel_instance->setTouch(_touch_instance);
@ -711,4 +715,4 @@ bool TFTDisplay::connect()
return true;
}
#endif
#endif

View File

@ -1,188 +0,0 @@
// This code has been copied from LovyanGFX to make the SPI device selectable for touchscreens.
// Ideally this could eventually be an inherited class from BUS_SPI,
// but currently too many internal objects are set private.
#include "configuration.h"
#if ARCH_PORTDUINO
#include "lgfx/v1/misc/pixelcopy.hpp"
#include "main.h"
#include "mesh_bus_spi.h"
#include <Arduino.h>
#include <SPI.h>
namespace lgfx
{
inline namespace v1
{
//----------------------------------------------------------------------------
void Mesh_Bus_SPI::config(const config_t &config)
{
_cfg = config;
if (_cfg.pin_dc >= 0) {
pinMode(_cfg.pin_dc, pin_mode_t::output);
gpio_hi(_cfg.pin_dc);
}
}
bool Mesh_Bus_SPI::init(void)
{
dc_h();
pinMode(_cfg.pin_dc, pin_mode_t::output);
if (SPIName != "")
PrivateSPI->begin(SPIName.c_str());
else
PrivateSPI->begin();
return true;
}
void Mesh_Bus_SPI::release(void)
{
PrivateSPI->end();
}
void Mesh_Bus_SPI::spi_device(HardwareSPI *newSPI, std::string newSPIName)
{
PrivateSPI = newSPI;
SPIName = newSPIName;
}
void Mesh_Bus_SPI::beginTransaction(void)
{
dc_h();
SPISettings setting(_cfg.freq_write, MSBFIRST, _cfg.spi_mode);
PrivateSPI->beginTransaction(setting);
}
void Mesh_Bus_SPI::endTransaction(void)
{
PrivateSPI->endTransaction();
dc_h();
}
void Mesh_Bus_SPI::beginRead(void)
{
PrivateSPI->endTransaction();
// SPISettings setting(_cfg.freq_read, BitOrder::MSBFIRST, _cfg.spi_mode, false);
SPISettings setting(_cfg.freq_read, MSBFIRST, _cfg.spi_mode);
PrivateSPI->beginTransaction(setting);
}
void Mesh_Bus_SPI::endRead(void)
{
PrivateSPI->endTransaction();
beginTransaction();
}
void Mesh_Bus_SPI::wait(void) {}
bool Mesh_Bus_SPI::busy(void) const
{
return false;
}
bool Mesh_Bus_SPI::writeCommand(uint32_t data, uint_fast8_t bit_length)
{
dc_l();
PrivateSPI->transfer((uint8_t *)&data, bit_length >> 3);
dc_h();
return true;
}
void Mesh_Bus_SPI::writeData(uint32_t data, uint_fast8_t bit_length)
{
PrivateSPI->transfer((uint8_t *)&data, bit_length >> 3);
}
void Mesh_Bus_SPI::writeDataRepeat(uint32_t data, uint_fast8_t bit_length, uint32_t length)
{
const uint8_t dst_bytes = bit_length >> 3;
uint32_t limit = (dst_bytes == 3) ? 12 : 16;
auto buf = _flip_buffer.getBuffer(512);
size_t fillpos = 0;
reinterpret_cast<uint32_t *>(buf)[0] = data;
fillpos += dst_bytes;
uint32_t len;
do {
len = ((length - 1) % limit) + 1;
if (limit <= 64)
limit <<= 1;
while (fillpos < len * dst_bytes) {
memcpy(&buf[fillpos], buf, fillpos);
fillpos += fillpos;
}
PrivateSPI->transfer(buf, len * dst_bytes);
} while (length -= len);
}
void Mesh_Bus_SPI::writePixels(pixelcopy_t *param, uint32_t length)
{
const uint8_t dst_bytes = param->dst_bits >> 3;
uint32_t limit = (dst_bytes == 3) ? 12 : 16;
uint32_t len;
do {
len = ((length - 1) % limit) + 1;
if (limit <= 32)
limit <<= 1;
auto buf = _flip_buffer.getBuffer(len * dst_bytes);
param->fp_copy(buf, 0, len, param);
PrivateSPI->transfer(buf, len * dst_bytes);
} while (length -= len);
}
void Mesh_Bus_SPI::writeBytes(const uint8_t *data, uint32_t length, bool dc, bool use_dma)
{
if (dc)
dc_h();
else
dc_l();
PrivateSPI->transfer(const_cast<uint8_t *>(data), length);
if (!dc)
dc_h();
}
uint32_t Mesh_Bus_SPI::readData(uint_fast8_t bit_length)
{
uint32_t res = 0;
bit_length >>= 3;
if (!bit_length)
return res;
int idx = 0;
do {
res |= PrivateSPI->transfer(0) << idx;
idx += 8;
} while (--bit_length);
return res;
}
bool Mesh_Bus_SPI::readBytes(uint8_t *dst, uint32_t length, bool use_dma)
{
do {
dst[0] = PrivateSPI->transfer(0);
++dst;
} while (--length);
return true;
}
void Mesh_Bus_SPI::readPixels(void *dst, pixelcopy_t *param, uint32_t length)
{
uint32_t bytes = param->src_bits >> 3;
uint32_t dstindex = 0;
uint32_t len = 4;
uint8_t buf[24];
param->src_data = buf;
do {
if (len > length)
len = length;
readBytes((uint8_t *)buf, len * bytes, true);
param->src_x = 0;
dstindex = param->fp_copy(dst, dstindex, dstindex + len, param);
length -= len;
} while (length);
}
} // namespace v1
} // namespace lgfx
#endif

View File

@ -1,100 +0,0 @@
#if ARCH_PORTDUINO
/*----------------------------------------------------------------------------/
Lovyan GFX - Graphics library for embedded devices.
Original Source:
https://github.com/lovyan03/LovyanGFX/
Licence:
[FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt)
Author:
[lovyan03](https://twitter.com/lovyan03)
Contributors:
[ciniml](https://github.com/ciniml)
[mongonta0716](https://github.com/mongonta0716)
[tobozo](https://github.com/tobozo)
/----------------------------------------------------------------------------*/
#pragma once
#include <stdint.h>
#include "lgfx/v1/Bus.hpp"
#include "lgfx/v1/platforms/common.hpp"
namespace lgfx
{
inline namespace v1
{
//----------------------------------------------------------------------------
class Mesh_Bus_SPI : public IBus
{
public:
struct config_t {
uint32_t freq_write = 16000000;
uint32_t freq_read = 8000000;
// bool spi_3wire = true;
// bool use_lock = true;
int16_t pin_sclk = -1;
int16_t pin_miso = -1;
int16_t pin_mosi = -1;
int16_t pin_dc = -1;
uint8_t spi_mode = 0;
};
const config_t &config(void) const { return _cfg; }
void config(const config_t &config);
bus_type_t busType(void) const override { return bus_type_t::bus_spi; }
bool init(void) override;
void release(void) override;
void spi_device(HardwareSPI *newSPI, std::string newSPIName);
void beginTransaction(void) override;
void endTransaction(void) override;
void wait(void) override;
bool busy(void) const override;
bool writeCommand(uint32_t data, uint_fast8_t bit_length) override;
void writeData(uint32_t data, uint_fast8_t bit_length) override;
void writeDataRepeat(uint32_t data, uint_fast8_t bit_length, uint32_t count) override;
void writePixels(pixelcopy_t *param, uint32_t length) override;
void writeBytes(const uint8_t *data, uint32_t length, bool dc, bool use_dma) override;
void initDMA(void) {}
void flush(void) {}
void addDMAQueue(const uint8_t *data, uint32_t length) override { writeBytes(data, length, true, true); }
void execDMAQueue(void) {}
uint8_t *getDMABuffer(uint32_t length) override { return _flip_buffer.getBuffer(length); }
void beginRead(void) override;
void endRead(void) override;
uint32_t readData(uint_fast8_t bit_length) override;
bool readBytes(uint8_t *dst, uint32_t length, bool use_dma) override;
void readPixels(void *dst, pixelcopy_t *param, uint32_t length) override;
private:
HardwareSPI *PrivateSPI;
std::string SPIName;
__attribute__((always_inline)) inline void dc_h(void) { gpio_hi(_cfg.pin_dc); }
__attribute__((always_inline)) inline void dc_l(void) { gpio_lo(_cfg.pin_dc); }
config_t _cfg;
FlipBuffer _flip_buffer;
bool _need_wait;
uint32_t _mask_reg_dc;
uint32_t _last_apb_freq = -1;
uint32_t _clkdiv_write;
uint32_t _clkdiv_read;
volatile uint32_t *_gpio_reg_dc_h;
volatile uint32_t *_gpio_reg_dc_l;
};
//----------------------------------------------------------------------------
} // namespace v1
} // namespace lgfx
#endif

View File

@ -627,7 +627,9 @@ void setup()
}
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#if defined(HAS_NEOPIXEL) || defined(UNPHONE) || defined(RGBLED_RED)
ambientLightingThread = new AmbientLightingThread(ScanI2C::DeviceType::NONE);
#elif !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (rgb_found.type != ScanI2C::DeviceType::NONE) {
ambientLightingThread = new AmbientLightingThread(rgb_found.type);
}
@ -839,6 +841,21 @@ void setup()
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio\n");
}
}
} else if (settingsMap[use_sx1268]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1268 radio on SPI port %s\n", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(*LoraSPI, spiSettings);
rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
LOG_ERROR("Failed to find SX1268 radio\n");
delete rIf;
rIf = NULL;
exit(EXIT_FAILURE);
} else {
LOG_INFO("SX1268 Radio init succeeded, using SX1268 radio\n");
}
}
}
#elif defined(HW_SPI1_DEVICE)

View File

@ -267,7 +267,7 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
}
}
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
bool MeshService::trySendPosition(NodeNum dest, bool wantReplies)
{
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
@ -278,6 +278,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
if (positionModule) {
LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel);
positionModule->sendOurPosition(dest, wantReplies, node->channel);
return true;
}
} else {
#endif
@ -286,6 +287,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
nodeInfoModule->sendOurNodeInfo(dest, wantReplies, node->channel);
}
}
return false;
}
void MeshService::sendToPhone(meshtastic_MeshPacket *p)

View File

@ -108,8 +108,9 @@ class MeshService
void reloadOwner(bool shouldSave = true);
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least
/// sends our owner
void sendNetworkPing(NodeNum dest, bool wantReplies = false);
/// sends our nodeinfo
/// returns true if we sent a position
bool trySendPosition(NodeNum dest, bool wantReplies = false);
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb

View File

@ -76,9 +76,12 @@ const RegionInfo regions[] = {
RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false, false),
/*
???
Taiwan, 920-925Mhz, limited to 0.5W indoor or coastal, 1.0W outdoor.
5.8.1 in the Low-power Radio-frequency Devices Technical Regulations
https://www.ncc.gov.tw/english/files/23070/102_5190_230703_1_doc_C.PDF
https://gazette.nat.gov.tw/egFront/e_detail.do?metaid=147283
*/
RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false, false),
RDEF(TW, 920.0f, 925.0f, 100, 0, 27, true, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
@ -586,4 +589,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
sendingPacket = p;
return p->encrypted.size + sizeof(PacketHeader);
}
}

View File

@ -148,6 +148,9 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_TD_LORAC = 60,
/* CDEBYTE EoRa-S3 board using their own MM modules, clone of LILYGO T3S3 */
meshtastic_HardwareModel_CDEBYTE_EORA_S3 = 61,
/* TWC_MESH_V4
Adafruit NRF52840 feather express with SX1262, SSD1306 OLED and NEO6M GPS */
meshtastic_HardwareModel_TWC_MESH_V4 = 62,
/* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */

View File

@ -161,10 +161,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 = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
// this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
this->payload = 0xb7;
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
// this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
}
} else {
// pass the pressed key
@ -233,14 +233,16 @@ int32_t CannedMessageModule::runOnce()
{
if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
temporaryMessage = "";
return INT32_MAX;
}
// LOG_DEBUG("Check status\n");
UIFrameEvent e = {false, true};
if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED)) {
// TODO: might have some feedback of sendig state
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) {
// TODO: might have some feedback of sending state
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
temporaryMessage = "";
e.frameChanged = true;
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
@ -434,7 +436,7 @@ int32_t CannedMessageModule::runOnce()
}
if (screen)
screen->forceDisplay();
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
showTemporaryMessage("GPS Toggled");
break;
// mute (switch off/toggle) external notifications on fn+m
@ -442,18 +444,21 @@ int32_t CannedMessageModule::runOnce()
if (moduleConfig.external_notification.enabled == true) {
if (externalNotificationModule->getMute()) {
externalNotificationModule->setMute(false);
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
showTemporaryMessage("Notifications \nEnabled");
} else {
externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
externalNotificationModule->setMute(true);
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
showTemporaryMessage("Notifications \nDisabled");
}
}
break;
case 0xaf: // fn+space send network ping like double press does
service.refreshLocalMeshNode();
service.sendNetworkPing(NODENUM_BROADCAST, true);
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
if (service.trySendPosition(NODENUM_BROADCAST, true)) {
showTemporaryMessage("Position \nUpdate Sent");
} else {
showTemporaryMessage("Node Info \nUpdate Sent");
}
break;
default:
if (this->cursor == this->freetext.length()) {
@ -542,13 +547,28 @@ int CannedMessageModule::getPrevIndex()
return this->currentMessageIndex - 1;
}
}
void CannedMessageModule::showTemporaryMessage(const String &message)
{
temporaryMessage = message;
UIFrameEvent e = {false, true};
e.frameChanged = true;
notifyObservers(&e);
runState = CANNED_MESSAGE_RUN_STATE_MESSAGE;
// run this loop again in 2 seconds, next iteration will clear the display
setIntervalFromNow(2000);
}
#if !HAS_TFT
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
char buffer[50];
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
if (temporaryMessage.length() != 0) {
LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str());
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage);
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
String displayString;
@ -768,4 +788,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result;
}
#endif
#endif

View File

@ -10,6 +10,7 @@ enum cannedMessageModuleRunState {
CANNED_MESSAGE_RUN_STATE_FREETEXT,
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED,
CANNED_MESSAGE_RUN_STATE_MESSAGE,
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
CANNED_MESSAGE_RUN_STATE_ACTION_UP,
CANNED_MESSAGE_RUN_STATE_ACTION_DOWN,
@ -51,6 +52,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
void handleSetCannedMessageModuleMessages(const char *from_msg);
void showTemporaryMessage(const String &message);
String drawWithCursor(String text, int cursor);
/*
@ -114,7 +117,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
int messagesCount = 0;
unsigned long lastTouchMillis = 0;
String temporaryMessage;
};
extern CannedMessageModule *cannedMessageModule;
#endif
#endif

View File

@ -26,7 +26,18 @@
#ifdef HAS_NCP5623
#include <graphics/RAKled.h>
#endif
#ifdef HAS_NEOPIXEL
#include <graphics/NeoPixel.h>
#endif
#ifdef UNPHONE
#include "unPhone.h"
extern unPhone unphone;
#endif
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
@ -108,27 +119,44 @@ int32_t ExternalNotificationModule::runOnce()
millis()) {
getExternal(2) ? setExternalOff(2) : setExternalOn(2);
}
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
#ifdef HAS_NCP5623
if (rgb_found.type == ScanI2C::NCP5623) {
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
rgb.setColor(red, green, blue);
if (ascending) { // fade in
brightnessIndex++;
if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
ascending = false;
}
} else {
brightnessIndex--; // fade out
}
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
analogWrite(RGBLED_GREEN, 255 - green);
analogWrite(RGBLED_BLUE, 255 - blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, red);
analogWrite(RGBLED_GREEN, green);
analogWrite(RGBLED_BLUE, blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
pixels.show();
#endif
#ifdef UNPHONE
unphone.rgb(red, green, blue);
#endif
if (ascending) { // fade in
brightnessIndex++;
if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
ascending = false;
}
if (brightnessIndex == 0) {
ascending = true;
colorState++; // next color
if (colorState > 7) {
colorState = 1;
}
} else {
brightnessIndex--; // fade out
}
if (brightnessIndex == 0) {
ascending = true;
colorState++; // next color
if (colorState > 7) {
colorState = 1;
}
}
#endif
@ -179,6 +207,9 @@ void ExternalNotificationModule::setExternalOn(uint8_t index)
switch (index) {
case 1:
#ifdef UNPHONE
unphone.vibe(true); // the unPhone's vibration motor is on a i2c GPIO expander
#endif
if (moduleConfig.external_notification.output_vibra)
digitalWrite(moduleConfig.external_notification.output_vibra, true);
break;
@ -197,6 +228,22 @@ void ExternalNotificationModule::setExternalOn(uint8_t index)
rgb.setColor(red, green, blue);
}
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
analogWrite(RGBLED_GREEN, 255 - green);
analogWrite(RGBLED_BLUE, 255 - blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, red);
analogWrite(RGBLED_GREEN, green);
analogWrite(RGBLED_BLUE, blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
pixels.show();
#endif
#ifdef UNPHONE
unphone.rgb(red, green, blue);
#endif
#ifdef T_WATCH_S3
drv.go();
#endif
@ -209,6 +256,9 @@ void ExternalNotificationModule::setExternalOff(uint8_t index)
switch (index) {
case 1:
#ifdef UNPHONE
unphone.vibe(false); // the unPhone's vibration motor is on a i2c GPIO expander
#endif
if (moduleConfig.external_notification.output_vibra)
digitalWrite(moduleConfig.external_notification.output_vibra, false);
break;
@ -222,14 +272,33 @@ void ExternalNotificationModule::setExternalOff(uint8_t index)
break;
}
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
red = 0;
green = 0;
blue = 0;
#ifdef HAS_NCP5623
if (rgb_found.type == ScanI2C::NCP5623) {
red = 0;
green = 0;
blue = 0;
rgb.setColor(red, green, blue);
}
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
analogWrite(RGBLED_GREEN, 255 - green);
analogWrite(RGBLED_BLUE, 255 - blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, red);
analogWrite(RGBLED_GREEN, green);
analogWrite(RGBLED_BLUE, blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
pixels.show();
#endif
#ifdef UNPHONE
unphone.rgb(red, green, blue);
#endif
#endif
#ifdef T_WATCH_S3
drv.stop();
#endif
@ -328,6 +397,21 @@ ExternalNotificationModule::ExternalNotificationModule()
rgb.begin();
rgb.setCurrent(10);
}
#endif
#ifdef RGBLED_RED
pinMode(RGBLED_RED, OUTPUT); // set up the RGB led pins
pinMode(RGBLED_GREEN, OUTPUT);
pinMode(RGBLED_BLUE, OUTPUT);
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255); // with a common anode type, logic is reversed
analogWrite(RGBLED_GREEN, 255); // so we want to initialise with lights off
analogWrite(RGBLED_BLUE, 255);
#endif
#ifdef HAS_NEOPIXEL
pixels.begin(); // Initialise the pixel(s)
pixels.clear(); // Set all pixel colors to 'off'
pixels.setBrightness(moduleConfig.ambient_lighting.current);
#endif
} else {
LOG_INFO("External Notification Module Disabled\n");
@ -509,4 +593,4 @@ void ExternalNotificationModule::handleSetRingtone(const char *from_msg)
if (changed) {
nodeDB->saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig);
}
}
}

View File

@ -54,9 +54,9 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
JSONObject json;
json = json_value->AsObject();
// parse the channel name from the topic string by looking for "json/"
const char *jsonSlash = "json/";
char *ptr = strstr(topic, jsonSlash) + sizeof(jsonSlash) + 1; // set pointer to after "json/"
// parse the channel name from the topic string
// the topic has been checked above for having jsonTopic prefix, so just move past it
char *ptr = topic + jsonTopic.length();
ptr = strtok(ptr, "/") ? strtok(ptr, "/") : ptr; // if another "/" was added, parse string up to that character
meshtastic_Channel sendChannel = channels.getByName(ptr);
// We allow downlink JSON packets only on a channel named "mqtt"
@ -76,6 +76,8 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
p->channel = json["channel"]->AsNumber();
if (json.find("to") != json.end() && json["to"]->IsNumber())
p->to = json["to"]->AsNumber();
if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
p->hop_limit = json["hopLimit"]->AsNumber();
if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) {
memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length());
p->decoded.payload.size = jsonPayloadStr.length();
@ -105,6 +107,8 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
p->channel = json["channel"]->AsNumber();
if (json.find("to") != json.end() && json["to"]->IsNumber())
p->to = json["to"]->AsNumber();
if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
p->hop_limit = json["hopLimit"]->AsNumber();
p->decoded.payload.size =
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes),
&meshtastic_Position_msg, &pos); // make the Data protobuf from position
@ -548,7 +552,10 @@ void MQTT::perhapsReportToMap()
} else {
if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) {
last_report_to_map = millis();
LOG_WARN("MQTT Map reporting is enabled, but precision is 0 or no position available.\n");
if (map_position_precision == 0)
LOG_WARN("MQTT Map reporting is enabled, but precision is 0\n");
if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)
LOG_WARN("MQTT Map reporting is enabled, but no position available.\n");
return;
}
@ -904,6 +911,7 @@ bool MQTT::isValidJsonEnvelope(JSONObject &json)
{
// if "sender" is provided, avoid processing packets we uplinked
return (json.find("sender") != json.end() ? (json["sender"]->AsString().compare(owner.id) != 0) : true) &&
(json.find("hopLimit") != json.end() ? json["hopLimit"]->IsNumber() : true) && // hop limit should be a number
(json.find("from") != json.end()) && json["from"]->IsNumber() &&
(json["from"]->AsNumber() == nodeDB->getNodeNum()) && // only accept message if the "from" is us
(json.find("type") != json.end()) && json["type"]->IsString() && // should specify a type

View File

@ -52,6 +52,8 @@
#define HW_VENDOR meshtastic_HardwareModel_CANARYONE
#elif defined(NORDIC_PCA10059)
#define HW_VENDOR meshtastic_HardwareModel_NRF52840_PCA10059
#elif defined(TWC_MESH_V4)
#define HW_VENDOR meshtastic_HardwareModel_TWC_MESH_V4
#elif defined(PRIVATE_HW) || defined(FEATHER_DIY)
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
#else
@ -110,4 +112,4 @@
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
// No serial ports on this board - ONLY use segger in memory console
#define USE_SEGGER
#endif
#endif

View File

@ -136,6 +136,7 @@ void portduinoSetup()
settingsMap[use_sx1262] = false;
settingsMap[use_rf95] = false;
settingsMap[use_sx1280] = false;
settingsMap[use_sx1268] = false;
if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1262") {
settingsMap[use_sx1262] = true;
@ -143,6 +144,8 @@ void portduinoSetup()
settingsMap[use_rf95] = true;
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1280") {
settingsMap[use_sx1280] = true;
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1268") {
settingsMap[use_sx1268] = true;
}
settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<bool>(false);
@ -221,6 +224,7 @@ void portduinoSetup()
settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as<int>(-1);
settingsMap[touchscreenBusFrequency] = yamlConfig["Touchscreen"]["BusFrequency"].as<int>(1000000);
settingsMap[touchscreenRotate] = yamlConfig["Touchscreen"]["Rotate"].as<int>(-1);
settingsMap[touchscreenI2CAddr] = yamlConfig["Touchscreen"]["I2CAddr"].as<int>(-1);
if (yamlConfig["Touchscreen"]["spidev"]) {
settingsStrings[touchscreenspidev] = "/dev/" + yamlConfig["Touchscreen"]["spidev"].as<std::string>("");
}
@ -332,4 +336,4 @@ int initGPIOPin(int pinNum, std::string gpioChipName)
std::cout << "Warning, cannot claim pin " << gpio_name << (p ? p.__cxa_exception_type()->name() : "null") << std::endl;
return ERRNO_DISABLED;
}
}
}

View File

@ -13,6 +13,7 @@ enum configNames {
dio3_tcxo_voltage,
use_rf95,
use_sx1280,
use_sx1268,
user,
gpiochip,
spidev,
@ -21,6 +22,7 @@ enum configNames {
touchscreenModule,
touchscreenCS,
touchscreenIRQ,
touchscreenI2CAddr,
touchscreenBusFrequency,
touchscreenRotate,
touchscreenspidev,

View File

@ -29,10 +29,7 @@ const uint32_t g_ADigitalPinMap[] = {
void initVariant()
{
// LED1 & LED2
// LED1
pinMode(PIN_LED1, OUTPUT);
ledOff(PIN_LED1);
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
}
}

View File

@ -43,16 +43,12 @@ extern "C" {
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (0 + 12) // Blue LED P1.12
#define PIN_LED2 (0 + 6) // Built in Green P0.06
// Green Built in LED1
// #define PIN_LED1 (0 + 6) // LED1 P1.15
// RGB NeoPixel LED2
// #define PIN_LED1 (0 + 8) Red
// #define PIN_LED1 (32 + 9) Green
// #define PIN_LED1 (0 + 12) Blue
#define PIN_LED1 (0 + 6) // Built in Green P0.06
#define PIN_LED2 (0 + 6) // Just here for completeness
#define RGBLED_RED (0 + 8) // Red of RGB P0.08
#define RGBLED_GREEN (32 + 9) // Green of RGB P1.09
#define RGBLED_BLUE (0 + 12) // Blue of RGB P0.12
#define RGBLED_CA // comment out this line if you have a common cathode type, as defined use common anode logic
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
@ -168,4 +164,4 @@ static const uint8_t SCK = PIN_SPI_SCK;
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif
#endif

View File

@ -0,0 +1,10 @@
[env:TWC_mesh_v4]
extends = nrf52840_base
board = TWC_mesh_v4
board_level = extra
build_flags = ${nrf52840_base.build_flags} -I variants/TWC_mesh_v4 -D TWC_mesh_v4 -L".pio\libdeps\TWC_mesh_v4\BSEC2 Software Library\src\cortex-m4\fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/TWC_mesh_v4>
lib_deps =
${nrf52840_base.lib_deps}
zinggjm/GxEPD2@^1.4.9
debug_tool = jlink

View File

@ -0,0 +1,38 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "variant.h"
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
// P0
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
// P1
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
void initVariant()
{
// LED1 & LED2
pinMode(PIN_LED1, OUTPUT);
ledOff(PIN_LED1);
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
}

View File

@ -0,0 +1,133 @@
#ifndef _VARIANT_TWC_MESH_V4_
#define _VARIANT_TWC_MESH_V4_
#define PCA10059
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
// define USE_LFRC // Board uses RC for LF
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Number of pins defined in PinDescription array
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (6)
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (32 + 10) // Blue LED P1.10
#define PIN_LED2 (32 + 15) // Built in Green P1.15
// RGB NeoPixel LED2
// #define PIN_LED1 (0 + 8) Red
// #define PIN_LED1 (32 + 9) Green
// #define PIN_LED1 (0 + 12) Blue
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1
#define LED_BLUE PIN_LED2
#define LED_STATE_ON 0 // State when LED is litted
/*
* Buttons
*/
#define PIN_BUTTON1 (32 + 2) // BTN_DN P1.02 Built in button
/*
* Analog pins
*/
#define PIN_A0 (0 + 29) // using VDIV (A6 / P0.29)
static const uint8_t A0 = PIN_A0;
#define ADC_RESOLUTION 14
// Other pins
#define PIN_AREF (-1) // AREF Not yet used
static const uint8_t AREF = PIN_AREF;
/*
* Serial interfaces
*/
#define PIN_SERIAL1_RX (0 + 24)
#define PIN_SERIAL1_TX (0 + 25)
// Connected to Jlink CDC
#define PIN_SERIAL2_RX (-1)
#define PIN_SERIAL2_TX (-1)
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 1
#define PIN_SPI_MISO (0 + 15) // MISO P0.15
#define PIN_SPI_MOSI (0 + 13) // MOSI P0.13
#define PIN_SPI_SCK (0 + 14) // SCK P0.14
static const uint8_t SS = (0 + 6); // LORA_CS P0.6
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
////#define USE_EINK
#define USE_SSD1306
/*
* Wire Interfaces
*/
#define WIRE_INTERFACES_COUNT 1
#define PIN_WIRE_SDA (0 + 12) // SDA P0.12
#define PIN_WIRE_SCL (0 + 11) // SCL P0.11
// NiceRF 868 LoRa module
#define USE_SX1262
#define USE_LLCC68
#define SX126X_CS (0 + 6) // LORA_CS P0.06
#define SX126X_DIO1 (0 + 7) // DIO1 P0.07
#define SX126X_BUSY (0 + 26) // LORA_BUSY P0.26
#define SX126X_RESET (0 + 27) // LORA_RESET P0.27
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define PIN_GPS_EN (-1)
#define PIN_GPS_PPS (-1) // Pulse per second input from the GPS
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX
// Battery
// The battery sense is hooked to pin A6 (0.29)
#define BATTERY_PIN PIN_A0
// and has 12 bit resolution
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER (2.0F)
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif

View File

@ -15,4 +15,4 @@ upload_protocol = esptool
upload_speed = 460800
lib_deps =
${esp32_base.lib_deps}
makuna/NeoPixelBus@^2.7.1
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@ -1,5 +1,4 @@
// https://betafpv.com/products/elrs-micro-tx-module
#include <NeoPixelBus.h>
// 0.96" OLED
#define I2C_SDA 22
@ -15,7 +14,11 @@
#define LORA_CS 5
#define RF95_FAN_EN 17
#define LED_PIN 16 // This is a LED_WS2812 not a standard LED
// #define LED_PIN 16 // This is a LED_WS2812 not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 16 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define BUTTON_PIN 25
#define BUTTON_NEED_PULLUP
@ -31,4 +34,4 @@
#define SX128X_TXEN 26
#define SX128X_RXEN 27
#define SX128X_RESET LORA_RESET
#define SX128X_MAX_POWER 13
#define SX128X_MAX_POWER 13

View File

@ -22,4 +22,4 @@ build_flags = ${esp32_base.build_flags}
lib_deps = ${esp32s3_base.lib_deps}
zinggjm/GxEPD2@^1.5.3
;adafruit/Adafruit NeoPixel@^1.10.7
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@ -10,6 +10,10 @@
// #define LED_PIN PIN_LED
// Board has RGB LED 21
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 21 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
// The usbPower state is revered ?
// DEBUG | ??:??:?? 365 [Power] Battery: usbPower=0, isCharging=0, batMv=4116, batPct=90

View File

@ -1,24 +1,16 @@
#define I2C_SDA 1
#define I2C_SCL 0
#define BUTTON_PIN 9
#define BUTTON_NEED_PULLUP
// LED flashes brighter
// LED pin on HT-DEV-ESP_V2 and HT-DEV-ESP_V3
// https://resource.heltec.cn/download/HT-CT62/HT-CT62_Reference_Design.pdf
#define LED_PIN 18 // LED
#define LED_INVERTED 1
// https://resource.heltec.cn/download/HT-DEV-ESP/HT-DEV-ESP_V3_Sch.pdf
#define LED_PIN 2 // LED
#define LED_INVERTED 0
#define HAS_SCREEN 1
#define HAS_SCREEN 0
#define HAS_GPS 0
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#undef LORA_SCK
#undef LORA_MISO
#undef LORA_MOSI
#undef LORA_CS
#define USE_SX1262
#define LORA_SCK 10
#define LORA_MISO 6

View File

@ -20,4 +20,5 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/lora_relay_v1>
lib_deps =
${nrf52840_base.lib_deps}
sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0
bodmer/TFT_eSPI@^2.4.76
bodmer/TFT_eSPI@^2.4.76
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@ -44,7 +44,11 @@ extern "C" {
// LEDs
#define PIN_LED1 (3)
#define PIN_LED2 (4)
#define PIN_NEOPIXEL (8)
// #define PIN_NEOPIXEL (8)
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 8 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2

View File

@ -23,3 +23,4 @@ lib_deps =
${nrf52840_base.lib_deps}
sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0
bodmer/TFT_eSPI@^2.4.76
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@ -61,7 +61,12 @@ extern "C" {
// LEDs
#define PIN_LED1 (3)
#define PIN_LED2 (4)
#define PIN_NEOPIXEL (8)
// #define PIN_NEOPIXEL (8)
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 8 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define PIN_BUZZER (40)
#define LED_BUILTIN PIN_LED1

View File

@ -13,7 +13,7 @@ platform_packages =
lib_deps =
${esp32_base.lib_deps}
zinggjm/GxEPD2@^1.5.1
adafruit/Adafruit NeoPixel@^1.10.7
adafruit/Adafruit NeoPixel @ ^1.12.0
build_unflags = -DARDUINO_USB_MODE=1
build_flags =
;${esp32_base.build_flags} -D MY_ESP32S3_DIY -I variants/my_esp32s3_diy_eink
@ -24,4 +24,4 @@ build_flags =
-DEINK_HEIGHT=128
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-DARDUINO_USB_MODE=0
-DARDUINO_USB_MODE=0

View File

@ -12,6 +12,10 @@
#define I2C_SCL 17 // 2
// #define LED_PIN 38 // This is a RGB LED not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define BUTTON_PIN 0 // This is the BOOT button
#define BUTTON_NEED_PULLUP

View File

@ -12,11 +12,11 @@ platform_packages =
tool-esptoolpy@^1.40500.0
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit NeoPixel@^1.10.7
adafruit/Adafruit NeoPixel @ ^1.12.0
build_unflags = -DARDUINO_USB_MODE=1
build_flags =
;${esp32_base.build_flags} -D MY_ESP32S3_DIY -I variants/my_esp32s3_diy_oled
${esp32_base.build_flags} -D PRIVATE_HW -I variants/my_esp32s3_diy_oled
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-DARDUINO_USB_MODE=0
-DARDUINO_USB_MODE=0

View File

@ -12,6 +12,10 @@
#define I2C_SCL 17 // 2
// #define LED_PIN 38 // This is a RGB LED not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define BUTTON_PIN 0 // This is the BOOT button
#define BUTTON_NEED_PULLUP
@ -53,4 +57,4 @@
// #define PIN_EINK_DC 1
// #define PIN_EINK_RES (-1)
// #define PIN_EINK_SCLK 5
// #define PIN_EINK_MOSI 6
// #define PIN_EINK_MOSI 6

View File

@ -13,6 +13,7 @@ build_unflags =
-D ARDUINO_USB_MODE
build_flags = ${esp32_base.build_flags}
;-D BOARD_HAS_PSRAM // what's up with this - doesn't seem to be recognised at boot
-D UNPHONE
-I variants/unphone
-D ARDUINO_USB_MODE=0
@ -27,4 +28,5 @@ build_src_filter = ${esp32_base.build_src_filter} +<../variants/unphone>
lib_deps = ${esp32s3_base.lib_deps}
lovyan03/LovyanGFX @ ^1.1.8
https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic @ ^9.0.0
https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic @ ^9.0.0
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@ -10,6 +10,7 @@ void initVariant()
unphone.printWakeupReason(); // what woke us up? (stored, not printed :|)
unphone.checkPowerSwitch(); // if power switch is off, shutdown
unphone.backlight(false); // setup backlight and make sure its off
unphone.expanderPower(true); // enable power to expander / hat / sheild
for (int i = 0; i < 3; i++) { // buzz a bit
unphone.vibe(true);

View File

@ -48,7 +48,7 @@
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define HAS_SDCARD 1
// #define HAS_SDCARD 1 // causes hang if defined
#define SDCARD_CS 43
#define LED_PIN 13 // the red part of the RGB LED

View File

@ -181,6 +181,7 @@ static const uint8_t SCL = PIN_WIRE_SCL;
#define BAT_READ \
14 // P0_14 = 14 Reads battery voltage from divider on signal board. (PIN_VBAT is reading voltage divider on XIAO and is
// program pin 32 / or P0.31)
#define BATTERY_SENSE_RESOLUTION_BITS 10
#define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED
#define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge

View File

@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 3
build = 7
build = 8