Initial commit: Security Mesh Node

This commit is contained in:
UA1ZBE
2026-07-22 07:56:45 +03:00
commit 965c3e9e30
19 changed files with 1565 additions and 0 deletions

251
src/main.cpp Normal file
View File

@@ -0,0 +1,251 @@
#include <Arduino.h>
#include <Mesh.h>
#include <InternalFileSystem.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/NRF52Board.h>
#include <helpers/SimpleMeshTables.h>
#include <helpers/StaticPoolPacketManager.h>
#include <helpers/ChannelDetails.h>
#include <helpers/ArduinoSerialInterface.h>
#include <Crypto.h>
#include <SHA256.h>
#include "target.h"
using namespace Adafruit_LittleFS_Namespace;
#ifdef PROMICRO
PromicroBoard board;
Module radio_module_obj(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
RADIO_CLASS radio_module(&radio_module_obj);
WRAPPER_CLASS radio_driver(radio_module, board);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#else
NRF52Board board("Security");
Module radio_module_obj(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
RADIO_CLASS radio_module(&radio_module_obj);
WRAPPER_CLASS radio_driver(radio_module, board);
AutoDiscoverRTCClock rtc_clock;
#endif
StdRNG fast_rng;
SimpleMeshTables tables;
OneWire oneWire(PIN_DS18B20);
DallasTemperature ds18b20(&oneWire);
static bool g_armed = false;
static bool g_hall_alert = false;
static bool g_motion_alert = false;
static bool g_relay2_state = false;
static bool g_temp_requested = false;
static unsigned long g_temp_last_request = 0;
static float g_last_temperature = -127.0f;
static unsigned long g_last_hall_alert = 0;
static unsigned long g_last_motion_alert = 0;
static const unsigned long ALERT_COOLDOWN_MS = 600000;
static unsigned long g_boot_time = 0;
static bool g_startup_msg_sent = false;
struct SecurityConfig { uint32_t magic; uint8_t armed; uint8_t relay2; };
static const uint32_t CFG_MAGIC = 0x53454355;
bool saveSecurityConfig() {
SecurityConfig cfg = { CFG_MAGIC, g_armed ? 1 : 0, g_relay2_state ? 1 : 0 };
File f = InternalFS.open(CONFIG_FILE, FILE_O_WRITE);
if (!f) return false;
bool ok = f.write((const uint8_t*)&cfg, sizeof(cfg)) == sizeof(cfg);
f.close(); return ok;
}
bool loadSecurityConfig() {
File f = InternalFS.open(CONFIG_FILE, FILE_O_READ);
if (!f) return false;
SecurityConfig cfg;
if (f.read(&cfg, sizeof(cfg)) != sizeof(cfg)) { f.close(); return false; }
f.close();
if (cfg.magic != CFG_MAGIC) return false;
g_armed = cfg.armed; g_relay2_state = cfg.relay2;
return true;
}
class SecurityMesh : public mesh::Mesh {
public:
mesh::GroupChannel mesh_channel;
bool channel_ready = false;
SecurityMesh(mesh::Radio& r, mesh::RNG& rng, mesh::RTCClock& clock, SimpleMeshTables& t)
: Mesh(r, *new ArduinoMillis(), rng, clock, *new StaticPoolPacketManager(16), t) {}
void setup_channel() {
uint8_t key[32];
SHA256 sha; sha.reset(); sha.update((const uint8_t*)"1234", 4); sha.finalize(key, 32);
memset(mesh_channel.secret, 0, 32);
memcpy(mesh_channel.secret, key, 16);
mesh::Utils::sha256(mesh_channel.hash, sizeof(mesh_channel.hash), mesh_channel.secret, 16);
channel_ready = true;
}
int searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel channels[], int max_matches) override {
if (max_matches > 0 && channel_ready && memcmp(hash, mesh_channel.hash, sizeof(mesh_channel.hash)) == 0) {
channels[0] = mesh_channel;
return 1;
}
return 0;
}
void send_text(const char* text) {
if (!channel_ready) return;
uint32_t ts = rtc_clock.getCurrentTime();
uint8_t buf[256];
memcpy(buf, &ts, 4);
buf[4] = 0;
int tlen = strlen(text);
if (tlen > 200) tlen = 200;
memcpy(buf + 5, text, tlen);
auto pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_TXT, mesh_channel, buf, 5 + tlen);
if (pkt) sendFlood(pkt, (uint32_t)0, (uint8_t)1);
}
void onGroupDataRecv(mesh::Packet* pkt, uint8_t type, const mesh::GroupChannel& channel, uint8_t* data, size_t len) override {
if (type != PAYLOAD_TYPE_GRP_TXT) return;
if (len < 5 || data[4] != 0) return;
for (int i = 0; i < 3; i++) { digitalWrite(PIN_LED_STATUS, HIGH); delay(50); digitalWrite(PIN_LED_STATUS, LOW); delay(50); }
int tlen = len - 5;
if (tlen > 250) tlen = 250;
char text[256];
memcpy(text, data + 5, tlen);
text[tlen] = 0;
int i = tlen; while (i > 0 && text[i-1] == ' ') { text[i-1] = 0; i--; }
for (int i = 0; text[i]; i++) { if (text[i] >= 'A' && text[i] <= 'Z') text[i] += 32; }
const char* cmd = text;
const char* colon = strchr(text, ':');
if (colon && colon[1] == ' ') cmd = colon + 2;
while (*cmd == ' ') cmd++;
if (strcmp(cmd, "help") == 0) {
send_text("help:ohrana on,ohrana off,relay1 on,relay1 off,relay2 on,relay2 off,status,ver,scan,security_conf");
} else if (strcmp(cmd, "ohrana on") == 0) {
g_armed = true; digitalWrite(PIN_RELAY_1, LOW); saveSecurityConfig(); send_text("ohrana on ok");
} else if (strcmp(cmd, "ohrana off") == 0) {
g_armed = false; digitalWrite(PIN_RELAY_1, HIGH); saveSecurityConfig(); send_text("ohrana off ok");
} else if (strcmp(cmd, "relay1 on") == 0) {
digitalWrite(PIN_RELAY_1, LOW); send_text("relay1 on ok");
} else if (strcmp(cmd, "relay1 off") == 0) {
digitalWrite(PIN_RELAY_1, HIGH); send_text("relay1 off ok");
} else if (strcmp(cmd, "relay2 on") == 0) {
g_relay2_state = true; digitalWrite(PIN_RELAY_2, LOW); send_text("relay2 on ok");
} else if (strcmp(cmd, "relay2 off") == 0) {
g_relay2_state = false; digitalWrite(PIN_RELAY_2, HIGH); send_text("relay2 off ok");
} else if (strcmp(cmd, "status") == 0) {
char r[128]; char tb[16]; float t = g_last_temperature;
if (t == -127.0f) strcpy(tb, "N/A"); else snprintf(tb, sizeof(tb), "%+.1fC", t);
snprintf(r, sizeof(r), "status:%s temp:%s hall:%s motion:%s",
g_armed ? "armed" : "off", tb, g_hall_alert ? "trig" : "ok", g_motion_alert ? "trig" : "ok");
send_text(r);
} else if (strcmp(cmd, "ver") == 0) {
char r[64]; snprintf(r, sizeof(r), "build:%s %s", __DATE__, __TIME__); send_text(r);
} else if (strcmp(cmd, "scan") == 0) {
float sum = 0;
for (int j = 0; j < 20; j++) { sum += radio_driver.getCurrentRSSI(); delay(50); }
char r[32]; snprintf(r, sizeof(r), "noise:%.0fdBm", sum / 20); send_text(r);
} else if (strncmp(cmd, "security_conf", 13) == 0) {
const char* nc = cmd + 13; while (*nc == ' ') nc++;
if (strlen(nc) > 0 && strlen(nc) < 32) {
uint8_t key[32];
SHA256 sha; sha.reset(); sha.update((const uint8_t*)nc, strlen(nc)); sha.finalize(key, 32);
memset(mesh_channel.secret, 0, 32);
memcpy(mesh_channel.secret, key, 16);
mesh::Utils::sha256(mesh_channel.hash, sizeof(mesh_channel.hash), mesh_channel.secret, 16);
char r[64]; snprintf(r, sizeof(r), "channel:%s", nc); send_text(r);
} else send_text("bad name");
}
}
};
SecurityMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables);
bool radio_init() {
#ifdef PROMICRO
board.begin();
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
if (radio_module.begin() != RADIOLIB_ERR_NONE) return false;
radio_module.setDio2AsRfSwitch(true);
radio_module.setTCXO(SX126X_DIO3_TCXO_VOLTAGE);
radio_module.setCurrentLimit(SX126X_CURRENT_LIMIT);
radio_driver.setParams(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR);
radio_driver.setTxPower(LORA_TX_POWER);
radio_driver.setRxBoostedGainMode(true);
return true;
}
void setup() {
Serial.begin(115200);
g_boot_time = millis();
NRF_WDT->CONFIG = (WDT_CONFIG_SLEEP_Run << WDT_CONFIG_SLEEP_Pos) | (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos);
NRF_WDT->CRV = (WDT_TIMEOUT_MS * 32768) / 1000;
NRF_WDT->RREN = WDT_RREN_RR0_Enabled << WDT_RREN_RR0_Pos;
NRF_WDT->TASKS_START = 1;
pinMode(PIN_REED, INPUT_PULLUP); pinMode(PIN_PIR, INPUT); ds18b20.begin();
pinMode(PIN_RELAY_1, OUTPUT); pinMode(PIN_RELAY_2, OUTPUT); pinMode(PIN_LED_STATUS, OUTPUT);
digitalWrite(PIN_RELAY_1, HIGH); digitalWrite(PIN_RELAY_2, HIGH); digitalWrite(PIN_LED_STATUS, LOW);
InternalFS.begin();
loadSecurityConfig();
if (g_armed) digitalWrite(PIN_RELAY_1, LOW); else digitalWrite(PIN_RELAY_1, HIGH);
digitalWrite(PIN_RELAY_2, g_relay2_state ? LOW : HIGH);
if (!radio_init()) {
Serial.println("RADIO FAIL");
while (1) { digitalWrite(PIN_LED_STATUS, HIGH); delay(100); digitalWrite(PIN_LED_STATUS, LOW); delay(100); }
}
fast_rng.begin(radio_driver.getRngSeed());
the_mesh.setup_channel();
the_mesh.begin();
Serial.println("OK");
}
void loop() {
NRF_WDT->RR[0] = WDT_RR_RR_Reload;
the_mesh.loop();
rtc_clock.tick();
if (!g_startup_msg_sent && millis() - g_boot_time >= 10000) {
g_startup_msg_sent = true;
char m[80]; snprintf(m, sizeof(m), "poweron %s %s", __DATE__, __TIME__);
the_mesh.send_text(m);
}
unsigned long now = millis();
int reed = digitalRead(PIN_REED);
if (g_armed && reed == HIGH && !g_hall_alert && now - g_last_hall_alert > ALERT_COOLDOWN_MS) {
g_hall_alert = true; g_last_hall_alert = now; the_mesh.send_text("alert:hall");
}
int pir = digitalRead(PIN_PIR);
if (g_armed && pir == HIGH && !g_motion_alert && now - g_last_motion_alert > ALERT_COOLDOWN_MS) {
g_motion_alert = true; g_last_motion_alert = now; the_mesh.send_text("alert:motion");
}
if (g_hall_alert && reed == LOW) g_hall_alert = false;
if (g_motion_alert && pir == LOW) g_motion_alert = false;
if (!g_temp_requested) { ds18b20.requestTemperatures(); g_temp_requested = true; g_temp_last_request = now; }
else if (now - g_temp_last_request > 750) { g_last_temperature = ds18b20.getTempCByIndex(0); g_temp_requested = false; }
if (g_armed) {
static unsigned long lt = 0; static bool ls = false;
if (now - lt > 1000) { lt = now; ls = !ls; digitalWrite(PIN_LED_STATUS, ls); }
} else digitalWrite(PIN_LED_STATUS, LOW);
}

146
src/target.h Normal file
View File

@@ -0,0 +1,146 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#define USE_SX1262
#define RADIO_CLASS CustomSX1262
#define WRAPPER_CLASS CustomSX1262Wrapper
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define SX126X_CURRENT_LIMIT 140
#define SX126X_RX_BOOSTED_GAIN 1
#define LORA_FREQ 868.731018
#define LORA_BW 62.5
#define LORA_SF 7
#define LORA_CR 7
#ifndef LORA_TX_POWER
#define LORA_TX_POWER 22
#endif
#define MAX_LORA_TX_POWER 22
#define PATH_HASH_MODE 0
#ifdef PROMICRO
#ifndef P_LORA_NSS
#define P_LORA_NSS 13
#endif
#ifndef P_LORA_SCLK
#define P_LORA_SCLK 12
#endif
#ifndef P_LORA_MOSI
#define P_LORA_MOSI 14
#endif
#ifndef P_LORA_MISO
#define P_LORA_MISO 15
#endif
#ifndef P_LORA_DIO_1
#define P_LORA_DIO_1 11
#endif
#ifndef P_LORA_RESET
#define P_LORA_RESET 10
#endif
#ifndef P_LORA_BUSY
#define P_LORA_BUSY 16
#endif
#define SX126X_POWER_EN 21
#else
#ifndef P_LORA_NSS
#define P_LORA_NSS 30
#endif
#ifndef P_LORA_SCLK
#define P_LORA_SCLK 29
#endif
#ifndef P_LORA_MOSI
#define P_LORA_MOSI 31
#endif
#ifndef P_LORA_MISO
#define P_LORA_MISO 2
#endif
#ifndef P_LORA_DIO_1
#define P_LORA_DIO_1 7
#endif
#ifndef P_LORA_RESET
#define P_LORA_RESET 6
#endif
#ifndef P_LORA_BUSY
#define P_LORA_BUSY 10
#endif
#endif
#ifdef PROMICRO
#ifndef PIN_REED
#define PIN_REED 0
#endif
#ifndef PIN_PIR
#define PIN_PIR 1
#endif
#ifndef PIN_DS18B20
#define PIN_DS18B20 2
#endif
#else
#ifndef PIN_REED
#define PIN_REED 12
#endif
#ifndef PIN_PIR
#define PIN_PIR 11
#endif
#ifndef PIN_DS18B20
#define PIN_DS18B20 3
#endif
#endif
#ifdef PROMICRO
#ifndef PIN_RELAY_1
#define PIN_RELAY_1 3
#endif
#ifndef PIN_RELAY_2
#define PIN_RELAY_2 4
#endif
#ifndef PIN_LED_STATUS
#define PIN_LED_STATUS 22
#endif
#else
#ifndef PIN_RELAY_1
#define PIN_RELAY_1 4
#endif
#ifndef PIN_RELAY_2
#define PIN_RELAY_2 5
#endif
#ifndef PIN_LED_STATUS
#define PIN_LED_STATUS 13
#endif
#endif
#define CONFIG_FILE "/security.cfg"
#define CHANNEL_FILE "/channel.cfg"
#define WDT_TIMEOUT_MS 10000
#include <RadioLib.h>
#include <helpers/radiolib/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#ifdef PROMICRO
#include <PromicroBoard.h>
#elif defined(HELTEC_T114)
#include <T114Board.h>
#endif
#ifdef PROMICRO
extern PromicroBoard board;
extern RADIO_CLASS radio_module;
extern WRAPPER_CLASS radio_driver;
#elif defined(HELTEC_T114)
extern T114Board board;
extern RADIO_CLASS radio_module;
extern WRAPPER_CLASS radio_driver;
#else
extern RADIO_CLASS radio_module;
extern WRAPPER_CLASS radio_driver;
#endif
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
mesh::LocalIdentity radio_new_identity();

View File

@@ -0,0 +1,59 @@
#include "T114Board.h"
#include <Arduino.h>
#include <Wire.h>
#ifdef NRF52_POWER_MANAGEMENT
// Static configuration for power management
// Values come from variant.h defines
const PowerMgtConfig power_config = {
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN,
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL,
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK
};
void T114Board::initiateShutdown(uint8_t reason) {
#if ENV_INCLUDE_GPS == 1
pinMode(GPS_EN, OUTPUT);
digitalWrite(GPS_EN, LOW);
#endif
digitalWrite(SX126X_POWER_EN, LOW);
bool enable_lpcomp = (reason == SHUTDOWN_REASON_LOW_VOLTAGE ||
reason == SHUTDOWN_REASON_BOOT_PROTECT);
pinMode(PIN_BAT_CTL, OUTPUT);
digitalWrite(PIN_BAT_CTL, enable_lpcomp ? HIGH : LOW);
if (enable_lpcomp) {
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel);
}
enterSystemOff(reason);
}
#endif // NRF52_POWER_MANAGEMENT
void T114Board::begin() {
NRF52Board::begin();
pinMode(PIN_VBAT_READ, INPUT);
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
#endif
Wire.begin();
#ifdef P_LORA_TX_LED
pinMode(P_LORA_TX_LED, OUTPUT);
digitalWrite(P_LORA_TX_LED, HIGH);
#endif
pinMode(SX126X_POWER_EN, OUTPUT);
#ifdef NRF52_POWER_MANAGEMENT
// Boot voltage protection check (may not return if voltage too low)
// We need to call this after we configure SX126X_POWER_EN as output but before we pull high
checkBootVoltage(&power_config);
#endif
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up
}

59
src/variants/T114Board.h Normal file
View File

@@ -0,0 +1,59 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
#include <helpers/NRF52Board.h>
// built-ins
#define PIN_VBAT_READ 4
#define PIN_BAT_CTL 6
#define MV_LSB (3000.0F / 4096.0F) // 12-bit ADC with 3.0V input range
class T114Board : public NRF52BoardDCDC {
protected:
#ifdef NRF52_POWER_MANAGEMENT
void initiateShutdown(uint8_t reason) override;
#endif
public:
T114Board() : NRF52Board("T114_OTA") {}
void begin();
#if defined(P_LORA_TX_LED)
void onBeforeTransmit() override {
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
}
void onAfterTransmit() override {
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
}
#endif
uint16_t getBattMilliVolts() override {
int adcvalue = 0;
analogReadResolution(12);
analogReference(AR_INTERNAL_3_0);
pinMode(PIN_BAT_CTL, OUTPUT); // battery adc can be read only ctrl pin 6 set to high
digitalWrite(PIN_BAT_CTL, 1);
delay(10);
adcvalue = analogRead(PIN_VBAT_READ);
digitalWrite(6, 0);
return (uint16_t)((float)adcvalue * MV_LSB * 4.9);
}
const char* getManufacturerName() const override {
return "Heltec T114";
}
void powerOff() override {
#ifdef LED_PIN
digitalWrite(LED_PIN, HIGH);
#endif
#if ENV_INCLUDE_GPS == 1
pinMode(GPS_EN, OUTPUT);
digitalWrite(GPS_EN, LOW);
#endif
sd_power_system_off();
}
};

View File

@@ -0,0 +1,25 @@
#include <Arduino.h>
#include <Wire.h>
#include "PromicroBoard.h"
void PromicroBoard::begin() {
NRF52Board::begin();
btn_prev_state = HIGH;
pinMode(PIN_VBAT_READ, INPUT);
#ifdef BUTTON_PIN
pinMode(BUTTON_PIN, INPUT_PULLUP);
#endif
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
#endif
Wire.begin();
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up
}

View File

@@ -0,0 +1,79 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
#include <helpers/NRF52Board.h>
#define P_LORA_NSS 13 //P1.13 45
#define P_LORA_DIO_1 11 //P0.10 10
#define P_LORA_RESET 10 //P0.09 9
#define P_LORA_BUSY 16 //P0.29 29
#define P_LORA_MISO 15 //P0.02 2
#define P_LORA_SCLK 12 //P1.11 43
#define P_LORA_MOSI 14 //P1.15 47
#define SX126X_POWER_EN 21 //P0.13 13
#define SX126X_RXEN 2 //P0.17
#define SX126X_TXEN RADIOLIB_NC
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE (1.8f)
#define PIN_VBAT_READ 17
#define ADC_MULTIPLIER (1.815f) // dependent on voltage divider resistors. TODO: more accurate battery tracking
class PromicroBoard : public NRF52BoardDCDC {
protected:
uint8_t btn_prev_state;
float adc_mult = ADC_MULTIPLIER;
public:
PromicroBoard() : NRF52Board("ProMicro_OTA") {}
void begin();
#define BATTERY_SAMPLES 8
uint16_t getBattMilliVolts() override {
analogReadResolution(12);
uint32_t raw = 0;
for (int i = 0; i < BATTERY_SAMPLES; i++) {
raw += analogRead(PIN_VBAT_READ);
}
raw = raw / BATTERY_SAMPLES;
return (adc_mult * raw);
}
bool setAdcMultiplier(float multiplier) override {
if (multiplier == 0.0f) {
adc_mult = ADC_MULTIPLIER;}
else {
adc_mult = multiplier;
}
return true;
}
float getAdcMultiplier() const override {
if (adc_mult == 0.0f) {
return ADC_MULTIPLIER;
} else {
return adc_mult;
}
}
const char* getManufacturerName() const override {
return "ProMicro DIY";
}
int buttonStateChanged() {
#ifdef BUTTON_PIN
uint8_t v = digitalRead(BUTTON_PIN);
if (v != btn_prev_state) {
btn_prev_state = v;
return (v == LOW) ? 1 : -1;
}
#endif
return 0;
}
void powerOff() override {
sd_power_system_off();
}
};

View File

@@ -0,0 +1,15 @@
#include "variant.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
8, 6, 17, 20, 22, 24, 32, 11, 36, 38,
9, 10, 43, 45, 47, 2, 29, 31,
33, 34, 37,
13, 15
};
void initVariant()
{
}

View File

@@ -0,0 +1,82 @@
/*
* variant.h
* Copyright (C) 2023 Seeed K.K.
* MIT License
*/
#pragma once
#include "WVariant.h"
////////////////////////////////////////////////////////////////////////////////
// Low frequency clock source
#define VARIANT_MCK (64000000ul)
//#define USE_LFXO // 32.768 kHz crystal oscillator
#define USE_LFRC // 32.768 kHz RC oscillator
////////////////////////////////////////////////////////////////////////////////
// Power
#define PIN_EXT_VCC (21)
#define EXT_VCC (PIN_EXT_VCC)
#define BATTERY_PIN (17)
#define ADC_RESOLUTION 12
////////////////////////////////////////////////////////////////////////////////
// Number of pins
#define PINS_COUNT (23)
#define NUM_DIGITAL_PINS (23)
#define NUM_ANALOG_INPUTS (3)
#define NUM_ANALOG_OUTPUTS (0)
////////////////////////////////////////////////////////////////////////////////
// UART pin definition
#define PIN_SERIAL1_TX (1)
#define PIN_SERIAL1_RX (0)
////////////////////////////////////////////////////////////////////////////////
// I2C pin definition
#define WIRE_INTERFACES_COUNT 2
#define PIN_WIRE_SDA (6)
#define PIN_WIRE_SCL (7)
#define PIN_WIRE1_SDA (13)
#define PIN_WIRE1_SCL (14)
////////////////////////////////////////////////////////////////////////////////
// SPI pin definition
#define SPI_INTERFACES_COUNT 2
#define PIN_SPI_SCK (2)
#define PIN_SPI_MISO (3)
#define PIN_SPI_MOSI (4)
#define PIN_SPI_NSS (5)
#define PIN_SPI1_SCK (18)
#define PIN_SPI1_MISO (19)
#define PIN_SPI1_MOSI (20)
////////////////////////////////////////////////////////////////////////////////
// Builtin LEDs
#define PIN_LED (22)
#define LED_PIN PIN_LED
#define LED_BLUE PIN_LED
#define LED_BUILTIN PIN_LED
#define LED_STATE_ON 1
////////////////////////////////////////////////////////////////////////////////
// Builtin buttons
#define PIN_BUTTON1 (6)
#define BUTTON_PIN PIN_BUTTON1

15
src/variants/variant.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include "variant.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
0xff, 0xff, 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, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47
};
void initVariant()
{
pinMode(PIN_USER_BTN, INPUT);
}

142
src/variants/variant.h Normal file
View File

@@ -0,0 +1,142 @@
/*
* variant.h
* Copyright (C) 2023 Seeed K.K.
* MIT License
*/
#pragma once
#include "WVariant.h"
////////////////////////////////////////////////////////////////////////////////
// Low frequency clock source
#define USE_LFXO // 32.768 kHz crystal oscillator
#define VARIANT_MCK (64000000ul)
#define WIRE_INTERFACES_COUNT (2)
////////////////////////////////////////////////////////////////////////////////
// Power
#define NRF_APM
#define PIN_3V3_EN (38)
#define BATTERY_PIN (4)
#define ADC_MULTIPLIER (4.90F)
#define ADC_RESOLUTION (14)
#define BATTERY_SENSE_RES (12)
#define AREF_VOLTAGE (3.0)
// Power management boot protection threshold (millivolts)
// Set to 0 to disable boot protection
#define PWRMGT_VOLTAGE_BOOTLOCK 3300 // Won't boot below this voltage (mV)
// LPCOMP wake configuration (voltage recovery from SYSTEMOFF)
// AIN2 = P0.04 = BATTERY_PIN / PIN_VBAT_READ
#define PWRMGT_LPCOMP_AIN 2
#define PWRMGT_LPCOMP_REFSEL 1 // 2/8 VDD (~3.68-4.04V)
////////////////////////////////////////////////////////////////////////////////
// Number of pins
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (1)
#define NUM_ANALOG_OUTPUTS (0)
////////////////////////////////////////////////////////////////////////////////
// UART pin definition
#define PIN_SERIAL1_RX (37)
#define PIN_SERIAL1_TX (39)
#define PIN_SERIAL2_RX (9)
#define PIN_SERIAL2_TX (10)
////////////////////////////////////////////////////////////////////////////////
// I2C pin definition
#define PIN_WIRE_SDA (26) // P0.26
#define PIN_WIRE_SCL (27) // P0.27
#define PIN_WIRE1_SDA (7) // P0.8
#define PIN_WIRE1_SCL (8) // P0.7
////////////////////////////////////////////////////////////////////////////////
// SPI pin definition
#define SPI_INTERFACES_COUNT (2)
#define PIN_SPI_MISO (23)
#define PIN_SPI_MOSI (22)
#define PIN_SPI_SCK (19)
#define PIN_SPI_NSS (24)
////////////////////////////////////////////////////////////////////////////////
// Builtin LEDs
#define LED_BUILTIN (35)
#define PIN_LED LED_BUILTIN
#define LED_RED LED_BUILTIN
#define LED_BLUE (-1) // No blue led, prevents Bluefruit flashing the green LED during advertising
#define LED_PIN LED_BUILTIN
#define LED_STATE_ON LOW
#define PIN_NEOPIXEL (14)
#define NEOPIXEL_NUM (2)
////////////////////////////////////////////////////////////////////////////////
// Builtin buttons
#define PIN_BUTTON1 (42)
#define BUTTON_PIN PIN_BUTTON1
// #define PIN_BUTTON2 (11)
// #define BUTTON_PIN2 PIN_BUTTON2
#define PIN_USER_BTN BUTTON_PIN
#define EXTERNAL_FLASH_DEVICES MX25R1635F
#define EXTERNAL_FLASH_USE_QSPI
////////////////////////////////////////////////////////////////////////////////
// Lora
#define USE_SX1262
#define LORA_CS (24)
#define SX126X_DIO1 (20)
#define SX126X_BUSY (17)
#define SX126X_RESET (25)
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define PIN_SPI1_MISO (43)
#define PIN_SPI1_MOSI (41)
#define PIN_SPI1_SCK (40)
////////////////////////////////////////////////////////////////////////////////
// Buzzer
// #define PIN_BUZZER (46)
////////////////////////////////////////////////////////////////////////////////
// GPS
#define GPS_EN (21)
#define GPS_RESET (38)
#define PIN_GPS_RX (39) // This is for bits going TOWARDS the GPS
#define PIN_GPS_TX (37) // This is for bits going TOWARDS the CPU
////////////////////////////////////////////////////////////////////////////////
// TFT
#define PIN_TFT_SCL (40)
#define PIN_TFT_SDA (41)
#define PIN_TFT_RST (2)
#define PIN_TFT_VDD_CTL (3)
#define PIN_TFT_LEDA_CTL (15)
#define PIN_TFT_CS (11)
#define PIN_TFT_DC (12)