Skip to content
72 changes: 72 additions & 0 deletions boards/muzi_base_duo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_MUZI_BASE_DUO -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x4405"
],
[
"0x239A",
"0x0029"
],
[
"0x239A",
"0x002A"
]
],
"usb_product": "muzi_base_duo",
"mcu": "nrf52840",
"variant": "MUZI_BASE_DUO",
"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": "nrf52.cfg"
},
"frameworks": [
"arduino"
],
"name": "Muzi Base Duo",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
]
},
"url": "https://github.com/muzi-works",
"vendor": "MuziWorks"
}
39 changes: 39 additions & 0 deletions src/helpers/radiolib/CustomLR1121.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include <RadioLib.h>
#include "MeshCore.h"

class CustomLR1121 : public LR1121 {
bool _rx_boosted = false;

public:
CustomLR1121(Module *mod) : LR1121(mod) { }

size_t getPacketLength(bool update) override {
size_t len = LR1121::getPacketLength(update);
if (len == 0 && getIrqStatus() & RADIOLIB_LR11X0_IRQ_HEADER_ERR) {
// we've just received a corrupted packet
// this may have triggered a bug causing subsequent packets to be shifted
// call standby() to return radio to known-good state
// recvRaw will call startReceive() to restart rx
MESH_DEBUG_PRINTLN("LR1121: got header err, calling standby()");
standby();
}
return len;
}

float getFreqMHz() const { return freqMHz; }

int16_t setRxBoostedGainMode(bool en) {
_rx_boosted = en;
return LR1121::setRxBoostedGainMode(en);
}

bool getRxBoostedGainMode() const { return _rx_boosted; }

bool isReceiving() {
uint16_t irq = getIrqStatus();
bool detected = ((irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID) || (irq & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED));
return detected;
}
};
34 changes: 34 additions & 0 deletions src/helpers/radiolib/CustomLR1121Wrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include "CustomLR1121.h"
#include "RadioLibWrappers.h"
#include "LR11x0Reset.h"

class CustomLR1121Wrapper : public RadioLibWrapper {
public:
CustomLR1121Wrapper(CustomLR1121& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { }
void doResetAGC() override { lr11x0ResetAGC((LR11x0 *)_radio, ((CustomLR1121 *)_radio)->getFreqMHz()); }
bool isReceivingPacket() override {
return ((CustomLR1121 *)_radio)->isReceiving();
}
float getCurrentRSSI() override {
float rssi = -110;
((CustomLR1121 *)_radio)->getRssiInst(&rssi);
return rssi;
}

void onSendFinished() override {
RadioLibWrapper::onSendFinished();
_radio->setPreambleLength(16); // overcomes weird issues with small and big pkts
}

float getLastRSSI() const override { return ((CustomLR1121 *)_radio)->getRSSI(); }
float getLastSNR() const override { return ((CustomLR1121 *)_radio)->getSNR(); }

void setRxBoostedGainMode(bool en) override {
((CustomLR1121 *)_radio)->setRxBoostedGainMode(en);
}
bool getRxBoostedGainMode() const override {
return ((CustomLR1121 *)_radio)->getRxBoostedGainMode();
}
};
101 changes: 101 additions & 0 deletions src/helpers/ui/SH1107Display.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "SH1107Display.h"
#include <Adafruit_GrayOLED.h>
#include "Adafruit_SH110X.h"

#ifndef DISPLAY_ROTATION
#define DISPLAY_ROTATION 0
#endif

bool SH1107Display::i2c_probe(TwoWire &wire, uint8_t addr)
{
wire.beginTransmission(addr);
uint8_t error = wire.endTransmission();
return (error == 0);
}

bool SH1107Display::begin()
{
bool result = display.begin(DISPLAY_ADDRESS, true) && i2c_probe(Wire, DISPLAY_ADDRESS);
if (result) {
display.setRotation(DISPLAY_ROTATION);
}
return result;
}

void SH1107Display::turnOn()
{
display.oled_command(SH110X_DISPLAYON);
_isOn = true;
}

void SH1107Display::turnOff()
{
display.oled_command(SH110X_DISPLAYOFF);
_isOn = false;
}

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

void SH1107Display::startFrame(Color bkg)
{
display.clearDisplay(); // TODO: apply 'bkg'
display.setContrast(300); // 0-255. default setting was causing some flickering.
// display.SH110X_SETPRECHARGE(255);
_color = SH110X_WHITE;
display.setTextColor(_color);
display.setTextSize(1);
display.cp437(true); // Use full 256 char 'Code Page 437' font
}

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

void SH1107Display::setColor(Color c)
{
_color = (c != 0) ? SH110X_WHITE : SH110X_BLACK;
display.setTextColor(_color);
}

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

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

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

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

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

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

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

#include "DisplayDriver.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#define SH110X_NO_SPLASH
#include <Adafruit_SH110X.h>

#ifndef PIN_OLED_RESET
#define PIN_OLED_RESET -1
#ifndef PIN_OLED_12V_EN
#define PIN_OLED_12V_EN -1
#endif
#endif

#ifndef DISPLAY_ADDRESS
#define DISPLAY_ADDRESS 0x3c
#endif

class SH1107Display : public DisplayDriver
{
Adafruit_SH1107 display;
bool _isOn;
uint8_t _color;

bool i2c_probe(TwoWire &wire, uint8_t addr);

public:
SH1107Display() : DisplayDriver(128, 128), display(128, 128, &Wire, PIN_OLED_RESET, PIN_OLED_12V_EN) { _isOn = false; }
bool begin();

bool isOn() override { return _isOn; }
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;
};
50 changes: 50 additions & 0 deletions variants/muzi_base_duo/muzi_base_duoBoard.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <Arduino.h>
#include <Wire.h>

#include "muzi_base_duoBoard.h"

#ifdef NRF52_POWER_MANAGEMENT
const PowerMgtConfig power_config = {
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN,
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL,
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK
};

void muzi_base_duoBoard::initiateShutdown(uint8_t reason) {
// Disable LoRa module power before shutdown
if (reason == SHUTDOWN_REASON_LOW_VOLTAGE ||
reason == SHUTDOWN_REASON_BOOT_PROTECT) {
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel);
}

enterSystemOff(reason);
}
#endif // NRF52_POWER_MANAGEMENT

void muzi_base_duoBoard::begin() {
NRF52BoardDCDC::begin();
pinMode(PIN_VBAT_READ, INPUT);
pinMode(SCREEN_12V_ENABLE, OUTPUT);
digitalWrite(SCREEN_12V_ENABLE, HIGH); // Enable 12V power for SH1107 display
delay(250);
Wire.begin();
// delay(1000); // wait for display to initialize. otherwise it doesn't come up on boot.

#ifdef PIN_USER_BTN
pinMode(PIN_USER_BTN, INPUT_PULLUP);
#endif
pinMode(PIN_BUTTON1, INPUT_PULLUP);
pinMode(PIN_BUTTON2, INPUT_PULLUP);
pinMode(PIN_BUTTON3, INPUT_PULLUP);
pinMode(PIN_BUTTON4, INPUT_PULLUP);
pinMode(PIN_BUTTON5, INPUT_PULLUP);
pinMode(PIN_BUTTON6, INPUT_PULLUP);

// #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
// Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
// #endif
#ifdef NRF52_POWER_MANAGEMENT
checkBootVoltage(&power_config);
#endif
// delay(10); // give LR1121 some time to power up
}
37 changes: 37 additions & 0 deletions variants/muzi_base_duo/muzi_base_duoBoard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include <MeshCore.h>
#include <Arduino.h>
#include <helpers/NRF52Board.h>

class muzi_base_duoBoard : public NRF52BoardDCDC {
protected:
#ifdef NRF52_POWER_MANAGEMENT
void initiateShutdown(uint8_t reason) override;
#endif

public:
muzi_base_duoBoard() : NRF52Board("MUZI_BASE_DUO_OTA") {}
void begin();

#define BATTERY_SAMPLES 8

uint16_t getBattMilliVolts() override {
analogReadResolution(12);
analogReference(AR_INTERNAL_3_0);
delay(1);

uint32_t raw = 0;
for (int i = 0; i < BATTERY_SAMPLES; i++) {
raw += analogRead(PIN_VBAT_READ);
}
raw = raw / BATTERY_SAMPLES;

// ADC_MULTIPLIER is the voltage divider ratio
return (raw * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096;
}

const char* getManufacturerName() const override {
return "Muzi Base Duo";
}
};
Loading