Merge branch 'meshtastic:master' into master

This commit is contained in:
Mictronics 2024-02-26 15:21:41 +01:00 committed by GitHub
commit 3971f1f050
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 265 additions and 44 deletions

View File

@ -32,7 +32,7 @@ jobs:
- board: meshtastic-diy-v1 - board: meshtastic-diy-v1
- board: rak4631 - board: rak4631
- board: t-echo - board: t-echo
- board: station-g1 - board: station-g2
- board: m5stack-coreink - board: m5stack-coreink
- board: tbeam-s3-core - board: tbeam-s3-core
- board: tlora-t3s3-v1 - board: tlora-t3s3-v1
@ -99,6 +99,7 @@ jobs:
- board: t-watch-s3 - board: t-watch-s3
- board: t-deck - board: t-deck
- board: picomputer-s3 - board: picomputer-s3
- board: station-g2
uses: ./.github/workflows/build_esp32_s3.yml uses: ./.github/workflows/build_esp32_s3.yml
with: with:
board: ${{ matrix.board }} board: ${{ matrix.board }}

View File

@ -6,4 +6,4 @@
"platformio.platformio-ide", "platformio.platformio-ide",
"trunk.io" "trunk.io"
], ],
} }

41
boards/station-g2.json Executable file
View File

@ -0,0 +1,41 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "station-g2"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "BQ Station G2",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://wiki.uniteng.com/en/meshtastic/station-g2",
"vendor": "BQ Consulting"
}

View File

@ -903,8 +903,8 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
if (!lite) { if (!lite) {
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) { if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
if (screen) if (screen)
screen->print("warning: node_db_lite full! erasing oldest entry\n"); screen->print("Warn: node database full!\nErasing oldest entry\n");
LOG_INFO("warning: node_db_lite full! erasing oldest entry\n"); LOG_INFO("Warn: node database full!\nErasing oldest entry\n");
// look for oldest node and erase it // look for oldest node and erase it
uint32_t oldest = UINT32_MAX; uint32_t oldest = UINT32_MAX;
int oldestIndex = -1; int oldestIndex = -1;

View File

@ -332,6 +332,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
if (isRegionUnset && config.lora.region > meshtastic_Config_LoRaConfig_RegionCode_UNSET) { if (isRegionUnset && config.lora.region > meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
config.lora.tx_enabled = true; config.lora.tx_enabled = true;
initRegion(); initRegion();
if (myRegion->dutyCycle < 100) {
config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit
}
if (strcmp(moduleConfig.mqtt.root, default_mqtt_root) == 0) { if (strcmp(moduleConfig.mqtt.root, default_mqtt_root) == 0) {
sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name); sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name);
changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG; changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG;

View File

@ -118,13 +118,16 @@ meshtastic_MeshPacket *PositionModule::allocReply()
// lat/lon are unconditionally included - IF AVAILABLE! // lat/lon are unconditionally included - IF AVAILABLE!
LOG_DEBUG("Sending location with precision %i\n", precision); LOG_DEBUG("Sending location with precision %i\n", precision);
p.latitude_i = localPosition.latitude_i & (INT32_MAX << (32 - precision)); if (precision < 32 && precision > 0) {
p.longitude_i = localPosition.longitude_i & (INT32_MAX << (32 - precision)); p.latitude_i = localPosition.latitude_i & (UINT32_MAX << (32 - precision));
p.longitude_i = localPosition.longitude_i & (UINT32_MAX << (32 - precision));
// We want the imprecise position to be the middle of the possible location, not // We want the imprecise position to be the middle of the possible location, not
if (precision < 31 && precision > 1) {
p.latitude_i += (1 << (31 - precision)); p.latitude_i += (1 << (31 - precision));
p.longitude_i += (1 << (31 - precision)); p.longitude_i += (1 << (31 - precision));
} else {
p.latitude_i = localPosition.latitude_i;
p.longitude_i = localPosition.longitude_i;
} }
p.precision_bits = precision; p.precision_bits = precision;
p.time = localPosition.time; p.time = localPosition.time;

View File

@ -57,7 +57,7 @@ meshtastic_MeshPacket *PaxcounterModule::allocReply()
int32_t PaxcounterModule::runOnce() int32_t PaxcounterModule::runOnce()
{ {
if (moduleConfig.paxcounter.enabled && !config.bluetooth.enabled && !config.network.wifi_enabled) { if (isActive()) {
if (firstTime) { if (firstTime) {
firstTime = false; firstTime = false;
LOG_DEBUG( LOG_DEBUG(
@ -87,4 +87,55 @@ int32_t PaxcounterModule::runOnce()
} }
} }
#if HAS_SCREEN
#ifdef OLED_RU
#include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif
#ifdef OLED_UA
#include "graphics/fonts/OLEDDisplayFontsUA.h"
#endif
// TODO / FIXME: This code is copied from src/graphics/Screen.cpp
// It appears (in slightly variants) also in other modules like
// src/modules/Telemetry/PowerTelemetry.cpp, src/modules/Telemetry/EnvironmentTelemetry.cpp
// and src/modules/CannedMessageModule.cpp
// It probably should go to a common header file for consistency
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
#else
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#ifdef OLED_UA
#define FONT_SMALL ArialMT_Plain_10_UA
#else
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
#endif
#endif
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
#endif
void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
char buffer[50];
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
display->drawString(x + 0, y + 0, "PAX");
libpax_counter_count(&count_from_libpax);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_SMALL);
display->drawStringf(display->getWidth() / 2 + x, 0 + y + 12, buffer, "WiFi: %d\nBLE: %d\nuptime: %ds",
count_from_libpax.wifi_count, count_from_libpax.ble_count, millis() / 1000);
}
#endif // HAS_SCREEN
#endif #endif

View File

@ -23,6 +23,11 @@ class PaxcounterModule : private concurrency::OSThread, public ProtobufModule<me
bool sendInfo(NodeNum dest = NODENUM_BROADCAST); bool sendInfo(NodeNum dest = NODENUM_BROADCAST);
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Paxcount *p) override; virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Paxcount *p) override;
virtual meshtastic_MeshPacket *allocReply() override; virtual meshtastic_MeshPacket *allocReply() override;
bool isActive() { return moduleConfig.paxcounter.enabled && !config.bluetooth.enabled && !config.network.wifi_enabled; }
#if HAS_SCREEN
virtual bool wantUIFrame() override { return isActive(); }
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
#endif
}; };
extern PaxcounterModule *paxcounterModule; extern PaxcounterModule *paxcounterModule;

View File

@ -45,7 +45,8 @@ int32_t StoreForwardModule::runOnce()
this->busy = false; this->busy = false;
} }
} }
} else if ((millis() - lastHeartbeat > (heartbeatInterval * 1000)) && airTime->isTxAllowedChannelUtil(true)) { } else if (this->heartbeat && (millis() - lastHeartbeat > (heartbeatInterval * 1000)) &&
airTime->isTxAllowedChannelUtil(true)) {
lastHeartbeat = millis(); lastHeartbeat = millis();
LOG_INFO("*** Sending heartbeat\n"); LOG_INFO("*** Sending heartbeat\n");
meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero; meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero;
@ -141,25 +142,31 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to, uin
LOG_DEBUG("SF historyQueueCreate - millis %d\n", millis()); LOG_DEBUG("SF historyQueueCreate - millis %d\n", millis());
LOG_DEBUG("SF historyQueueCreate - math %d\n", (millis() - msAgo)); LOG_DEBUG("SF historyQueueCreate - math %d\n", (millis() - msAgo));
*/ */
if (this->packetHistory[i].time && (this->packetHistory[i].time < (millis() - msAgo))) { if (this->packetHistoryTXQueue_size < this->historyReturnMax) {
/* Copy the messages that were received by the router in the last msAgo if (this->packetHistory[i].time && (this->packetHistory[i].time < (millis() - msAgo))) {
to the packetHistoryTXQueue structure. /* Copy the messages that were received by the router in the last msAgo
Client not interested in packets from itself and only in broadcast packets or packets towards it. */ to the packetHistoryTXQueue structure.
if (this->packetHistory[i].from != to && Client not interested in packets from itself and only in broadcast packets or packets towards it. */
(this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == to)) { if (this->packetHistory[i].from != to &&
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time; (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == to)) {
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].to = this->packetHistory[i].to; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].to = this->packetHistory[i].to;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].channel = this->packetHistory[i].channel; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload_size = this->packetHistory[i].payload_size; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].channel = this->packetHistory[i].channel;
memcpy(this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload, this->packetHistory[i].payload, this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload_size =
meshtastic_Constants_DATA_PAYLOAD_LEN); this->packetHistory[i].payload_size;
this->packetHistoryTXQueue_size++; memcpy(this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload, this->packetHistory[i].payload,
*last_request_index = i + 1; // Set to one higher such that we don't send the same message again meshtastic_Constants_DATA_PAYLOAD_LEN);
this->packetHistoryTXQueue_size++;
*last_request_index = i + 1; // Set to one higher such that we don't send the same message again
LOG_DEBUG("*** PacketHistoryStruct time=%d, msg=%s\n", this->packetHistory[i].time, LOG_DEBUG("*** PacketHistoryStruct time=%d, msg=%s\n", this->packetHistory[i].time,
this->packetHistory[i].payload); this->packetHistory[i].payload);
}
} }
} else {
LOG_WARN("*** S&F - Maximum history return reached.\n");
return this->packetHistoryTXQueue_size;
} }
} }
return this->packetHistoryTXQueue_size; return this->packetHistoryTXQueue_size;
@ -174,20 +181,24 @@ void StoreForwardModule::historyAdd(const meshtastic_MeshPacket &mp)
{ {
const auto &p = mp.decoded; const auto &p = mp.decoded;
if (this->packetHistoryCurrent < this->records) { if (this->packetHistoryCurrent == this->records) {
this->packetHistory[this->packetHistoryCurrent].time = millis(); LOG_WARN("*** S&F - PSRAM Full. Starting overwrite now.\n");
this->packetHistory[this->packetHistoryCurrent].to = mp.to; this->packetHistoryCurrent = 0;
this->packetHistory[this->packetHistoryCurrent].channel = mp.channel; this->packetHistoryMax = 0;
this->packetHistory[this->packetHistoryCurrent].from = mp.from; for (auto &i : lastRequest) {
this->packetHistory[this->packetHistoryCurrent].payload_size = p.payload.size; i.second = 0; // Clear the last request index for each client device
memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN); }
this->packetHistoryCurrent++;
this->packetHistoryMax++;
} else {
// TODO: Overwrite the oldest message in the history buffer when it is full.
LOG_WARN("*** S&F - PSRAM Full. Packet is not added to the history.\n");
} }
this->packetHistory[this->packetHistoryCurrent].time = millis();
this->packetHistory[this->packetHistoryCurrent].to = mp.to;
this->packetHistory[this->packetHistoryCurrent].channel = mp.channel;
this->packetHistory[this->packetHistoryCurrent].from = mp.from;
this->packetHistory[this->packetHistoryCurrent].payload_size = p.payload.size;
memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
this->packetHistoryCurrent++;
this->packetHistoryMax++;
} }
meshtastic_MeshPacket *StoreForwardModule::allocReply() meshtastic_MeshPacket *StoreForwardModule::allocReply()
@ -313,7 +324,8 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m
if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) { if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) {
auto &p = mp.decoded; auto &p = mp.decoded;
if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 0x00)) { if (mp.to == nodeDB.getNodeNum() && (p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') &&
(p.payload.bytes[2] == 0x00)) {
LOG_DEBUG("*** Legacy Request to send\n"); LOG_DEBUG("*** Legacy Request to send\n");
// Send the last 60 minutes of messages. // Send the last 60 minutes of messages.
@ -543,6 +555,8 @@ StoreForwardModule::StoreForwardModule()
// send heartbeat advertising? // send heartbeat advertising?
if (moduleConfig.store_forward.heartbeat) if (moduleConfig.store_forward.heartbeat)
this->heartbeat = moduleConfig.store_forward.heartbeat; this->heartbeat = moduleConfig.store_forward.heartbeat;
else
this->heartbeat = false;
// Popupate PSRAM with our data structures. // Popupate PSRAM with our data structures.
this->populatePSRAM(); this->populatePSRAM();

View File

@ -44,7 +44,7 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
StoreForwardModule(); StoreForwardModule();
unsigned long lastHeartbeat = 0; unsigned long lastHeartbeat = 0;
uint32_t heartbeatInterval = default_broadcast_interval_secs; uint32_t heartbeatInterval = 900;
/** /**
Update our local reference of when we last saw that node. Update our local reference of when we last saw that node.

View File

@ -351,11 +351,13 @@ void MQTT::sendSubscriptions()
std::string topic = cryptTopic + channels.getGlobalId(i) + "/#"; std::string topic = cryptTopic + channels.getGlobalId(i) + "/#";
LOG_INFO("Subscribing to %s\n", topic.c_str()); LOG_INFO("Subscribing to %s\n", topic.c_str());
pubSub.subscribe(topic.c_str(), 1); // FIXME, is QOS 1 right? pubSub.subscribe(topic.c_str(), 1); // FIXME, is QOS 1 right?
#ifndef ARCH_NRF52 // JSON is not supported on nRF52, see issue #2804
if (moduleConfig.mqtt.json_enabled == true) { if (moduleConfig.mqtt.json_enabled == true) {
std::string topicDecoded = jsonTopic + channels.getGlobalId(i) + "/#"; std::string topicDecoded = jsonTopic + channels.getGlobalId(i) + "/#";
LOG_INFO("Subscribing to %s\n", topicDecoded.c_str()); LOG_INFO("Subscribing to %s\n", topicDecoded.c_str());
pubSub.subscribe(topicDecoded.c_str(), 1); // FIXME, is QOS 1 right? pubSub.subscribe(topicDecoded.c_str(), 1); // FIXME, is QOS 1 right?
} }
#endif // ARCH_NRF52
} }
} }
#endif #endif
@ -450,6 +452,7 @@ void MQTT::publishQueuedMessages()
publish(topic.c_str(), bytes, numBytes, false); publish(topic.c_str(), bytes, numBytes, false);
#ifndef ARCH_NRF52 // JSON is not supported on nRF52, see issue #2804
if (moduleConfig.mqtt.json_enabled) { if (moduleConfig.mqtt.json_enabled) {
// handle json topic // handle json topic
auto jsonString = this->meshPacketToJson(env->packet); auto jsonString = this->meshPacketToJson(env->packet);
@ -460,6 +463,7 @@ void MQTT::publishQueuedMessages()
publish(topicJson.c_str(), jsonString.c_str(), false); publish(topicJson.c_str(), jsonString.c_str(), false);
} }
} }
#endif // ARCH_NRF52
mqttPool.release(env); mqttPool.release(env);
} }
} }
@ -504,6 +508,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &
publish(topic.c_str(), bytes, numBytes, false); publish(topic.c_str(), bytes, numBytes, false);
#ifndef ARCH_NRF52 // JSON is not supported on nRF52, see issue #2804
if (moduleConfig.mqtt.json_enabled) { if (moduleConfig.mqtt.json_enabled) {
// handle json topic // handle json topic
auto jsonString = this->meshPacketToJson((meshtastic_MeshPacket *)&mp_decoded); auto jsonString = this->meshPacketToJson((meshtastic_MeshPacket *)&mp_decoded);
@ -514,7 +519,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &
publish(topicJson.c_str(), jsonString.c_str(), false); publish(topicJson.c_str(), jsonString.c_str(), false);
} }
} }
#endif // ARCH_NRF52
} else { } else {
LOG_INFO("MQTT not connected, queueing packet\n"); LOG_INFO("MQTT not connected, queueing packet\n");
if (mqttQueue.numFree() == 0) { if (mqttQueue.numFree() == 0) {

View File

@ -133,6 +133,8 @@
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HT62 #define HW_VENDOR meshtastic_HardwareModel_HELTEC_HT62
#elif defined(CHATTER_2) #elif defined(CHATTER_2)
#define HW_VENDOR meshtastic_HardwareModel_CHATTER_2 #define HW_VENDOR meshtastic_HardwareModel_CHATTER_2
#elif defined(STATION_G2)
#define HW_VENDOR meshtastic_HardwareModel_STATION_G2
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -155,4 +157,4 @@
#define LORA_CS 18 #define LORA_CS 18
#endif #endif
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32 // FIXME: may be different on ESP32-S3, etc. #define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32 // FIXME: may be different on ESP32-S3, etc.

View File

@ -0,0 +1,29 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#define USB_VID 0x303a
#define USB_PID 0x1001
#define EXTERNAL_NUM_INTERRUPTS 46
#define NUM_DIGITAL_PINS 48
#define NUM_ANALOG_INPUTS 20
#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
#define digitalPinToInterrupt(p) (((p) <= 48) ? (p) : -1)
#define digitalPinHasPWM(p) (p < 46)
// GPIO48 Reference: https://github.com/espressif/arduino-esp32/pull/8600
// The default Wire will be mapped to Screen and Sensors
static const uint8_t SDA = 5;
static const uint8_t SCL = 6;
// Default SPI will be mapped to Radio
static const uint8_t MISO = 14;
static const uint8_t SCK = 12;
static const uint8_t MOSI = 13;
static const uint8_t SS = 11;
#endif /* Pins_Arduino_h */

View File

@ -0,0 +1,15 @@
[env:station-g2]
extends = esp32s3_base
board = station-g2
board_build.mcu = esp32s3
upload_protocol = esptool
;upload_port = /dev/ttyACM0
upload_speed = 921600
lib_deps =
${esp32s3_base.lib_deps}
build_unflags = -DARDUINO_USB_MODE=1
build_flags =
${esp32s3_base.build_flags} -D STATION_G2 -I variants/station-g2
-DBOARD_HAS_PSRAM
-DSTATION_G2
-DARDUINO_USB_MODE=0

52
variants/station-g2/variant.h Executable file
View File

@ -0,0 +1,52 @@
/*
Board Information: https://wiki.uniteng.com/en/meshtastic/station-g2
*/
// Station G2 may not have GPS installed, but it has a GROVE GPS Socket for Optional GPS Module
#define GPS_RX_PIN 7
#define GPS_TX_PIN 15
// Station G2 has 1.3 inch OLED Screen
#define USE_SH1107_128_64
#define I2C_SDA 5 // I2C pins for this board
#define I2C_SCL 6
#define BUTTON_PIN 38 // This is the Program Button
#define BUTTON_NEED_PULLUP
#define USE_SX1262
#define LORA_MISO 14
#define LORA_SCK 12
#define LORA_MOSI 13
#define LORA_CS 11
#define LORA_RESET 21
#define LORA_DIO1 48
#ifdef USE_SX1262
#define SX126X_CS LORA_CS // FIXME - we really should define LORA_CS instead
#define SX126X_DIO1 LORA_DIO1
#define SX126X_BUSY 47
#define SX126X_RESET LORA_RESET
// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// Ensure the PA does not exceed the saturation output power. More
// Info:https://wiki.uniteng.com/en/meshtastic/station-g2#summary-for-lora-power-amplifier-conduction-test
#define SX126X_MAX_POWER 19
#endif
#define BATTERY_PIN 4 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO4_CHANNEL
#define ADC_MULTIPLIER 4
#define BATTERY_SENSE_SAMPLES 15 // Set the number of samples, It has an effect of increasing sensitivity.
#define BAT_FULLVOLT 8400
#define BAT_EMPTYVOLT 5000
#define BAT_CHARGINGVOLT 8400
#define BAT_NOBATVOLT 4460
#define CELL_TYPE_LION // same curve for liion/lipo
#define NUM_CELLS 2