mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge branch 'dev' into trace
# Conflicts: # examples/companion_radio/main.cpp # src/Dispatcher.cpp
This commit is contained in:
commit
9aa2edf9ba
37 changed files with 1558 additions and 390 deletions
|
|
@ -78,9 +78,11 @@ void Dispatcher::checkRecv() {
|
|||
float score;
|
||||
uint32_t air_time;
|
||||
{
|
||||
uint8_t raw[MAX_TRANS_UNIT];
|
||||
uint8_t raw[MAX_TRANS_UNIT+1];
|
||||
int len = _radio->recvRaw(raw, MAX_TRANS_UNIT);
|
||||
if (len > 0) {
|
||||
logRxRaw(_radio->getLastSNR(), _radio->getLastRSSI(), raw, len);
|
||||
|
||||
pkt = _mgr->allocNew();
|
||||
if (pkt == NULL) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): WARNING: received data, no unused packets available!", getLogDateTime());
|
||||
|
|
@ -106,10 +108,17 @@ void Dispatcher::checkRecv() {
|
|||
memcpy(pkt->path, &raw[i], pkt->path_len); i += pkt->path_len;
|
||||
|
||||
pkt->payload_len = len - i; // payload is remainder
|
||||
memcpy(pkt->payload, &raw[i], pkt->payload_len);
|
||||
if (pkt->payload_len > sizeof(pkt->payload)) {
|
||||
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): packet payload too big, payload_len=%d", getLogDateTime(), (uint32_t)pkt->payload_len);
|
||||
_mgr->free(pkt); // put back into pool
|
||||
pkt = NULL;
|
||||
} else {
|
||||
memcpy(pkt->payload, &raw[i], pkt->payload_len);
|
||||
|
||||
score = _radio->packetScore(pkt->_snr = (_radio->getLastSNR() * 4.0f), len);
|
||||
air_time = _radio->getEstAirtimeFor(len);
|
||||
pkt->_snr = _radio->getLastSNR() * 4.0f;
|
||||
score = _radio->packetScore(_radio->getLastSNR(), len);
|
||||
air_time = _radio->getEstAirtimeFor(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -122,6 +131,12 @@ void Dispatcher::checkRecv() {
|
|||
Serial.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d",
|
||||
2 + pkt->path_len + pkt->payload_len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len,
|
||||
(int)pkt->getSNR(), (int)_radio->getLastRSSI(), (int)(score*1000));
|
||||
|
||||
static uint8_t packet_hash[MAX_HASH_SIZE];
|
||||
pkt->calculatePacketHash(packet_hash);
|
||||
Serial.print(" hash=");
|
||||
mesh::Utils::printHex(Serial, packet_hash, MAX_HASH_SIZE);
|
||||
|
||||
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ
|
||||
|| pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
|
||||
Serial.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[1], (uint32_t)pkt->payload[0]);
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ protected:
|
|||
|
||||
virtual DispatcherAction onRecvPacket(Packet* pkt) = 0;
|
||||
|
||||
virtual void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { } // custom hook
|
||||
|
||||
virtual void logRx(Packet* packet, int len, float score) { } // hooks for custom logging
|
||||
virtual void logTx(Packet* packet, int len) { }
|
||||
virtual void logTxFail(Packet* packet, int len) { }
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public:
|
|||
virtual void onBeforeTransmit() { }
|
||||
virtual void onAfterTransmit() { }
|
||||
virtual void reboot() = 0;
|
||||
virtual void powerOff() { /* no op */ }
|
||||
virtual uint8_t getStartupReason() const = 0;
|
||||
virtual bool startOTAUpdate() { return false; } // not supported
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,7 +23,12 @@ public:
|
|||
#ifdef LILYGO_T3S3
|
||||
void begin(HWCDC& serial) { _serial = &serial; }
|
||||
#elif defined(NRF52_PLATFORM)
|
||||
void begin(Adafruit_USBD_CDC& serial) { _serial = &serial; }
|
||||
void begin(Adafruit_USBD_CDC& serial) {
|
||||
_serial = &serial;
|
||||
#ifdef RAK_4631
|
||||
pinMode(WB_IO2, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void begin(HardwareSerial& serial) { _serial = &serial; }
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -247,9 +247,9 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
|
|||
#ifdef MAX_GROUP_CHANNELS
|
||||
int BaseChatMesh::searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel dest[], int max_matches) {
|
||||
int n = 0;
|
||||
for (int i = 0; i < num_channels && n < max_matches; i++) {
|
||||
if (channels[i].hash[0] == hash[0]) {
|
||||
dest[n++] = channels[i];
|
||||
for (int i = 0; i < MAX_GROUP_CHANNELS && n < max_matches; i++) {
|
||||
if (channels[i].channel.hash[0] == hash[0]) {
|
||||
dest[n++] = channels[i].channel;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
|
@ -651,24 +651,61 @@ bool BaseChatMesh::removeContact(ContactInfo& contact) {
|
|||
#ifdef MAX_GROUP_CHANNELS
|
||||
#include <base64.hpp>
|
||||
|
||||
mesh::GroupChannel* BaseChatMesh::addChannel(const char* psk_base64) {
|
||||
ChannelDetails* BaseChatMesh::addChannel(const char* name, const char* psk_base64) {
|
||||
if (num_channels < MAX_GROUP_CHANNELS) {
|
||||
auto dest = &channels[num_channels];
|
||||
|
||||
memset(dest->secret, 0, sizeof(dest->secret));
|
||||
int len = decode_base64((unsigned char *) psk_base64, strlen(psk_base64), dest->secret);
|
||||
memset(dest->channel.secret, 0, sizeof(dest->channel.secret));
|
||||
int len = decode_base64((unsigned char *) psk_base64, strlen(psk_base64), dest->channel.secret);
|
||||
if (len == 32 || len == 16) {
|
||||
mesh::Utils::sha256(dest->hash, sizeof(dest->hash), dest->secret, len);
|
||||
mesh::Utils::sha256(dest->channel.hash, sizeof(dest->channel.hash), dest->channel.secret, len);
|
||||
StrHelper::strncpy(dest->name, name, sizeof(dest->name));
|
||||
num_channels++;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
bool BaseChatMesh::getChannel(int idx, ChannelDetails& dest) {
|
||||
if (idx >= 0 && idx < MAX_GROUP_CHANNELS) {
|
||||
dest = channels[idx];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool BaseChatMesh::setChannel(int idx, const ChannelDetails& src) {
|
||||
static uint8_t zeroes[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
||||
|
||||
if (idx >= 0 && idx < MAX_GROUP_CHANNELS) {
|
||||
channels[idx] = src;
|
||||
if (memcmp(&src.channel.secret[16], zeroes, 16) == 0) {
|
||||
mesh::Utils::sha256(channels[idx].channel.hash, sizeof(channels[idx].channel.hash), src.channel.secret, 16); // 128-bit key
|
||||
} else {
|
||||
mesh::Utils::sha256(channels[idx].channel.hash, sizeof(channels[idx].channel.hash), src.channel.secret, 32); // 256-bit key
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int BaseChatMesh::findChannelIdx(const mesh::GroupChannel& ch) {
|
||||
for (int i = 0; i < MAX_GROUP_CHANNELS; i++) {
|
||||
if (memcmp(ch.secret, channels[i].channel.secret, sizeof(ch.secret)) == 0) return i;
|
||||
}
|
||||
return -1; // not found
|
||||
}
|
||||
#else
|
||||
mesh::GroupChannel* BaseChatMesh::addChannel(const char* psk_base64) {
|
||||
ChannelDetails* BaseChatMesh::addChannel(const char* name, const char* psk_base64) {
|
||||
return NULL; // not supported
|
||||
}
|
||||
bool BaseChatMesh::getChannel(int idx, ChannelDetails& dest) {
|
||||
return false;
|
||||
}
|
||||
bool BaseChatMesh::setChannel(int idx, const ChannelDetails& src) {
|
||||
return false;
|
||||
}
|
||||
int BaseChatMesh::findChannelIdx(const mesh::GroupChannel& ch) {
|
||||
return -1; // not found
|
||||
}
|
||||
#endif
|
||||
|
||||
ContactsIterator BaseChatMesh::startContactsIterator() {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@ struct ConnectionInfo {
|
|||
uint32_t expected_ack;
|
||||
};
|
||||
|
||||
struct ChannelDetails {
|
||||
mesh::GroupChannel channel;
|
||||
char name[32];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief abstract Mesh class for common 'chat' client
|
||||
*/
|
||||
|
|
@ -74,8 +79,8 @@ class BaseChatMesh : public mesh::Mesh {
|
|||
int matching_peer_indexes[MAX_SEARCH_RESULTS];
|
||||
unsigned long txt_send_timeout;
|
||||
#ifdef MAX_GROUP_CHANNELS
|
||||
mesh::GroupChannel channels[MAX_GROUP_CHANNELS];
|
||||
int num_channels;
|
||||
ChannelDetails channels[MAX_GROUP_CHANNELS];
|
||||
int num_channels; // only for addChannel()
|
||||
#endif
|
||||
mesh::Packet* _pendingLoopback;
|
||||
uint8_t temp_buf[MAX_TRANS_UNIT];
|
||||
|
|
@ -89,6 +94,7 @@ protected:
|
|||
{
|
||||
num_contacts = 0;
|
||||
#ifdef MAX_GROUP_CHANNELS
|
||||
memset(channels, 0, sizeof(channels));
|
||||
num_channels = 0;
|
||||
#endif
|
||||
txt_send_timeout = 0;
|
||||
|
|
@ -154,7 +160,10 @@ public:
|
|||
bool addContact(const ContactInfo& contact);
|
||||
int getNumContacts() const { return num_contacts; }
|
||||
ContactsIterator startContactsIterator();
|
||||
mesh::GroupChannel* addChannel(const char* psk_base64);
|
||||
ChannelDetails* addChannel(const char* name, const char* psk_base64);
|
||||
bool getChannel(int idx, ChannelDetails& dest);
|
||||
bool setChannel(int idx, const ChannelDetails& src);
|
||||
int findChannelIdx(const mesh::GroupChannel& ch);
|
||||
|
||||
void loop();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ void CommonCLI::loadPrefs(FILESYSTEM* fs) {
|
|||
file.read((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115
|
||||
file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
|
||||
file.read(pad, 4); // 120
|
||||
file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
|
||||
|
||||
// sanitise bad pref values
|
||||
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
||||
|
|
@ -91,6 +92,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
|||
file.write((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115
|
||||
file.write((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
|
||||
file.write(pad, 4); // 120
|
||||
file.write((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
|
@ -176,6 +178,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->rx_delay_base));
|
||||
} else if (memcmp(config, "txdelay", 7) == 0) {
|
||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->tx_delay_factor));
|
||||
} else if (memcmp(config, "flood.max", 9) == 0) {
|
||||
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max);
|
||||
} else if (memcmp(config, "direct.txdelay", 14) == 0) {
|
||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor));
|
||||
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) {
|
||||
|
|
@ -262,6 +266,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||
} else {
|
||||
strcpy(reply, "Error, cannot be negative");
|
||||
}
|
||||
} else if (memcmp(config, "flood.max ", 10) == 0) {
|
||||
uint8_t m = atoi(&config[10]);
|
||||
if (m <= 64) {
|
||||
_prefs->flood_max = m;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else {
|
||||
strcpy(reply, "Error, max 64");
|
||||
}
|
||||
} else if (memcmp(config, "direct.txdelay ", 15) == 0) {
|
||||
float f = atof(&config[15]);
|
||||
if (f >= 0) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ struct NodePrefs { // persisted to file
|
|||
uint8_t reserved1;
|
||||
uint8_t reserved2;
|
||||
float bw;
|
||||
uint8_t flood_max;
|
||||
};
|
||||
|
||||
class CommonCLICallbacks {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class CustomSX1262 : public SX1262 {
|
|||
CustomSX1262(Module *mod) : SX1262(mod) { }
|
||||
|
||||
bool isReceiving() {
|
||||
uint16_t irq = getIrqStatus();
|
||||
uint16_t irq = getIrqFlags();
|
||||
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class CustomSX1268 : public SX1268 {
|
|||
CustomSX1268(Module *mod) : SX1268(mod) { }
|
||||
|
||||
bool isReceiving() {
|
||||
uint16_t irq = getIrqStatus();
|
||||
uint16_t irq = getIrqFlags();
|
||||
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ public:
|
|||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
|
||||
#ifdef ESP32_CPU_FREQ
|
||||
setCpuFrequencyMhz(ESP32_CPU_FREQ);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_VBAT_READ
|
||||
// battery read support
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
|
|
|
|||
|
|
@ -24,12 +24,22 @@
|
|||
#include <driver/rtc_io.h>
|
||||
|
||||
class HeltecV3Board : public ESP32Board {
|
||||
private:
|
||||
bool adc_active_state;
|
||||
|
||||
public:
|
||||
void begin() {
|
||||
ESP32Board::begin();
|
||||
|
||||
// Auto-detect correct ADC_CTRL pin polarity (different for boards >3.2)
|
||||
pinMode(PIN_ADC_CTRL, INPUT);
|
||||
adc_active_state = !digitalRead(PIN_ADC_CTRL);
|
||||
|
||||
pinMode(PIN_ADC_CTRL, OUTPUT);
|
||||
//pinMode(PIN_VEXT_EN, OUTPUT);
|
||||
digitalWrite(PIN_ADC_CTRL, !adc_active_state); // Initially inactive
|
||||
|
||||
pinMode(PIN_VEXT_EN, OUTPUT);
|
||||
digitalWrite(PIN_VEXT_EN, LOW); // for V3.2 boards
|
||||
|
||||
esp_reset_reason_t reason = esp_reset_reason();
|
||||
if (reason == ESP_RST_DEEPSLEEP) {
|
||||
|
|
@ -66,9 +76,14 @@ public:
|
|||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
// TODO: re-enable this when there is a definite wake-up source pin:
|
||||
// enterDeepSleep(0);
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
analogReadResolution(10);
|
||||
digitalWrite(PIN_ADC_CTRL, PIN_ADC_CTRL_ACTIVE);
|
||||
digitalWrite(PIN_ADC_CTRL, adc_active_state);
|
||||
|
||||
uint32_t raw = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
|
|
@ -76,7 +91,7 @@ public:
|
|||
}
|
||||
raw = raw / 8;
|
||||
|
||||
digitalWrite(PIN_ADC_CTRL, PIN_ADC_CTRL_INACTIVE);
|
||||
digitalWrite(PIN_ADC_CTRL, !adc_active_state);
|
||||
|
||||
return (5.2 * (3.3 / 1024.0) * raw) * 1000;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,10 +52,11 @@ int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) {
|
|||
int err = _radio->readData(bytes, len);
|
||||
if (err != RADIOLIB_ERR_NONE) {
|
||||
MESH_DEBUG_PRINTLN("RadioLibWrapper: error: readData(%d)", err);
|
||||
len = 0;
|
||||
} else {
|
||||
// Serial.print(" readData() -> "); Serial.println(len);
|
||||
n_recv++;
|
||||
}
|
||||
n_recv++;
|
||||
}
|
||||
state = STATE_IDLE; // need another startReceive()
|
||||
return len;
|
||||
|
|
|
|||
69
src/helpers/StationG2Board.h
Normal file
69
src/helpers/StationG2Board.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// LoRa radio module pins for Station G2
|
||||
#define P_LORA_DIO_1 48
|
||||
#define P_LORA_NSS 11
|
||||
#define P_LORA_RESET 21
|
||||
#define P_LORA_BUSY 47
|
||||
#define P_LORA_SCLK 12
|
||||
#define P_LORA_MISO 14
|
||||
#define P_LORA_MOSI 13
|
||||
|
||||
// built-ins
|
||||
//#define PIN_LED_BUILTIN 35
|
||||
//#define PIN_VEXT_EN 36
|
||||
|
||||
#include "ESP32Board.h"
|
||||
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class StationG2Board : public ESP32Board {
|
||||
public:
|
||||
void begin() {
|
||||
ESP32Board::begin();
|
||||
|
||||
esp_reset_reason_t reason = esp_reset_reason();
|
||||
if (reason == ESP_RST_DEEPSLEEP) {
|
||||
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
|
||||
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
|
||||
startup_reason = BD_STARTUP_RX_PACKET;
|
||||
}
|
||||
|
||||
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
|
||||
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
|
||||
}
|
||||
}
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "Station G2";
|
||||
}
|
||||
};
|
||||
|
|
@ -3,8 +3,6 @@
|
|||
#include <MeshCore.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define HAS_T1000e_POWEROFF
|
||||
|
||||
// LoRa and SPI pins
|
||||
#define P_LORA_DIO_1 (32 + 1) // P1.1
|
||||
#define P_LORA_NSS (0 + 12) // P0.12
|
||||
|
|
@ -31,8 +29,13 @@ public:
|
|||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
#ifdef BATTERY_PIN
|
||||
analogReference(AR_INTERNAL_3_0);
|
||||
analogReadResolution(12);
|
||||
float volts = (analogRead(BATTERY_PIN) * ADC_MULTIPLIER * AREF_VOLTAGE) / 4096;
|
||||
|
||||
analogReference(AR_DEFAULT); // put back to default
|
||||
analogReadResolution(10);
|
||||
|
||||
return volts * 1000;
|
||||
#else
|
||||
return 0;
|
||||
|
|
@ -56,7 +59,7 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
void powerOff() {
|
||||
void powerOff() override {
|
||||
#ifdef HAS_GPS
|
||||
digitalWrite(GPS_VRTC_EN, LOW);
|
||||
digitalWrite(GPS_RESET, LOW);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ void T114Board::begin() {
|
|||
Wire.begin();
|
||||
#endif
|
||||
|
||||
#ifdef P_LORA_TX_LED
|
||||
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||
digitalWrite(P_LORA_TX_LED, HIGH);
|
||||
#endif
|
||||
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
delay(10); // give sx1262 some time to power up
|
||||
|
|
|
|||
|
|
@ -28,6 +28,15 @@ public:
|
|||
void begin();
|
||||
uint8_t getStartupReason() const override { return startup_reason; }
|
||||
|
||||
#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
|
||||
|
||||
#define BATTERY_SAMPLES 8
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
|
|
|
|||
63
src/helpers/nrf52/faketecBoard.cpp
Normal file
63
src/helpers/nrf52/faketecBoard.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#include <Arduino.h>
|
||||
#include "faketecBoard.h"
|
||||
|
||||
#include <bluefruit.h>
|
||||
#include <Wire.h>
|
||||
|
||||
static BLEDfu bledfu;
|
||||
|
||||
static void connect_callback(uint16_t conn_handle)
|
||||
{
|
||||
(void)conn_handle;
|
||||
MESH_DEBUG_PRINTLN("BLE client connected");
|
||||
}
|
||||
|
||||
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
(void)conn_handle;
|
||||
(void)reason;
|
||||
|
||||
MESH_DEBUG_PRINTLN("BLE client disconnected");
|
||||
}
|
||||
|
||||
bool faketecBoard::startOTAUpdate() {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
|
||||
|
||||
Bluefruit.begin(1, 0);
|
||||
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
|
||||
Bluefruit.setTxPower(4);
|
||||
// Set the BLE device name
|
||||
Bluefruit.setName("Faketec_OTA");
|
||||
|
||||
Bluefruit.Periph.setConnectCallback(connect_callback);
|
||||
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
|
||||
|
||||
// To be consistent OTA DFU should be added first if it exists
|
||||
bledfu.begin();
|
||||
|
||||
// Set up and start advertising
|
||||
// Advertising packet
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
Bluefruit.Advertising.addTxPower();
|
||||
Bluefruit.Advertising.addName();
|
||||
|
||||
/* Start Advertising
|
||||
- Enable auto advertising if disconnected
|
||||
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
|
||||
- Timeout for fast mode is 30 seconds
|
||||
- Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||
|
||||
For recommended advertising interval
|
||||
https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
*/
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
return true;
|
||||
}
|
||||
69
src/helpers/nrf52/faketecBoard.h
Normal file
69
src/helpers/nrf52/faketecBoard.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include <MeshCore.h>
|
||||
#include <Arduino.h>
|
||||
#include <Wire.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 faketecBoard : public mesh::MainBoard {
|
||||
protected:
|
||||
uint8_t startup_reason;
|
||||
|
||||
public:
|
||||
void begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
|
||||
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
|
||||
Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL);
|
||||
#else
|
||||
Wire.begin();
|
||||
#endif
|
||||
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
uint8_t getStartupReason() const override { return startup_reason; }
|
||||
|
||||
#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_MULTIPLIER * raw);
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "Faketec DIY";
|
||||
}
|
||||
|
||||
void reboot() override {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
bool startOTAUpdate() override;
|
||||
};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include "SSD1306Display.h"
|
||||
|
||||
bool SSD1306Display::begin() {
|
||||
return display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS);
|
||||
return display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS, true, false);
|
||||
}
|
||||
|
||||
void SSD1306Display::turnOn() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue