Skip to content

Initial Meshpocket Support #498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions boards/heltec_meshpocket.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x4405"],
["0x239A", "0x0029"],
["0x239A", "0x002A"]
],
"usb_product": "HT-n5262",
"mcu": "nrf52840",
"variant": "heltec_mesh_pocket",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": ["jlink"],
"svd_path": "nrf52840.svd",
"openocd_target": "nrf52840-mdk-rs"
},
"frameworks": ["arduino"],
"name": "Heltec nrf (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://heltec.org/project/meshpocket/",
"vendor": "Heltec"
}

66 changes: 66 additions & 0 deletions src/helpers/ui/SSD1680Display.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "SSD1680Display.h"

bool SSD1680Display::begin() {
display.begin(true);
return true;
}

// eInk displays are usually kept in deep sleep
// This means that drawing reinitializes them anyways.
void SSD1680Display::turnOn() {
}

void SSD1680Display::turnOff() {
}

void SSD1680Display::clear() {
display.clearDisplay();
}

void SSD1680Display::startFrame(Color bkg) {
display.clearBuffer();
_color = EPD_BLACK;
display.setTextColor(_color);
display.setTextSize(1);
display.cp437(true); // Use full 256 char 'Code Page 437' font
}

void SSD1680Display::setTextSize(int sz) {
display.setTextSize(sz);
}

void SSD1680Display::setColor(Color c) {
_color = (c != 0) ? EPD_BLACK : EPD_WHITE;
display.setTextColor(_color);
}

void SSD1680Display::setCursor(int x, int y) {
display.setCursor(x, y);
}

void SSD1680Display::print(const char* str) {
display.print(str);
}

void SSD1680Display::fillRect(int x, int y, int w, int h) {
display.fillRect(x, y, w, h, _color);
}

void SSD1680Display::drawRect(int x, int y, int w, int h) {
display.drawRect(x, y, w, h, _color);
}

void SSD1680Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
display.drawBitmap(x, y, bits, w, h, EPD_BLACK);
}

uint16_t SSD1680Display::getTextWidth(const char* str) {
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
return w;
}

void SSD1680Display::endFrame() {
display.display();
}
32 changes: 32 additions & 0 deletions src/helpers/ui/SSD1680Display.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include "DisplayDriver.h"
#include <drivers/Adafruit_SSD1680.h>


class SSD1680Display : public DisplayDriver {
Adafruit_SSD1680 display;
bool _display_on;
uint32_t _last_full_update;
uint8_t _partial_update_count;
uint8_t _color;

public:
SSD1680Display() : DisplayDriver(250, 122), display(250, 122, PIN_DISPLAY_DC, PIN_DISPLAY_RST, PIN_DISPLAY_CS, -1, PIN_DISPLAY_BUSY, &SPI1) { _display_on = false; _last_full_update = 0; _partial_update_count = -1;};
bool begin();

bool isOn() override { return true; }
void turnOn() override;
void turnOff() override;
void clear() override;
void startFrame(Color bkg = DARK) override;
void setTextSize(int sz) override;
void setColor(Color c) override;
void setCursor(int x, int y) override;
void print(const char* str) override;
void fillRect(int x, int y, int w, int h) override;
void drawRect(int x, int y, int w, int h) override;
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override;
uint16_t getTextWidth(const char* str) override;
void endFrame() override;
};
35 changes: 35 additions & 0 deletions variants/heltec_meshpocket/MeshPocket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <Arduino.h>
#include "MeshPocket.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");
}

void HeltecMeshPocket::begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
Serial.begin(9600);
pinMode(PIN_VBAT_READ, INPUT);

pinMode(PIN_USER_BTN, INPUT);

#ifdef P_LORA_TX_LED
pinMode(P_LORA_TX_LED, OUTPUT);
digitalWrite(P_LORA_TX_LED, HIGH);
#endif
}
55 changes: 55 additions & 0 deletions variants/heltec_meshpocket/MeshPocket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include <MeshCore.h>
#include <Arduino.h>

#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE 1.8

// built-ins
#define PIN_VBAT_READ 29
#define PIN_BAT_CTL 34
#define MV_LSB (3000.0F / 4096.0F) // 12-bit ADC with 3.0V input range

class HeltecMeshPocket : public mesh::MainBoard {
protected:
uint8_t startup_reason;

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

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 set to high
pinMode(PIN_VBAT_READ, INPUT);
digitalWrite(PIN_BAT_CTL, 1);

delay(10);
adcvalue = analogRead(PIN_VBAT_READ);
digitalWrite(PIN_BAT_CTL, 0);

return (uint16_t)((float)adcvalue * MV_LSB * 4.9);
}

const char* getManufacturerName() const override {
return "Heltec MeshPocket";
}

void reboot() override {
NVIC_SystemReset();
}

bool startOTAUpdate(const char* id, char reply[]) override;
};
42 changes: 42 additions & 0 deletions variants/heltec_meshpocket/platformio.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[Heltec_meshpocket]
extends = nrf52840_base
board = heltec_meshpocket
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_6.1.1_API/include
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
-I variants/heltec_meshpocket
-I src/helpers/ui
-D HELTEC_MESHPOCKET
-D P_LORA_TX_LED=13
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${nrf52840_base.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/*.cpp>
+<../variants/heltec_meshpocket>
lib_deps =
${nrf52840_base.lib_deps}
adafruit/Adafruit EPD @ 4.6.1
debug_tool = jlink
upload_protocol = nrfutil

[env:Heltec_MeshPocket_companion_radio_ble]
extends = Heltec_meshpocket
build_flags =
${Heltec_meshpocket.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456 ; dynamic, random PIN
-D OFFLINE_QUEUE_SIZE=256
-D DISPLAY_CLASS=SSD1680Display
build_src_filter = ${Heltec_meshpocket.build_src_filter}
+<helpers/ui/SSD1680Display.cpp>
+<../examples/companion_radio>
lib_deps =
${Heltec_meshpocket.lib_deps}
densaugeo/base64 @ ~1.4.0
67 changes: 67 additions & 0 deletions variants/heltec_meshpocket/target.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>

HeltecMeshPocket board;

RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);

WRAPPER_CLASS radio_driver(radio, board);

SSD1680Display display;
MeshPocketSensorManager sensors = MeshPocketSensorManager();

VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);

bool radio_init() {
return radio.std_init(&SPI);
}

uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}

void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}

void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}

mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

bool MeshPocketSensorManager::begin() {
return true;
}

void MeshPocketSensorManager::loop() {

}

bool MeshPocketSensorManager::querySensors(uint8_t requester_permission, CayenneLPP& telemetry) {
return true;
}

int MeshPocketSensorManager::getNumSettings() const {
return 0;
}

const char* MeshPocketSensorManager::getSettingName(int i) const {
return NULL;
}

const char* MeshPocketSensorManager::getSettingValue(int i) const {
return NULL;
}

bool MeshPocketSensorManager::setSettingValue(const char* name, const char* value) {
return false;
}
37 changes: 37 additions & 0 deletions variants/heltec_meshpocket/target.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/CustomSX1262Wrapper.h>
#include "MeshPocket.h"
#include <helpers/RadioLibWrappers.h>
#include <helpers/SensorManager.h>

extern HeltecMeshPocket board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;


bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

class MeshPocketSensorManager : public SensorManager {
public:
MeshPocketSensorManager() {};
bool begin() override;
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry);
void loop();
int getNumSettings() const override;
const char* getSettingName(int i) const override;
const char* getSettingValue(int i) const override;
bool setSettingValue(const char* name, const char* value) override;
};

extern MeshPocketSensorManager sensors;

#include "helpers/ui/SSD1680Display.h"
extern SSD1680Display display;
Loading