Skip to content
Open
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
15 changes: 3 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ Here are some general principals you should try to adhere to:

There are a number of fairly major features in the pipeline, with no particular time-frames attached yet. In very rough chronological order:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reset the changes to these .md files. Looks like these diffs were inherited from the main branch.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah; yeah I forked from the main branch; so will see if I can rebase to dev

- [X] Companion radio: UI redesign
- [ ] Repeater + Room Server: add ACL's (like Sensor Node has)
- [ ] Standardise Bridge mode for repeaters
- [X] Repeater + Room Server: add ACL's (like Sensor Node has)
- [X] Standardise Bridge mode for repeaters
- [ ] Repeater/Bridge: Standardise the Transport Codes for zoning/filtering
- [ ] Core + Repeater: enhanced zero-hop neighbour discovery
- [X] Core + Repeater: enhanced zero-hop neighbour discovery
- [ ] Core: round-trip manual path support
- [ ] Companion + Apps: support for multiple sub-meshes (and 'off-grid' client repeat mode)
- [ ] Core + Apps: support for LZW message compression
Expand All @@ -113,12 +113,3 @@ There are a number of fairly major features in the pipeline, with no particular
- Report bugs and request features on the [GitHub Issues](https://github.com/ripplebiz/MeshCore/issues) page.
- Find additional guides and components on [my site](https://buymeacoffee.com/ripplebiz).
- Join [MeshCore Discord](https://discord.gg/BMwCtwHj5V) to chat with the developers and get help from the community.

## RAK Wireless Board Support in PlatformIO

Before building/flashing the RAK4631 targets in this project, there is, unfortunately, some patching you have to do to your platformIO packages to make it work. There is a guide here on the process:
[RAK Wireless: How to Perform Installation of Board Support Package in PlatformIO](https://learn.rakwireless.com/hc/en-us/articles/26687276346775-How-To-Perform-Installation-of-Board-Support-Package-in-PlatformIO)

After building, you will need to convert the output firmware.hex file into a .uf2 file you can copy over to your RAK4631 device (after doing a full erase) by using the command `uf2conv.py -f 0xADA52840 -c firmware.hex` with the python script available from:
[GitHub: Microsoft - uf2](https://github.com/Microsoft/uf2/blob/master/utils/uf2conv.py)

229 changes: 121 additions & 108 deletions docs/faq.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/payloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,4 @@ The plaintext contained in the ciphertext matches the format described in [plain

# Custom packet

Custom packets have no defined format.
Custom packets have no defined format.
2 changes: 1 addition & 1 deletion examples/simple_room_server/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ void MyMesh::loop() {
if (c->extra.room.pending_ack && millisHasNowPassed(c->extra.room.ack_timeout)) {
c->extra.room.push_failures++;
c->extra.room.pending_ack = 0; // reset (TODO: keep prev expected_ack's in a list, incase they arrive LATER, after we retry)
MESH_DEBUG_PRINTLN("pending ACK timed out: push_failures: %d", (uint32_t)c->push_failures);
MESH_DEBUG_PRINTLN("pending ACK timed out: push_failures: %d", (uint32_t)c->extra.room.push_failures);
}
}
// check next Round-Robin client, and sync next new post
Expand Down
51 changes: 51 additions & 0 deletions variants/arduino_nesso_n1/ArduinoNessoN1Board.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "ArduinoNessoN1Board.h"
#include <Arduino.h>

void ArduinoNessoN1Board::begin() {
ESP32Board::begin();

#ifdef MESH_DEBUG
// delay for 2s after boot to ensure early output below makes it to the serial logger
delay(2000);
#endif

#ifdef P_LORA_TX_LED
MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): setup TX LED mode");
pinMode(P_LORA_TX_LED, OUTPUT);
digitalWrite(P_LORA_TX_LED, HIGH);
#endif

battery.begin();
battery.enableCharge();

MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): set Nesso N1 pin modes and default states...");
pinMode(LORA_ENABLE, OUTPUT); // RESET
pinMode(LORA_ANTENNA_SWITCH, OUTPUT); // ANTENNA_SWITCH
pinMode(LORA_LNA_ENABLE, OUTPUT); // LNA_ENABLE
pinMode(LCD_BACKLIGHT, OUTPUT);
pinMode(BEEP_PIN, OUTPUT);

// Toggle LoRa reset via expander
MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Enable LoRa...");
digitalWrite(LORA_ENABLE, LOW);
delay(10);
digitalWrite(LORA_ENABLE, HIGH);

// Configure antenna switch and LNA
digitalWrite(LORA_ANTENNA_SWITCH, HIGH); // enable antenna switch
digitalWrite(LORA_LNA_ENABLE, HIGH); // enable LNA

// Configure initial state of further devices on expander
MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Set LCD_BACKLIGHT and BEEP_PIN to low initial state...");
digitalWrite(LCD_BACKLIGHT, LOW);
digitalWrite(BEEP_PIN, LOW);

// Toggle LCD backlight to show the device has powered on until we get the screen working
MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Now high...");
digitalWrite(LCD_BACKLIGHT, HIGH);
digitalWrite(BEEP_PIN, HIGH);
delay(2000);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this delay need to be this long?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely not; this was just for testing to ensure that the device was waking - as without the screen on it wasn't clear that it was. It'll be gone before I intend for anything to be merged.

digitalWrite(LCD_BACKLIGHT, LOW);
digitalWrite(BEEP_PIN, LOW);
MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Now low...");
}
50 changes: 50 additions & 0 deletions variants/arduino_nesso_n1/ArduinoNessoN1Board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include <Arduino.h>
#include <MeshCore.h>
#include <helpers/ESP32Board.h>
#include "pins_arduino.h"

#define P_LORA_TX_LED LED_BUILTIN // defined in pins_arduino.h / expander.cpp through pin handling functions specific to the IO expander
// #define PIN_TFT_RST LCD_RESET
// #define PIN_TFT_LEDA_CTL LCD_BACKLIGHT

class ArduinoNessoN1Board : public ESP32Board {
private:
NessoBattery battery;

public:
void begin(); // Defined in ArduinoNessoN1Board.cpp

#ifdef P_LORA_TX_LED
void onBeforeTransmit() override {
MESH_DEBUG_PRINTLN("onBeforeTransmit: LOW LED for On");
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
}
void onAfterTransmit() override {
MESH_DEBUG_PRINTLN("onBeforeTransmit: HIGH LED for Off");
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
}
#endif

const char* getManufacturerName() const override {
return "Arduino Nesso N1";
}

uint16_t getBattMilliVolts() override {
#ifdef MESH_DEBUG
MESH_DEBUG_PRINTLN("getBattMilliVolts(): isCharging(): %u", battery.isCharging());
MESH_DEBUG_PRINTLN("getBattMilliVolts(): Current charge level %u %%", battery.getChargeLevel());
MESH_DEBUG_PRINTLN("getBattMilliVolts(): Current voltage %f V", battery.getVoltage());
MESH_DEBUG_PRINTLN("getBattMilliVolts(): Current voltage %u mV", battery.getMilliVoltage());
#endif
return battery.getMilliVoltage();
}

void reboot() override {
MESH_DEBUG_PRINTLN("ArduinoNessoN1.reboot(): noop() instead");
// esp_restart();
}
};


233 changes: 233 additions & 0 deletions variants/arduino_nesso_n1/expander.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
#pragma once
// Based off here https://github.com/espressif/arduino-esp32/blob/d1eb62d7c6dda16c254c374504aa93188d7c386b/variants/arduino_nesso_n1/expander.cpp
// Should be OK based on this? https://opensource.stackexchange.com/a/6406

#include "pins_arduino.h"
#include <helpers/ESP32Board.h>
#include <Wire.h>

static bool wireInitialized = true; // initialised in ESP32Board.begin() ; ToDo: Remove all these conditions in future
static bool expanderInitialized = false;

// From https://www.diodes.com/datasheet/download/PI4IOE5V6408.pdf
static void writeRegister(uint8_t address, uint8_t reg, uint8_t value) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}

static uint8_t readRegister(uint8_t address, uint8_t reg) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(address, 1);
return Wire.read();
}

static void writeBitRegister(uint8_t address, uint8_t reg, uint8_t bit, uint8_t value) {
MESH_DEBUG_PRINTLN("ExpanderPin writeBitRegister(address=%u, reg=%u, bit=%u, value=%u)", address, reg, bit, value);
uint8_t val = readRegister(address, reg);
if (value) {
writeRegister(address, reg, val | (1 << bit));
} else {
writeRegister(address, reg, val & ~(1 << bit));
}
}

static bool readBitRegister(uint8_t address, uint8_t reg, uint8_t bit) {
MESH_DEBUG_PRINTLN("ExpanderPin readBitRegister(address=%u, reg=%u, bit=%u)", address, reg, bit);
uint8_t val = readRegister(address, reg);
return ((val & (1 << bit)) > 0);
}

void pinMode(ExpanderPin pin, uint8_t mode) {
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
// reset all registers to default state
}
if (!expanderInitialized) {
writeRegister(pin.address, 0x1, 0x1);
// set all pins as high as default state
writeRegister(pin.address, 0x9, 0xFF);
// interrupt mask to all pins
writeRegister(pin.address, 0x11, 0xFF);
// all input
writeRegister(pin.address, 0x3, 0);
expanderInitialized = true;
}
MESH_DEBUG_PRINTLN("ExpanderPin pinMode(pin=%u, mode=%u)", pin.pin, mode);
writeBitRegister(pin.address, 0x3, pin.pin, mode == OUTPUT);
if (mode == OUTPUT) {
// remove high impedance
writeBitRegister(pin.address, 0x7, pin.pin, false);
} else if (mode == INPUT_PULLUP) {
// set pull-up resistor
writeBitRegister(pin.address, 0xB, pin.pin, true);
writeBitRegister(pin.address, 0xD, pin.pin, true);
} else if (mode == INPUT_PULLDOWN) {
// disable pull-up resistor
writeBitRegister(pin.address, 0xB, pin.pin, true);
writeBitRegister(pin.address, 0xD, pin.pin, false);
} else if (mode == INPUT) {
// disable pull selector resistor
writeBitRegister(pin.address, 0xB, pin.pin, false);
}
}

void digitalWrite(ExpanderPin pin, uint8_t val) {
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
}
MESH_DEBUG_PRINTLN("ExpanderPin digitalWrite(%u)", pin.pin);
writeBitRegister(pin.address, 0x5, pin.pin, val == HIGH);
}

int digitalRead(ExpanderPin pin) {
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
}
MESH_DEBUG_PRINTLN("ExpanderPin digitalRead(%u)", pin.pin);
return readBitRegister(pin.address, 0xF, pin.pin);
}

void NessoBattery::begin() {
// AW32001E - address 0x49
// Spec: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/products/core/LLM630%20Computer%20Kit/AW32001E.pdf
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
}

uint8_t val = 0;
val = readRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_CHIP_ID);
// coarsely check if chip is actually the right chip
auto res = (val == AW32001_I2C_CHIP_ADDR);
if (res) {
val = readRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_CHR_TMR);
#ifdef MESH_DEBUG
// Debug output the WatchDog Timer (wdt) state
MESH_DEBUG_PRINTLN("NessoBattery.begin(): CHR_TMR full register; bits 5,6 are for WDT = %#02x", val);
#endif
// disable WatchDog Timer (wdt)
// take existing register value AND with 00011111
val = val & 0x1f;
writeRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_CHR_TMR, val);
}
#ifdef MESH_DEBUG
else {
MESH_DEBUG_PRINTLN("NessoBattery.begin(): Register of chip ADDR = %u != I2C of chip %u", AW32001_REG_CHIP_ID, AW32001_I2C_CHIP_ADDR);
}
#endif

// store if chip is initiated by whether it passed above checks and had watchdog disabled
_power_mgmt_init = res;
}

void NessoBattery::enableCharge() {
// AW32001E - address 0x49
// set CEB (charge enable) bit (3) low (0) in AW32001_REG_PWR_CFG (0x01)
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge()");

if (_power_mgmt_init) {
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): _power_mgmt_init = true");
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
}

bool charge_enable_bit = readBitRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_PWR_CFG, 3);
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current charge setting (low is on): %u", charge_enable_bit);
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): isCharging(): %u", NessoBattery::isCharging());
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current charge level %u %%", NessoBattery::getChargeLevel());
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current voltage %f V", NessoBattery::getVoltage());
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current voltage %u mV", NessoBattery::getMilliVoltage());

writeBitRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_PWR_CFG, 3, false);
}
#ifdef MESH_DEBUG
else {
MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): _power_mgmt_init is false, won't enable charge");
}
#endif
}

NessoBattery::ChargeStatus NessoBattery::getChargeStatus(void) {
uint8_t reg_value = 0;
if (_power_mgmt_init)
{
reg_value = readRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_SYS_STA);
// Extract bits 4 and 3 for charge status
reg_value = (reg_value >> 3) & 0b00000011; // Get bits 4 and 3
MESH_DEBUG_PRINTLN("NessoBattery::getChargeStatus(): bits 4 and 3 from register %#02x = %u", AW32001_REG_SYS_STA, reg_value);
switch (reg_value)
{
case 0b00: return CS_NOT_CHARGING; // Not charging
case 0b01: return CS_PRE_CHARGE; // Pre-charge
case 0b10: return CS_CHARGE; // Charging
case 0b11: return CS_CHARGE_DONE; // Charge done
default: return CS_UNKNOWN; // Unknown state
}
}
MESH_DEBUG_PRINTLN("NessoBattery::getChargeStatus(): failed, probably chip wasn't init");
return CS_UNKNOWN; // Return unknown if read failed
}

bool NessoBattery::isCharging(void)
{
ChargeStatus status = getChargeStatus();
MESH_DEBUG_PRINTLN("NessoBattery::isCharging(): ChargeStatus = %u; is? false0/true1 = %u", status, (status == CS_PRE_CHARGE || status == CS_CHARGE));
return (status == CS_PRE_CHARGE || status == CS_CHARGE);
}

float NessoBattery::getVoltage() {
// BQ27220 - address 0x55
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
}
MESH_DEBUG_PRINTLN("NessoBattery::getVoltage()");
uint16_t voltage = (readRegister(0x55, 0x9) << 8) | readRegister(0x55, 0x8);
MESH_DEBUG_PRINTLN("NessoBattery::getVoltage(): %f", voltage / 1000.0f);
return (float)voltage / 1000.0f;
}

uint16_t NessoBattery::getMilliVoltage() {
// BQ27220 - address 0x55
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
}
MESH_DEBUG_PRINTLN("NessoBattery::getMilliVoltage()");
uint16_t voltage = (readRegister(0x55, 0x9) << 8) | readRegister(0x55, 0x8);
MESH_DEBUG_PRINTLN("NessoBattery::getMilliVoltage(): %u", voltage);
return voltage;
}

uint16_t NessoBattery::getChargeLevel() {
// BQ27220 - address 0x55
if (!wireInitialized) {
Wire.begin(SDA, SCL);
wireInitialized = true;
}
MESH_DEBUG_PRINTLN("NessoBattery::getChargeLevel()");
uint16_t current_capacity = readRegister(0x55, 0x11) << 8 | readRegister(0x55, 0x10);
uint16_t total_capacity = readRegister(0x55, 0x13) << 8 | readRegister(0x55, 0x12);
MESH_DEBUG_PRINTLN("NessoBattery::getChargeLevel(): curr = %u / total = %u; pct = %u %%", current_capacity, total_capacity, ((current_capacity * 100) / total_capacity));
return (current_capacity * 100) / total_capacity;
}

ExpanderPin LORA_LNA_ENABLE(5);
ExpanderPin LORA_ANTENNA_SWITCH(6);
ExpanderPin LORA_ENABLE(7);
ExpanderPin KEY1(0);
ExpanderPin KEY2(1);
ExpanderPin POWEROFF((1 << 8) | 0);
ExpanderPin LCD_RESET((1 << 8) | 1);
ExpanderPin GROVE_POWER_EN((1 << 8) | 2);
ExpanderPin VIN_DETECT((1 << 8) | 5);
ExpanderPin LCD_BACKLIGHT((1 << 8) | 6);
ExpanderPin LED_BUILTIN((1 << 8) | 7);
Loading