Merge upstream dev into keymindCascade
This commit is contained in:
commit
c31a0e5ed5
40 files changed
+2405
-200
No files matched your search
@@ -251,6 +251,9 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let a board feed its watchdog and perform periodic housekeeping.
|
||||
virtual void loop() {}
|
||||
|
||||
inline static uint32_t n_cad_busy = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@ struct ClientInfo {
|
||||
unsigned long ack_timeout;
|
||||
uint8_t push_failures;
|
||||
} room;
|
||||
struct {
|
||||
uint32_t expiry_timestamp; // epoch seconds
|
||||
uint32_t push_tag;
|
||||
uint16_t scope_region_id; // scope to use when sending telemetry to this client/subscriber
|
||||
uint8_t min_deltas_len;
|
||||
uint8_t min_deltas[14]; // LPP encoded
|
||||
uint8_t prev_telem[14]; // LPP encoded
|
||||
} sensor;
|
||||
} extra;
|
||||
|
||||
bool isAdmin() const { return (permissions & PERM_ACL_ROLE_MASK) == PERM_ACL_ADMIN; }
|
||||
|
||||
@@ -300,8 +300,8 @@ private:
|
||||
void setTxPower(int8_t dbm) override { _parent->tx_power_dbm = dbm; markDirty(); }
|
||||
float getRxDelay() const override { return _parent->rx_delay_base; }
|
||||
void setRxDelay(float d) override { _parent->rx_delay_base = d; markDirty(); }
|
||||
uint8_t getAgcResetInt() const override { return _parent->agc_reset_interval * 4; }
|
||||
void setAgcResetInt(uint8_t secs) override { _parent->agc_reset_interval = secs / 4; markDirty(); }
|
||||
uint16_t getAgcResetInt() const override { return _parent->agc_reset_interval * 4; }
|
||||
void setAgcResetInt(uint16_t secs) override { _parent->agc_reset_interval = secs / 4; markDirty(); }
|
||||
uint8_t getHashMode() const override { return _parent->path_hash_mode; }
|
||||
void setHashMode(uint8_t m) override { _parent->path_hash_mode = m; markDirty(); }
|
||||
uint8_t getMultiAcks() const override { return _parent->multi_acks; }
|
||||
|
||||
@@ -41,8 +41,8 @@ public:
|
||||
virtual float getRxDelay() const = 0;
|
||||
virtual void setRxDelay(float d) = 0;
|
||||
|
||||
virtual uint8_t getAgcResetInt() const = 0;
|
||||
virtual void setAgcResetInt(uint8_t secs) = 0;
|
||||
virtual uint16_t getAgcResetInt() const = 0;
|
||||
virtual void setAgcResetInt(uint16_t secs) = 0;
|
||||
|
||||
virtual uint8_t getHashMode() const = 0;
|
||||
virtual void setHashMode(uint8_t m) = 0;
|
||||
|
||||
@@ -43,8 +43,13 @@ bool StrHelper::isBlank(const char* str) {
|
||||
}
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdio.h>
|
||||
#if __has_include(<api/itoa.h>)
|
||||
// https://github.com/stm32duino/Arduino_Core_STM32/issues/3084
|
||||
#include <api/itoa.h>
|
||||
#endif
|
||||
|
||||
union int32_Float_t
|
||||
union int32_Float_t
|
||||
{
|
||||
int32_t Long;
|
||||
float Float;
|
||||
@@ -116,7 +121,7 @@ static void _ftoa(float f, char *p, int *status)
|
||||
*p++ = '-';
|
||||
if (int_part == 0)
|
||||
*p++ = '0';
|
||||
else
|
||||
else
|
||||
{
|
||||
#if defined(STM32_PLATFORM)
|
||||
// STM32 Arduino exposes utoa, but recent cores no longer declare ltoa.
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include <RadioLib.h>
|
||||
#include "MeshCore.h"
|
||||
|
||||
class CustomLR1121 : public LR1121 {
|
||||
uint32_t _preambleMillis = 66;
|
||||
uint32_t _maxPayloadMillis = 3934;
|
||||
uint32_t _activityAt = 0;
|
||||
bool _headerSeen = false;
|
||||
bool _rx_boosted = false;
|
||||
|
||||
public:
|
||||
CustomLR1121(Module *mod) : LR1121(mod) { }
|
||||
|
||||
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7,
|
||||
uint8_t syncWord = RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, int8_t power = 10,
|
||||
uint16_t preambleLength = 8, float tcxoVoltage = 1.6) {
|
||||
int16_t state = LR1121::begin(freq, bw, sf, cr, syncWord, power, preambleLength,
|
||||
tcxoVoltage);
|
||||
// RadioLib begin() defaults to LDO; use the LR1121 DC/DC regulator.
|
||||
if (state == RADIOLIB_ERR_NONE) state = setRegulatorDCDC();
|
||||
return state;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
int16_t startReceive() override {
|
||||
// include the PREAMBLE_DETECTED irq bit in reported flags.
|
||||
return LR1121::startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS | (1UL << RADIOLIB_IRQ_PREAMBLE_DETECTED), RADIOLIB_IRQ_RX_DEFAULT_MASK, 0);
|
||||
}
|
||||
|
||||
bool isReceiving() {
|
||||
uint32_t irq = getIrqStatus();
|
||||
bool preamble = irq & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED; // bit 4
|
||||
bool header = irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID; // bit 5
|
||||
bool hdrErr = irq & RADIOLIB_LR11X0_IRQ_HEADER_ERR; // bit 6
|
||||
uint32_t now = millis();
|
||||
if (hdrErr) {
|
||||
clearIrqState(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED | RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_HEADER_ERR);
|
||||
_activityAt = 0;
|
||||
_headerSeen = false;
|
||||
return false;
|
||||
}
|
||||
if (!header && _headerSeen) {
|
||||
// something cleared the header flag, reset our state.
|
||||
_activityAt = 0; _headerSeen = false;
|
||||
return false;
|
||||
}
|
||||
if (header) {
|
||||
if (!_headerSeen) { _headerSeen = true; _activityAt = now; };
|
||||
if (now - _activityAt > _maxPayloadMillis) {
|
||||
MESH_DEBUG_PRINTLN("Clearing header IRQ after %ums", _maxPayloadMillis);
|
||||
clearIrqState(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED | RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_HEADER_ERR);
|
||||
_activityAt = 0; _headerSeen = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (preamble) {
|
||||
if (_activityAt == 0) _activityAt = now;
|
||||
if (now - _activityAt > _preambleMillis) {
|
||||
clearIrqState(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED);
|
||||
_activityAt = 0;
|
||||
MESH_DEBUG_PRINTLN("Clearing preamble IRQ after %ums", _preambleMillis);
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
_activityAt = 0; _headerSeen = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void setPreambleMillis(uint32_t preambleMillis) {
|
||||
_preambleMillis = preambleMillis;
|
||||
MESH_DEBUG_PRINTLN("Set _preambleMillis=%u", _preambleMillis);
|
||||
}
|
||||
void setMaxPayloadMillis(uint32_t payloadMillis) {
|
||||
_maxPayloadMillis = payloadMillis;
|
||||
MESH_DEBUG_PRINTLN("Set _maxPayloadMillis=%u", _maxPayloadMillis);
|
||||
}
|
||||
|
||||
uint8_t getSpreadingFactor() const { return spreadingFactor; }
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
#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 setParams(float freq, float bw, uint8_t sf, uint8_t cr) override {
|
||||
((CustomLR1121 *)_radio)->setFrequency(freq);
|
||||
((CustomLR1121 *)_radio)->setSpreadingFactor(sf);
|
||||
((CustomLR1121 *)_radio)->setBandwidth(bw);
|
||||
((CustomLR1121 *)_radio)->setCodingRate(cr);
|
||||
updatePreamble(sf);
|
||||
PacketMillis pm = calcMaxPacketMillis(sf, bw, cr, preambleLengthForSF(sf));
|
||||
((CustomLR1121 *)_radio)->setPreambleMillis(pm.preambleMillis);
|
||||
((CustomLR1121 *)_radio)->setMaxPayloadMillis(pm.payloadMillis);
|
||||
}
|
||||
|
||||
void doResetAGC() override { lr11x0ResetAGC((LR11x0 *)_radio, ((CustomLR1121 *)_radio)->getFreqMHz(), getRxBoostedGainMode()); }
|
||||
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(preambleLengthForSF(getSpreadingFactor())); // overcomes weird issues with small and big pkts
|
||||
}
|
||||
|
||||
uint32_t getEstAirtimeFor(int len_bytes) override {
|
||||
auto airtime = RadioLibWrapper::getEstAirtimeFor(len_bytes);
|
||||
return airtime < 200 ? 200 : airtime; // at least 200 millis
|
||||
}
|
||||
|
||||
float getLastRSSI() const override { return ((CustomLR1121 *)_radio)->getRSSI(); }
|
||||
float getLastSNR() const override { return ((CustomLR1121 *)_radio)->getSNR(); }
|
||||
|
||||
uint8_t getSpreadingFactor() const override { return ((CustomLR1121 *)_radio)->getSpreadingFactor(); }
|
||||
|
||||
bool setRxBoostedGainMode(bool en) override {
|
||||
return ((CustomLR1121 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomLR1121 *)_radio)->getRxBoostedGainMode();
|
||||
}
|
||||
};
|
||||
@@ -63,12 +63,66 @@
|
||||
#define LPP_ERROR_OVERFLOW 1
|
||||
#define LPP_ERROR_UNKOWN_TYPE 2
|
||||
|
||||
class LPPReader {
|
||||
const uint8_t* _buf;
|
||||
uint8_t _len;
|
||||
uint8_t _pos;
|
||||
class LPPData {
|
||||
public:
|
||||
static uint8_t getDataSize(uint8_t type) {
|
||||
switch (type) {
|
||||
case LPP_GPS:
|
||||
return 9;
|
||||
case LPP_POLYLINE:
|
||||
return 8; // TODO: this is MINIMIUM
|
||||
case LPP_GYROMETER:
|
||||
case LPP_ACCELEROMETER:
|
||||
return 6;
|
||||
case LPP_GENERIC_SENSOR:
|
||||
case LPP_FREQUENCY:
|
||||
case LPP_DISTANCE:
|
||||
case LPP_ENERGY:
|
||||
case LPP_UNIXTIME:
|
||||
return 4;
|
||||
case LPP_COLOUR:
|
||||
return 3;
|
||||
case LPP_ANALOG_INPUT:
|
||||
case LPP_ANALOG_OUTPUT:
|
||||
case LPP_LUMINOSITY:
|
||||
case LPP_TEMPERATURE:
|
||||
case LPP_CONCENTRATION:
|
||||
case LPP_BAROMETRIC_PRESSURE:
|
||||
case LPP_RELATIVE_HUMIDITY:
|
||||
case LPP_ALTITUDE:
|
||||
case LPP_VOLTAGE:
|
||||
case LPP_CURRENT:
|
||||
case LPP_DIRECTION:
|
||||
case LPP_POWER:
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
float getFloat(const uint8_t * buffer, uint8_t size, uint32_t multiplier, bool is_signed) {
|
||||
static uint32_t getMultiplier(uint8_t type) {
|
||||
switch (type) {
|
||||
case LPP_CURRENT:
|
||||
case LPP_DISTANCE:
|
||||
case LPP_ENERGY:
|
||||
return 1000;
|
||||
case LPP_VOLTAGE:
|
||||
case LPP_ANALOG_INPUT:
|
||||
case LPP_ANALOG_OUTPUT:
|
||||
return 100;
|
||||
case LPP_TEMPERATURE:
|
||||
case LPP_BAROMETRIC_PRESSURE:
|
||||
case LPP_RELATIVE_HUMIDITY:
|
||||
return 10;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool isSigned(uint8_t type) {
|
||||
return type == LPP_ALTITUDE || type == LPP_TEMPERATURE || type == LPP_GYROMETER ||
|
||||
type == LPP_ANALOG_INPUT || type == LPP_ANALOG_OUTPUT || type == LPP_GPS || type == LPP_ACCELEROMETER;
|
||||
}
|
||||
|
||||
static float getFloat(const uint8_t * buffer, uint8_t size, uint32_t multiplier, bool is_signed) {
|
||||
uint32_t value = 0;
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
value = (value << 8) + buffer[i];
|
||||
@@ -85,6 +139,36 @@ class LPPReader {
|
||||
return sign * ((float) value / multiplier);
|
||||
}
|
||||
|
||||
static uint8_t putFloat(uint8_t * dest, float value, uint8_t size, uint32_t multiplier, bool is_signed) {
|
||||
// check sign
|
||||
bool sign = value < 0;
|
||||
if (sign) value = -value;
|
||||
|
||||
// get value to store
|
||||
uint32_t v = value * multiplier;
|
||||
|
||||
// format an uint32_t as if it was an int32_t
|
||||
if (is_signed & sign) {
|
||||
uint32_t mask = (1 << (size * 8)) - 1;
|
||||
v = v & mask;
|
||||
if (sign) v = mask - v + 1;
|
||||
}
|
||||
|
||||
// add bytes (MSB first)
|
||||
for (uint8_t i=1; i<=size; i++) {
|
||||
dest[size - i] = (v & 0xFF);
|
||||
v >>= 8;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class LPPReader {
|
||||
const uint8_t* _buf;
|
||||
uint8_t _len;
|
||||
uint8_t _pos;
|
||||
|
||||
public:
|
||||
LPPReader(const uint8_t buf[], uint8_t len) : _buf(buf), _len(len), _pos(0) { }
|
||||
|
||||
@@ -103,72 +187,42 @@ public:
|
||||
}
|
||||
|
||||
bool readGPS(float& lat, float& lon, float& alt) {
|
||||
lat = getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
|
||||
lon = getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
|
||||
alt = getFloat(&_buf[_pos], 3, 100, true); _pos += 3;
|
||||
lat = LPPData::getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
|
||||
lon = LPPData::getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
|
||||
alt = LPPData::getFloat(&_buf[_pos], 3, 100, true); _pos += 3;
|
||||
return _pos <= _len;
|
||||
}
|
||||
bool readVoltage(float& voltage) {
|
||||
voltage = getFloat(&_buf[_pos], 2, 100, false); _pos += 2;
|
||||
voltage = LPPData::getFloat(&_buf[_pos], 2, 100, false); _pos += 2;
|
||||
return _pos <= _len;
|
||||
}
|
||||
bool readCurrent(float& amps) {
|
||||
amps = getFloat(&_buf[_pos], 2, 1000, true); _pos += 2;
|
||||
amps = LPPData::getFloat(&_buf[_pos], 2, 1000, true); _pos += 2;
|
||||
return _pos <= _len;
|
||||
}
|
||||
bool readPower(float& watts) {
|
||||
watts = getFloat(&_buf[_pos], 2, 1, false); _pos += 2;
|
||||
watts = LPPData::getFloat(&_buf[_pos], 2, 1, false); _pos += 2;
|
||||
return _pos <= _len;
|
||||
}
|
||||
bool readTemperature(float& degrees_c) {
|
||||
degrees_c = getFloat(&_buf[_pos], 2, 10, true); _pos += 2;
|
||||
degrees_c = LPPData::getFloat(&_buf[_pos], 2, 10, true); _pos += 2;
|
||||
return _pos <= _len;
|
||||
}
|
||||
bool readPressure(float& pa) {
|
||||
pa = getFloat(&_buf[_pos], 2, 10, false); _pos += 2;
|
||||
pa = LPPData::getFloat(&_buf[_pos], 2, 10, false); _pos += 2;
|
||||
return _pos <= _len;
|
||||
}
|
||||
bool readRelativeHumidity(float& pct) {
|
||||
pct = getFloat(&_buf[_pos], 1, 2, false); _pos += 1;
|
||||
pct = LPPData::getFloat(&_buf[_pos], 1, 2, false); _pos += 1;
|
||||
return _pos <= _len;
|
||||
}
|
||||
bool readAltitude(float& m) {
|
||||
m = getFloat(&_buf[_pos], 2, 1, true); _pos += 2;
|
||||
m = LPPData::getFloat(&_buf[_pos], 2, 1, true); _pos += 2;
|
||||
return _pos <= _len;
|
||||
}
|
||||
|
||||
void skipData(uint8_t type) {
|
||||
switch (type) {
|
||||
case LPP_GPS:
|
||||
_pos += 9; break;
|
||||
case LPP_POLYLINE:
|
||||
_pos += 8; break; // TODO: this is MINIMUM
|
||||
case LPP_GYROMETER:
|
||||
case LPP_ACCELEROMETER:
|
||||
_pos += 6; break;
|
||||
case LPP_GENERIC_SENSOR:
|
||||
case LPP_FREQUENCY:
|
||||
case LPP_DISTANCE:
|
||||
case LPP_ENERGY:
|
||||
case LPP_UNIXTIME:
|
||||
_pos += 4; break;
|
||||
case LPP_COLOUR:
|
||||
_pos += 3; break;
|
||||
case LPP_ANALOG_INPUT:
|
||||
case LPP_ANALOG_OUTPUT:
|
||||
case LPP_LUMINOSITY:
|
||||
case LPP_TEMPERATURE:
|
||||
case LPP_CONCENTRATION:
|
||||
case LPP_BAROMETRIC_PRESSURE:
|
||||
case LPP_ALTITUDE:
|
||||
case LPP_VOLTAGE:
|
||||
case LPP_CURRENT:
|
||||
case LPP_DIRECTION:
|
||||
case LPP_POWER:
|
||||
_pos += 2; break;
|
||||
default:
|
||||
_pos++;
|
||||
}
|
||||
_pos += LPPData::getDataSize(type);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -185,6 +239,19 @@ class LPPWriter {
|
||||
public:
|
||||
LPPWriter(uint8_t buf[], uint8_t max_len): _buf(buf), _max_len(max_len), _len(0) { }
|
||||
|
||||
bool writeData(uint8_t channel, uint8_t type, float v) {
|
||||
uint8_t sz = LPPData::getDataSize(type);
|
||||
bool s = LPPData::isSigned(type);
|
||||
uint32_t mul = LPPData::getMultiplier(type);
|
||||
if (_len + 2 + sz <= _max_len) {
|
||||
_buf[_len++] = channel;
|
||||
_buf[_len++] = type;
|
||||
_len += LPPData::putFloat(&_buf[_len], v, sz, mul, s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool writeVoltage(uint8_t channel, float voltage) {
|
||||
if (_len + 4 <= _max_len) {
|
||||
_buf[_len++] = channel;
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "SH1107Display.h"
|
||||
#include <Adafruit_GrayOLED.h>
|
||||
#include "Adafruit_SH110X.h"
|
||||
|
||||
#ifndef DISPLAY_ROTATION
|
||||
#define DISPLAY_ROTATION 0
|
||||
#endif
|
||||
|
||||
ColorVal UIColor::window_bkg = SH110X_BLACK;
|
||||
ColorVal UIColor::title_bkg = SH110X_BLACK;
|
||||
ColorVal UIColor::title_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::primary_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::secondary_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::warning_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::popup_bkg = SH110X_BLACK;
|
||||
ColorVal UIColor::popup_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::corp_blue = SH110X_WHITE;
|
||||
|
||||
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);
|
||||
uint8_t cmd[] = {0xD5, 0xF0};
|
||||
display.oled_commandList(cmd, 2);
|
||||
_isOn = true;
|
||||
}
|
||||
|
||||
void SH1107Display::turnOff()
|
||||
{
|
||||
display.oled_command(SH110X_DISPLAYOFF);
|
||||
_isOn = false;
|
||||
}
|
||||
|
||||
void SH1107Display::clear()
|
||||
{
|
||||
display.clearDisplay();
|
||||
display.display();
|
||||
}
|
||||
|
||||
void SH1107Display::startFrame(ColorVal bkg)
|
||||
{
|
||||
display.clearDisplay(); // TODO: apply 'bkg'
|
||||
display.setContrast(120); // 0-127. 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(ColorVal 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();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#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
|
||||
#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) { _isOn = false; }
|
||||
bool begin();
|
||||
|
||||
bool isOn() override { return _isOn; }
|
||||
void turnOn() override;
|
||||
void turnOff() override;
|
||||
void clear() override;
|
||||
void startFrame(ColorVal bkg = UIColor::window_bkg) override;
|
||||
void setTextSize(int sz) override;
|
||||
void setColor(ColorVal 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;
|
||||
};
|
||||
Reference in new issue
Block a user