Merge pull request #8689 from meshtastic/develop-to-master
Develop to master
This commit is contained in:
@@ -61,6 +61,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
# Always use master branch for version bumps
|
||||||
|
ref: master
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v6
|
||||||
|
|||||||
@@ -37,4 +37,3 @@ Join our community and help improve Meshtastic! 🚀
|
|||||||
## Stats
|
## Stats
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ build_flags =
|
|||||||
-DRADIOLIB_EXCLUDE_LR11X0=1
|
-DRADIOLIB_EXCLUDE_LR11X0=1
|
||||||
-DHAL_DAC_MODULE_ONLY
|
-DHAL_DAC_MODULE_ONLY
|
||||||
-DHAL_RNG_MODULE_ENABLED
|
-DHAL_RNG_MODULE_ENABLED
|
||||||
|
-Wl,--wrap=__assert_func
|
||||||
|
-Wl,--wrap=strerror
|
||||||
|
-Wl,--wrap=_tzset_unlocked_r
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2xx0> -<mesh/raspihttp>
|
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2xx0> -<mesh/raspihttp>
|
||||||
|
|||||||
@@ -87,6 +87,9 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.7.16" date="2025-11-19">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.16</url>
|
||||||
|
</release>
|
||||||
<release version="2.7.15" date="2025-11-13">
|
<release version="2.7.15" date="2025-11-13">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.15</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.15</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
Vendored
+7
@@ -1,3 +1,10 @@
|
|||||||
|
meshtasticd (2.7.16.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Version 2.7.16
|
||||||
|
|
||||||
|
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Wed, 19 Nov 2025 16:12:32 +0000
|
||||||
|
|
||||||
|
|
||||||
meshtasticd (2.7.15.0) unstable; urgency=medium
|
meshtasticd (2.7.15.0) unstable; urgency=medium
|
||||||
|
|
||||||
* Version 2.7.15
|
* Version 2.7.15
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ BuildRequires: python3dist(grpcio[protobuf])
|
|||||||
BuildRequires: python3dist(grpcio-tools)
|
BuildRequires: python3dist(grpcio-tools)
|
||||||
BuildRequires: git-core
|
BuildRequires: git-core
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
|
BuildRequires: (glibc-devel >= 2.38) or pkgconfig(libbsd-overlay)
|
||||||
BuildRequires: pkgconfig(yaml-cpp)
|
BuildRequires: pkgconfig(yaml-cpp)
|
||||||
BuildRequires: pkgconfig(libgpiod)
|
BuildRequires: pkgconfig(libgpiod)
|
||||||
BuildRequires: pkgconfig(bluez)
|
BuildRequires: pkgconfig(bluez)
|
||||||
|
|||||||
+4
-1
@@ -115,7 +115,8 @@ lib_deps =
|
|||||||
[radiolib_base]
|
[radiolib_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib
|
# renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib
|
||||||
jgromes/RadioLib@7.3.0
|
# jgromes/RadioLib@7.4.0
|
||||||
|
https://github.com/jgromes/RadioLib/archive/536c7267362e2c1345be7054ba45e503252975ff.zip
|
||||||
|
|
||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -181,6 +182,8 @@ lib_deps =
|
|||||||
dfrobot/DFRobot_BMM150@1.0.0
|
dfrobot/DFRobot_BMM150@1.0.0
|
||||||
# renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561
|
# renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561
|
||||||
adafruit/Adafruit TSL2561@1.1.2
|
adafruit/Adafruit TSL2561@1.1.2
|
||||||
|
# renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/BH1750_WE@^1.1.10
|
||||||
|
wollewald/BH1750_WE@^1.1.10
|
||||||
|
|
||||||
; (not included in native / portduino)
|
; (not included in native / portduino)
|
||||||
[environmental_extra]
|
[environmental_extra]
|
||||||
|
|||||||
+8
-8
@@ -14,16 +14,16 @@ class NodeStatus : public Status
|
|||||||
CallbackObserver<NodeStatus, const NodeStatus *> statusObserver =
|
CallbackObserver<NodeStatus, const NodeStatus *> statusObserver =
|
||||||
CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus);
|
CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus);
|
||||||
|
|
||||||
uint8_t numOnline = 0;
|
uint16_t numOnline = 0;
|
||||||
uint8_t numTotal = 0;
|
uint16_t numTotal = 0;
|
||||||
|
|
||||||
uint8_t lastNumTotal = 0;
|
uint16_t lastNumTotal = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool forceUpdate = false;
|
bool forceUpdate = false;
|
||||||
|
|
||||||
NodeStatus() { statusType = STATUS_TYPE_NODE; }
|
NodeStatus() { statusType = STATUS_TYPE_NODE; }
|
||||||
NodeStatus(uint8_t numOnline, uint8_t numTotal, bool forceUpdate = false) : Status()
|
NodeStatus(uint16_t numOnline, uint16_t numTotal, bool forceUpdate = false) : Status()
|
||||||
{
|
{
|
||||||
this->forceUpdate = forceUpdate;
|
this->forceUpdate = forceUpdate;
|
||||||
this->numOnline = numOnline;
|
this->numOnline = numOnline;
|
||||||
@@ -34,11 +34,11 @@ class NodeStatus : public Status
|
|||||||
|
|
||||||
void observe(Observable<const NodeStatus *> *source) { statusObserver.observe(source); }
|
void observe(Observable<const NodeStatus *> *source) { statusObserver.observe(source); }
|
||||||
|
|
||||||
uint8_t getNumOnline() const { return numOnline; }
|
uint16_t getNumOnline() const { return numOnline; }
|
||||||
|
|
||||||
uint8_t getNumTotal() const { return numTotal; }
|
uint16_t getNumTotal() const { return numTotal; }
|
||||||
|
|
||||||
uint8_t getLastNumTotal() const { return lastNumTotal; }
|
uint16_t getLastNumTotal() const { return lastNumTotal; }
|
||||||
|
|
||||||
bool matches(const NodeStatus *newStatus) const
|
bool matches(const NodeStatus *newStatus) const
|
||||||
{
|
{
|
||||||
@@ -56,7 +56,7 @@ class NodeStatus : public Status
|
|||||||
numTotal = newStatus->getNumTotal();
|
numTotal = newStatus->getNumTotal();
|
||||||
}
|
}
|
||||||
if (isDirty || newStatus->forceUpdate) {
|
if (isDirty || newStatus->forceUpdate) {
|
||||||
LOG_DEBUG("Node status update: %d online, %d total", numOnline, numTotal);
|
LOG_DEBUG("Node status update: %u online, %u total", numOnline, numTotal);
|
||||||
onNewStatus.notifyObservers(this);
|
onNewStatus.notifyObservers(this);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+5
-10
@@ -194,7 +194,7 @@ static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level se
|
|||||||
|
|
||||||
#ifdef BATTERY_PIN
|
#ifdef BATTERY_PIN
|
||||||
|
|
||||||
static void adcEnable()
|
void battery_adcEnable()
|
||||||
{
|
{
|
||||||
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
|
||||||
#ifdef ADC_USE_PULLUP
|
#ifdef ADC_USE_PULLUP
|
||||||
@@ -214,7 +214,7 @@ static void adcEnable()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adcDisable()
|
static void battery_adcDisable()
|
||||||
{
|
{
|
||||||
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
|
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
|
||||||
#ifdef ADC_USE_PULLUP
|
#ifdef ADC_USE_PULLUP
|
||||||
@@ -320,7 +320,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
uint32_t raw = 0;
|
uint32_t raw = 0;
|
||||||
float scaled = 0;
|
float scaled = 0;
|
||||||
|
|
||||||
adcEnable();
|
battery_adcEnable();
|
||||||
#ifdef ARCH_ESP32 // ADC block for espressif platforms
|
#ifdef ARCH_ESP32 // ADC block for espressif platforms
|
||||||
raw = espAdcRead();
|
raw = espAdcRead();
|
||||||
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
||||||
@@ -332,7 +332,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
raw = raw / BATTERY_SENSE_SAMPLES;
|
raw = raw / BATTERY_SENSE_SAMPLES;
|
||||||
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
|
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
|
||||||
#endif
|
#endif
|
||||||
adcDisable();
|
battery_adcDisable();
|
||||||
|
|
||||||
if (!initial_read_done) {
|
if (!initial_read_done) {
|
||||||
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
||||||
@@ -906,13 +906,8 @@ void Power::readPowerStatus()
|
|||||||
low_voltage_counter++;
|
low_voltage_counter++;
|
||||||
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
|
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
|
||||||
if (low_voltage_counter > 10) {
|
if (low_voltage_counter > 10) {
|
||||||
#ifdef ARCH_NRF52
|
|
||||||
// We can't trigger deep sleep on NRF52, it's freezing the board
|
|
||||||
LOG_DEBUG("Low voltage detected, but not trigger deep sleep");
|
|
||||||
#else
|
|
||||||
LOG_INFO("Low voltage detected, trigger deep sleep");
|
LOG_INFO("Low voltage detected, trigger deep sleep");
|
||||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
low_voltage_counter = 0;
|
low_voltage_counter = 0;
|
||||||
@@ -1552,4 +1547,4 @@ bool Power::meshSolarInit()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define ICM20948_ADDR_ALT 0x68
|
#define ICM20948_ADDR_ALT 0x68
|
||||||
#define BHI260AP_ADDR 0x28
|
#define BHI260AP_ADDR 0x28
|
||||||
#define BMM150_ADDR 0x13
|
#define BMM150_ADDR 0x13
|
||||||
|
#define DA217_ADDR 0x26
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// LED
|
// LED
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
|
|||||||
if (i2cBus->available())
|
if (i2cBus->available())
|
||||||
i2cBus->read();
|
i2cBus->read();
|
||||||
}
|
}
|
||||||
|
LOG_DEBUG("Register value: 0x%x", value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,14 +378,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
}
|
}
|
||||||
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
|
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
|
||||||
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
|
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2);
|
||||||
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0x11f3 || registerValue == 0xe9c ||
|
if (registerValue == 0x5449) {
|
||||||
registerValue == 0xc8d) {
|
|
||||||
type = SHT4X;
|
|
||||||
logFoundDevice("SHT4X", (uint8_t)addr.address);
|
|
||||||
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
|
|
||||||
type = OPT3001;
|
type = OPT3001;
|
||||||
logFoundDevice("OPT3001", (uint8_t)addr.address);
|
logFoundDevice("OPT3001", (uint8_t)addr.address);
|
||||||
|
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2) != 0) { // unique SHT4x serial number
|
||||||
|
type = SHT4X;
|
||||||
|
logFoundDevice("SHT4X", (uint8_t)addr.address);
|
||||||
} else {
|
} else {
|
||||||
type = SHT31;
|
type = SHT31;
|
||||||
logFoundDevice("SHT31", (uint8_t)addr.address);
|
logFoundDevice("SHT31", (uint8_t)addr.address);
|
||||||
@@ -465,8 +465,23 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
|
||||||
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
|
|
||||||
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
|
||||||
|
case TCA9555_ADDR:
|
||||||
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 1);
|
||||||
|
if (registerValue == 0x13) {
|
||||||
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
|
||||||
|
if (registerValue == 0x81) {
|
||||||
|
type = DA217;
|
||||||
|
logFoundDevice("DA217", (uint8_t)addr.address);
|
||||||
|
} else {
|
||||||
|
type = TCA9555;
|
||||||
|
logFoundDevice("TCA9555", (uint8_t)addr.address);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = TCA9555;
|
||||||
|
logFoundDevice("TCA9555", (uint8_t)addr.address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TSL25911_ADDR:
|
case TSL25911_ADDR:
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
|
||||||
if (registerValue == 0x50) {
|
if (registerValue == 0x50) {
|
||||||
|
|||||||
+27
-8
@@ -240,6 +240,9 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
buffer[bytesRead] = b;
|
buffer[bytesRead] = b;
|
||||||
bytesRead++;
|
bytesRead++;
|
||||||
if ((bytesRead == 767) || (b == '\r')) {
|
if ((bytesRead == 767) || (b == '\r')) {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(debugmsg.c_str());
|
||||||
|
#endif
|
||||||
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG("Found: %s", message); // Log the found message
|
LOG_DEBUG("Found: %s", message); // Log the found message
|
||||||
@@ -247,9 +250,6 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
return GNSS_RESPONSE_OK;
|
return GNSS_RESPONSE_OK;
|
||||||
} else {
|
} else {
|
||||||
bytesRead = 0;
|
bytesRead = 0;
|
||||||
#ifdef GPS_DEBUG
|
|
||||||
LOG_DEBUG(debugmsg.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1275,6 +1275,24 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
memset(&ublox_info, 0, sizeof(ublox_info));
|
memset(&ublox_info, 0, sizeof(ublox_info));
|
||||||
delay(100);
|
delay(100);
|
||||||
|
|
||||||
|
#if defined(PIN_GPS_RESET) && PIN_GPS_RESET != -1
|
||||||
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||||
|
delay(10);
|
||||||
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
|
|
||||||
|
// attempt to detect the chip based on boot messages
|
||||||
|
std::vector<ChipInfo> passive_detect = {
|
||||||
|
{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
|
||||||
|
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
|
||||||
|
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352},
|
||||||
|
{"UC6580", "UC6580", GNSS_MODEL_UC6580},
|
||||||
|
// as L76K is sort of a last ditch effort, we won't attempt to detect it by startup messages for now.
|
||||||
|
/*{"L76K", "SW=URANUS", GNSS_MODEL_MTK}*/};
|
||||||
|
GnssModel_t detectedDriver = getProbeResponse(500, passive_detect, serialSpeed);
|
||||||
|
if (detectedDriver != GNSS_MODEL_UNKNOWN) {
|
||||||
|
return detectedDriver;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
||||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||||
delay(20);
|
delay(20);
|
||||||
@@ -1473,12 +1491,12 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
||||||
#ifdef GPS_DEBUG
|
|
||||||
LOG_DEBUG(response);
|
|
||||||
#endif
|
|
||||||
// check if we can see our chips
|
// check if we can see our chips
|
||||||
for (const auto &chipInfo : responseMap) {
|
for (const auto &chipInfo : responseMap) {
|
||||||
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(response);
|
||||||
|
#endif
|
||||||
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
||||||
delete[] response; // Cleanup before return
|
delete[] response; // Cleanup before return
|
||||||
return chipInfo.driver;
|
return chipInfo.driver;
|
||||||
@@ -1486,6 +1504,9 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
||||||
|
#ifdef GPS_DEBUG
|
||||||
|
LOG_DEBUG(response);
|
||||||
|
#endif
|
||||||
// Reset the response buffer for the next potential message
|
// Reset the response buffer for the next potential message
|
||||||
responseLen = 0;
|
responseLen = 0;
|
||||||
response[0] = '\0';
|
response[0] = '\0';
|
||||||
@@ -1572,8 +1593,6 @@ GPS *GPS::createGps()
|
|||||||
|
|
||||||
#ifdef PIN_GPS_RESET
|
#ifdef PIN_GPS_RESET
|
||||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
|
||||||
delay(10);
|
|
||||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -310,7 +310,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
#ifdef BUILD_EPOCH
|
#ifdef BUILD_EPOCH
|
||||||
if (tv.tv_sec < BUILD_EPOCH) {
|
if (tv.tv_sec < BUILD_EPOCH) {
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
||||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
LOG_WARN("Ignore time (%lu) before build epoch (%lu)!", printableEpoch, BUILD_EPOCH);
|
||||||
lastTimeValidationWarning = millis();
|
lastTimeValidationWarning = millis();
|
||||||
}
|
}
|
||||||
return RTCSetResultInvalidTime;
|
return RTCSetResultInvalidTime;
|
||||||
@@ -319,7 +319,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
// Calculate max allowed time safely to avoid overflow in logging
|
// Calculate max allowed time safely to avoid overflow in logging
|
||||||
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
||||||
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
||||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
LOG_WARN("Ignore time (%lu) too far in the future (build epoch: %lu, max allowed: %lu)!", printableEpoch,
|
||||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
||||||
lastTimeValidationWarning = millis();
|
lastTimeValidationWarning = millis();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -483,8 +483,6 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
lgfx::Touch_FT5x06 _touch_instance;
|
lgfx::Touch_FT5x06 _touch_instance;
|
||||||
#elif defined(HELTEC_V4_TFT)
|
#elif defined(HELTEC_V4_TFT)
|
||||||
lgfx::TOUCH_CHSC6X _touch_instance;
|
lgfx::TOUCH_CHSC6X _touch_instance;
|
||||||
#elif defined(HELTEC_V4_TFT)
|
|
||||||
lgfx::TOUCH_CHSC6X _touch_instance;
|
|
||||||
#else
|
#else
|
||||||
lgfx::Touch_GT911 _touch_instance;
|
lgfx::Touch_GT911 _touch_instance;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -101,3 +101,23 @@ void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength)
|
|||||||
else
|
else
|
||||||
snprintf(timeStr, maxLength, "unknown age");
|
snprintf(timeStr, maxLength, "unknown age");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getUptimeStr(uint32_t uptimeMillis, const char *prefix, char *uptimeStr, uint8_t maxLength, bool includeSecs)
|
||||||
|
{
|
||||||
|
uint32_t days = uptimeMillis / 86400000;
|
||||||
|
uint32_t hours = (uptimeMillis % 86400000) / 3600000;
|
||||||
|
uint32_t mins = (uptimeMillis % 3600000) / 60000;
|
||||||
|
uint32_t secs = (uptimeMillis % 60000) / 1000;
|
||||||
|
|
||||||
|
if (days) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %ud %uh", prefix, days, hours);
|
||||||
|
} else if (hours) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %uh %um", prefix, hours, mins);
|
||||||
|
} else if (!includeSecs) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %um", prefix, mins);
|
||||||
|
} else if (mins) {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %um %us", prefix, mins, secs);
|
||||||
|
} else {
|
||||||
|
snprintf(uptimeStr, maxLength, "%s: %us", prefix, secs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,3 +24,10 @@ bool deltaToTimestamp(uint32_t secondsAgo, uint8_t *hours, uint8_t *minutes, int
|
|||||||
* @param maxLength Maximum length of the resulting string buffer
|
* @param maxLength Maximum length of the resulting string buffer
|
||||||
*/
|
*/
|
||||||
void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength);
|
void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a compact human-readable string that only shows the largest non-zero time components.
|
||||||
|
* For example, 0 days 1 hour 2 minutes will display as "1h 2m" but 1 day 2 hours 3 minutes
|
||||||
|
* will display as "1d 2h".
|
||||||
|
*/
|
||||||
|
void getUptimeStr(uint32_t uptimeMillis, const char *prefix, char *uptimeStr, uint8_t maxLength, bool includeSecs = false);
|
||||||
|
|||||||
@@ -194,17 +194,12 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
||||||
int line = 0;
|
int line = 0;
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
|
||||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
|
||||||
graphics::ClockRenderer::drawBluetoothConnectedIcon(display, display->getWidth() - 18, display->getHeight() - 14);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone
|
||||||
char timeString[16];
|
char timeString[16];
|
||||||
int hour = 0;
|
int hour = 0;
|
||||||
int minute = 0;
|
int minute = 0;
|
||||||
int second = 0;
|
int second = 0;
|
||||||
|
|
||||||
if (rtc_sec > 0) {
|
if (rtc_sec > 0) {
|
||||||
long hms = rtc_sec % SEC_PER_DAY;
|
long hms = rtc_sec % SEC_PER_DAY;
|
||||||
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||||||
@@ -215,11 +210,11 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isPM = hour >= 12;
|
bool isPM = hour >= 12;
|
||||||
// hour = hour > 12 ? hour - 12 : hour;
|
|
||||||
if (config.display.use_12h_clock) {
|
if (config.display.use_12h_clock) {
|
||||||
hour %= 12;
|
hour %= 12;
|
||||||
if (hour == 0)
|
if (hour == 0) {
|
||||||
hour = 12;
|
hour = 12;
|
||||||
|
}
|
||||||
snprintf(timeString, sizeof(timeString), "%d:%02d", hour, minute);
|
snprintf(timeString, sizeof(timeString), "%d:%02d", hour, minute);
|
||||||
} else {
|
} else {
|
||||||
snprintf(timeString, sizeof(timeString), "%02d:%02d", hour, minute);
|
snprintf(timeString, sizeof(timeString), "%02d:%02d", hour, minute);
|
||||||
@@ -229,24 +224,56 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
char secondString[8];
|
char secondString[8];
|
||||||
snprintf(secondString, sizeof(secondString), "%02d", second);
|
snprintf(secondString, sizeof(secondString), "%02d", second);
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
static bool scaleInitialized = false;
|
||||||
float scale = 1.5;
|
static float scale = 0.75f;
|
||||||
#elif defined(CHATTER_2)
|
static float segmentWidth = SEGMENT_WIDTH * 0.75f;
|
||||||
float scale = 1.1;
|
static float segmentHeight = SEGMENT_HEIGHT * 0.75f;
|
||||||
#else
|
|
||||||
float scale = 0.75;
|
|
||||||
if (isHighResolution) {
|
|
||||||
scale = 1.5;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint16_t segmentWidth = SEGMENT_WIDTH * scale;
|
if (!scaleInitialized) {
|
||||||
uint16_t segmentHeight = SEGMENT_HEIGHT * scale;
|
float screenwidth_target_ratio = 0.80f; // Target 80% of display width (adjustable)
|
||||||
|
float max_scale = 3.5f; // Safety limit to avoid runaway scaling
|
||||||
|
float step = 0.05f; // Step increment per iteration
|
||||||
|
|
||||||
|
float target_width = display->getWidth() * screenwidth_target_ratio;
|
||||||
|
float target_height =
|
||||||
|
display->getHeight() -
|
||||||
|
(isHighResolution
|
||||||
|
? 46
|
||||||
|
: 33); // Be careful adjusting this number, we have to account for header and the text under the time
|
||||||
|
|
||||||
|
float calculated_width_size = 0.0f;
|
||||||
|
float calculated_height_size = 0.0f;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
segmentWidth = SEGMENT_WIDTH * scale;
|
||||||
|
segmentHeight = SEGMENT_HEIGHT * scale;
|
||||||
|
|
||||||
|
calculated_width_size = segmentHeight + ((segmentWidth + (segmentHeight * 2) + 4) * 4);
|
||||||
|
calculated_height_size = segmentHeight + ((segmentHeight + (segmentHeight * 2) + 4) * 2);
|
||||||
|
|
||||||
|
if (calculated_width_size >= target_width || calculated_height_size >= target_height || scale >= max_scale) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale += step;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we overshot width, back off one step and recompute segment sizes
|
||||||
|
if (calculated_width_size > target_width || calculated_height_size > target_height) {
|
||||||
|
scale -= step;
|
||||||
|
segmentWidth = SEGMENT_WIDTH * scale;
|
||||||
|
segmentHeight = SEGMENT_HEIGHT * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(timeString);
|
||||||
|
|
||||||
// calculate hours:minutes string width
|
// calculate hours:minutes string width
|
||||||
uint16_t timeStringWidth = strlen(timeString) * 5;
|
uint16_t timeStringWidth = len * 5; // base spacing between characters
|
||||||
|
|
||||||
for (uint8_t i = 0; i < strlen(timeString); i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
char character = timeString[i];
|
char character = timeString[i];
|
||||||
|
|
||||||
if (character == ':') {
|
if (character == ':') {
|
||||||
@@ -257,19 +284,21 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t hourMinuteTextX = (display->getWidth() / 2) - (timeStringWidth / 2);
|
uint16_t hourMinuteTextX = (display->getWidth() / 2) - (timeStringWidth / 2);
|
||||||
|
|
||||||
uint16_t startingHourMinuteTextX = hourMinuteTextX;
|
uint16_t startingHourMinuteTextX = hourMinuteTextX;
|
||||||
|
|
||||||
uint16_t hourMinuteTextY = (display->getHeight() / 2) - (((segmentWidth * 2) + (segmentHeight * 3) + 8) / 2);
|
uint16_t hourMinuteTextY = (display->getHeight() / 2) - (((segmentWidth * 2) + (segmentHeight * 3) + 8) / 2) + 2;
|
||||||
|
|
||||||
// iterate over characters in hours:minutes string and draw segmented characters
|
// iterate over characters in hours:minutes string and draw segmented characters
|
||||||
for (uint8_t i = 0; i < strlen(timeString); i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
char character = timeString[i];
|
char character = timeString[i];
|
||||||
|
|
||||||
if (character == ':') {
|
if (character == ':') {
|
||||||
drawSegmentedDisplayColon(display, hourMinuteTextX, hourMinuteTextY, scale);
|
drawSegmentedDisplayColon(display, hourMinuteTextX, hourMinuteTextY, scale);
|
||||||
|
|
||||||
hourMinuteTextX += segmentHeight + 6;
|
hourMinuteTextX += segmentHeight + 6;
|
||||||
|
if (scale >= 2.0f) {
|
||||||
|
hourMinuteTextX += (uint16_t)(4.5f * scale);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
drawSegmentedDisplayCharacter(display, hourMinuteTextX, hourMinuteTextY, character - '0', scale);
|
drawSegmentedDisplayCharacter(display, hourMinuteTextX, hourMinuteTextY, character - '0', scale);
|
||||||
|
|
||||||
@@ -279,38 +308,29 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
hourMinuteTextX += 5;
|
hourMinuteTextX += 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw seconds string
|
// draw seconds string + AM/PM
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
int xOffset = (isHighResolution) ? 0 : -1;
|
int xOffset = (isHighResolution) ? 0 : -1;
|
||||||
if (hour >= 10) {
|
if (hour >= 10) {
|
||||||
xOffset += (isHighResolution) ? 32 : 18;
|
xOffset += (isHighResolution) ? 32 : 18;
|
||||||
}
|
}
|
||||||
int yOffset = (isHighResolution) ? 3 : 1;
|
|
||||||
#ifdef SENSECAP_INDICATOR
|
|
||||||
yOffset -= 3;
|
|
||||||
#endif
|
|
||||||
#ifdef T_DECK
|
|
||||||
yOffset -= 5;
|
|
||||||
#endif
|
|
||||||
if (config.display.use_12h_clock) {
|
if (config.display.use_12h_clock) {
|
||||||
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2,
|
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - 1, isPM ? "pm" : "am");
|
||||||
isPM ? "pm" : "am");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USE_EINK
|
#ifndef USE_EINK
|
||||||
xOffset = (isHighResolution) ? 18 : 10;
|
xOffset = (isHighResolution) ? 18 : 10;
|
||||||
display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - yOffset,
|
if (scale >= 2.0f) {
|
||||||
|
xOffset -= (int)(4.5f * scale);
|
||||||
|
}
|
||||||
|
display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - 1,
|
||||||
secondString);
|
secondString);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
graphics::drawCommonFooter(display, x, y);
|
graphics::drawCommonFooter(display, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y)
|
|
||||||
{
|
|
||||||
display->drawFastImage(x, y, 18, 14, bluetoothConnectedIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw an analog clock
|
// Draw an analog clock
|
||||||
void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
@@ -321,11 +341,6 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
||||||
int line = 0;
|
int line = 0;
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
|
||||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
|
||||||
drawBluetoothConnectedIcon(display, display->getWidth() - 18, display->getHeight() - 14);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// clock face center coordinates
|
// clock face center coordinates
|
||||||
int16_t centerX = display->getWidth() / 2;
|
int16_t centerX = display->getWidth() / 2;
|
||||||
int16_t centerY = display->getHeight() / 2;
|
int16_t centerY = display->getHeight() / 2;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ void drawVerticalSegment(OLEDDisplay *display, int x, int y, int width, int heig
|
|||||||
|
|
||||||
// UI elements for clock displays
|
// UI elements for clock displays
|
||||||
// void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode = true, float scale = 1);
|
// void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode = true, float scale = 1);
|
||||||
void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y);
|
|
||||||
|
|
||||||
} // namespace ClockRenderer
|
} // namespace ClockRenderer
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
|
#include "graphics/TimeFormatters.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh/Channels.h"
|
#include "mesh/Channels.h"
|
||||||
@@ -650,17 +651,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
|
|
||||||
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line <= 5)) { // Only show uptime if the screen can show it
|
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line <= 5)) { // Only show uptime if the screen can show it
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
uint32_t uptime = millis() / 1000;
|
getUptimeStr(millis(), "Up", uptimeStr, sizeof(uptimeStr));
|
||||||
uint32_t days = uptime / 86400;
|
|
||||||
uint32_t hours = (uptime % 86400) / 3600;
|
|
||||||
uint32_t mins = (uptime % 3600) / 60;
|
|
||||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
|
||||||
if (days)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Up: %ud %uh", days, hours);
|
|
||||||
else if (hours)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Up: %uh %um", hours, mins);
|
|
||||||
else
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
|
||||||
textWidth = display->getStringWidth(uptimeStr);
|
textWidth = display->getStringWidth(uptimeStr);
|
||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], uptimeStr);
|
display->drawString(nameX, getTextPositions(display)[line++], uptimeStr);
|
||||||
@@ -729,4 +720,4 @@ void drawChirpy(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int1
|
|||||||
|
|
||||||
} // namespace DebugRenderer
|
} // namespace DebugRenderer
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -574,21 +574,16 @@ void menuHandler::textMessageBaseMenu()
|
|||||||
|
|
||||||
void menuHandler::systemBaseMenu()
|
void menuHandler::systemBaseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, Notifications, ScreenOptions, Bluetooth, PowerMenu, FrameToggles, Test, enumEnd };
|
enum optionsNumbers { Back, Notifications, ScreenOptions, Bluetooth, PowerMenu, Test, enumEnd };
|
||||||
static const char *optionsArray[enumEnd] = {"Back"};
|
static const char *optionsArray[enumEnd] = {"Back"};
|
||||||
static int optionsEnumArray[enumEnd] = {Back};
|
static int optionsEnumArray[enumEnd] = {Back};
|
||||||
int options = 1;
|
int options = 1;
|
||||||
|
|
||||||
optionsArray[options] = "Notifications";
|
optionsArray[options] = "Notifications";
|
||||||
optionsEnumArray[options++] = Notifications;
|
optionsEnumArray[options++] = Notifications;
|
||||||
#if defined(ST7789_CS) || defined(ST7796_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || \
|
optionsArray[options] = "Display Options";
|
||||||
defined(USE_SH1107) || defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
|
||||||
optionsArray[options] = "Screen Options";
|
|
||||||
optionsEnumArray[options++] = ScreenOptions;
|
optionsEnumArray[options++] = ScreenOptions;
|
||||||
#endif
|
|
||||||
|
|
||||||
optionsArray[options] = "Frame Visiblity Toggle";
|
|
||||||
optionsEnumArray[options++] = FrameToggles;
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
optionsArray[options] = "Bluetooth";
|
optionsArray[options] = "Bluetooth";
|
||||||
#else
|
#else
|
||||||
@@ -626,9 +621,6 @@ void menuHandler::systemBaseMenu()
|
|||||||
} else if (selected == PowerMenu) {
|
} else if (selected == PowerMenu) {
|
||||||
menuHandler::menuQueue = menuHandler::power_menu;
|
menuHandler::menuQueue = menuHandler::power_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
} else if (selected == FrameToggles) {
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == Test) {
|
} else if (selected == Test) {
|
||||||
menuHandler::menuQueue = menuHandler::test_menu;
|
menuHandler::menuQueue = menuHandler::test_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
@@ -1339,7 +1331,7 @@ void menuHandler::screenOptionsMenu()
|
|||||||
hasSupportBrightness = false;
|
hasSupportBrightness = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum optionsNumbers { Back, NodeNameLength, Brightness, ScreenColor };
|
enum optionsNumbers { Back, NodeNameLength, Brightness, ScreenColor, FrameToggles, DisplayUnits };
|
||||||
static const char *optionsArray[5] = {"Back"};
|
static const char *optionsArray[5] = {"Back"};
|
||||||
static int optionsEnumArray[5] = {Back};
|
static int optionsEnumArray[5] = {Back};
|
||||||
int options = 1;
|
int options = 1;
|
||||||
@@ -1361,8 +1353,14 @@ void menuHandler::screenOptionsMenu()
|
|||||||
optionsEnumArray[options++] = ScreenColor;
|
optionsEnumArray[options++] = ScreenColor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
optionsArray[options] = "Frame Visibility Toggle";
|
||||||
|
optionsEnumArray[options++] = FrameToggles;
|
||||||
|
|
||||||
|
optionsArray[options] = "Display Units";
|
||||||
|
optionsEnumArray[options++] = DisplayUnits;
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Screen Options";
|
bannerOptions.message = "Display Options";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
@@ -1376,6 +1374,12 @@ void menuHandler::screenOptionsMenu()
|
|||||||
} else if (selected == NodeNameLength) {
|
} else if (selected == NodeNameLength) {
|
||||||
menuHandler::menuQueue = menuHandler::node_name_length_menu;
|
menuHandler::menuQueue = menuHandler::node_name_length_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
|
} else if (selected == FrameToggles) {
|
||||||
|
menuHandler::menuQueue = menuHandler::FrameToggles;
|
||||||
|
screen->runNow();
|
||||||
|
} else if (selected == DisplayUnits) {
|
||||||
|
menuHandler::menuQueue = menuHandler::DisplayUnits;
|
||||||
|
screen->runNow();
|
||||||
} else {
|
} else {
|
||||||
menuQueue = system_base_menu;
|
menuQueue = system_base_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
@@ -1587,6 +1591,34 @@ void menuHandler::FrameToggles_menu()
|
|||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void menuHandler::DisplayUnits_menu()
|
||||||
|
{
|
||||||
|
enum optionsNumbers { Back, MetricUnits, ImperialUnits };
|
||||||
|
|
||||||
|
static const char *optionsArray[] = {"Back", "Metric", "Imperial"};
|
||||||
|
BannerOverlayOptions bannerOptions;
|
||||||
|
bannerOptions.message = " Select display units";
|
||||||
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
|
bannerOptions.optionsCount = 3;
|
||||||
|
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL)
|
||||||
|
bannerOptions.InitialSelected = 2;
|
||||||
|
else
|
||||||
|
bannerOptions.InitialSelected = 1;
|
||||||
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
|
if (selected == MetricUnits) {
|
||||||
|
config.display.units = meshtastic_Config_DisplayConfig_DisplayUnits_METRIC;
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
} else if (selected == ImperialUnits) {
|
||||||
|
config.display.units = meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL;
|
||||||
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
|
} else {
|
||||||
|
menuHandler::menuQueue = menuHandler::screen_options_menu;
|
||||||
|
screen->runNow();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
screen->showOverlayBanner(bannerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
||||||
{
|
{
|
||||||
if (menuQueue != menu_none)
|
if (menuQueue != menu_none)
|
||||||
@@ -1701,6 +1733,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
case FrameToggles:
|
case FrameToggles:
|
||||||
FrameToggles_menu();
|
FrameToggles_menu();
|
||||||
break;
|
break;
|
||||||
|
case DisplayUnits:
|
||||||
|
DisplayUnits_menu();
|
||||||
|
break;
|
||||||
case throttle_message:
|
case throttle_message:
|
||||||
screen->showSimpleBanner("Too Many Attempts\nTry again in 60 seconds.", 5000);
|
screen->showSimpleBanner("Too Many Attempts\nTry again in 60 seconds.", 5000);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ class menuHandler
|
|||||||
trace_route_menu,
|
trace_route_menu,
|
||||||
throttle_message,
|
throttle_message,
|
||||||
node_name_length_menu,
|
node_name_length_menu,
|
||||||
FrameToggles
|
FrameToggles,
|
||||||
|
DisplayUnits
|
||||||
};
|
};
|
||||||
static screenMenus menuQueue;
|
static screenMenus menuQueue;
|
||||||
|
|
||||||
@@ -88,6 +89,7 @@ class menuHandler
|
|||||||
static void powerMenu();
|
static void powerMenu();
|
||||||
static void nodeNameLengthMenu();
|
static void nodeNameLengthMenu();
|
||||||
static void FrameToggles_menu();
|
static void FrameToggles_menu();
|
||||||
|
static void DisplayUnits_menu();
|
||||||
static void textMessageMenu();
|
static void textMessageMenu();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -425,6 +425,12 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
{
|
{
|
||||||
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
||||||
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
||||||
|
bool locationScreen = false;
|
||||||
|
|
||||||
|
if (strcmp(title, "Bearings") == 0)
|
||||||
|
locationScreen = true;
|
||||||
|
else if (strcmp(title, "Distance") == 0)
|
||||||
|
locationScreen = true;
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
int columnWidth = display->getWidth();
|
int columnWidth = display->getWidth();
|
||||||
#else
|
#else
|
||||||
@@ -440,7 +446,7 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
|
|
||||||
int totalEntries = nodeDB->getNumMeshNodes();
|
int totalEntries = nodeDB->getNumMeshNodes();
|
||||||
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
||||||
|
int numskipped = 0;
|
||||||
int visibleNodeRows = totalRowsAvailable;
|
int visibleNodeRows = totalRowsAvailable;
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
int totalColumns = 1;
|
int totalColumns = 1;
|
||||||
@@ -460,6 +466,10 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
int rowCount = 0;
|
int rowCount = 0;
|
||||||
|
|
||||||
for (int i = startIndex; i < endIndex; ++i) {
|
for (int i = startIndex; i < endIndex; ++i) {
|
||||||
|
if (locationScreen && !nodeDB->getMeshNodeByIndex(i)->has_position) {
|
||||||
|
numskipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int xPos = x + (col * columnWidth);
|
int xPos = x + (col * columnWidth);
|
||||||
int yPos = y + yOffset;
|
int yPos = y + yOffset;
|
||||||
renderer(display, nodeDB->getMeshNodeByIndex(i), xPos, yPos, columnWidth);
|
renderer(display, nodeDB->getMeshNodeByIndex(i), xPos, yPos, columnWidth);
|
||||||
@@ -482,6 +492,9 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should correct the scrollbar
|
||||||
|
totalEntries -= numskipped;
|
||||||
|
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(M5STACK_UNITC6L)
|
||||||
// Draw column separator
|
// Draw column separator
|
||||||
if (shownCount > 0) {
|
if (shownCount > 0) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
|
#include "graphics/TimeFormatters.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
@@ -383,17 +384,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
|||||||
// === 4. Uptime (only show if metric is present) ===
|
// === 4. Uptime (only show if metric is present) ===
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||||
uint32_t uptime = node->device_metrics.uptime_seconds;
|
getUptimeStr(node->device_metrics.uptime_seconds * 1000, " Up", uptimeStr, sizeof(uptimeStr));
|
||||||
uint32_t days = uptime / 86400;
|
|
||||||
uint32_t hours = (uptime % 86400) / 3600;
|
|
||||||
uint32_t mins = (uptime % 3600) / 60;
|
|
||||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
|
||||||
if (days)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %ud %uh", days, hours);
|
|
||||||
else if (hours)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %uh %um", hours, mins);
|
|
||||||
else
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
|
||||||
}
|
}
|
||||||
if (uptimeStr[0] && line < 5) {
|
if (uptimeStr[0] && line < 5) {
|
||||||
display->drawString(x, getTextPositions(display)[line++], uptimeStr);
|
display->drawString(x, getTextPositions(display)[line++], uptimeStr);
|
||||||
@@ -592,18 +583,8 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||||
#endif
|
#endif
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
uint32_t uptime = millis() / 1000;
|
|
||||||
uint32_t days = uptime / 86400;
|
|
||||||
uint32_t hours = (uptime % 86400) / 3600;
|
|
||||||
uint32_t mins = (uptime % 3600) / 60;
|
|
||||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(M5STACK_UNITC6L)
|
||||||
if (days)
|
getUptimeStr(millis(), "Up", uptimeStr, sizeof(uptimeStr));
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %ud %uh", days, hours);
|
|
||||||
else if (hours)
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %uh %um", hours, mins);
|
|
||||||
else
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %um", mins);
|
|
||||||
#endif
|
#endif
|
||||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
||||||
|
|
||||||
@@ -1048,36 +1029,17 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
|||||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
||||||
// === Second Row: Last GPS Fix ===
|
// === Second Row: Last GPS Fix ===
|
||||||
if (gpsStatus->getLastFixMillis() > 0) {
|
if (gpsStatus->getLastFixMillis() > 0) {
|
||||||
uint32_t delta = (millis() - gpsStatus->getLastFixMillis()) / 1000; // seconds since last fix
|
uint32_t delta = millis() - gpsStatus->getLastFixMillis();
|
||||||
uint32_t days = delta / 86400;
|
char uptimeStr[32];
|
||||||
uint32_t hours = (delta % 86400) / 3600;
|
|
||||||
uint32_t mins = (delta % 3600) / 60;
|
|
||||||
uint32_t secs = delta % 60;
|
|
||||||
|
|
||||||
char buf[32];
|
|
||||||
#if defined(USE_EINK)
|
#if defined(USE_EINK)
|
||||||
// E-Ink: skip seconds, show only days/hours/mins
|
// E-Ink: skip seconds, show only days/hours/mins
|
||||||
if (days > 0) {
|
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), false);
|
||||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
|
||||||
} else if (hours > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
|
||||||
} else {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %um", mins);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
// Non E-Ink: include seconds where useful
|
// Non E-Ink: include seconds where useful
|
||||||
if (days > 0) {
|
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), true);
|
||||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
|
||||||
} else if (hours > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
|
||||||
} else if (mins > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %um %us", mins, secs);
|
|
||||||
} else {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %us", secs);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
display->drawString(0, getTextPositions(display)[line++], buf);
|
display->drawString(0, getTextPositions(display)[line++], uptimeStr);
|
||||||
} else {
|
} else {
|
||||||
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
||||||
}
|
}
|
||||||
@@ -1422,4 +1384,4 @@ std::string UIRenderer::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t mi
|
|||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
|
||||||
#endif // HAS_SCREEN
|
#endif // HAS_SCREEN
|
||||||
|
|||||||
+144
-191
@@ -18,6 +18,8 @@ const Emote emotes[] = {
|
|||||||
{"\U0001F642", Slightly_Smiling, Slightly_Smiling_width, Slightly_Smiling_height}, // 🙂 Slightly Smiling Face
|
{"\U0001F642", Slightly_Smiling, Slightly_Smiling_width, Slightly_Smiling_height}, // 🙂 Slightly Smiling Face
|
||||||
{"\U0001F609", Winking_Face, Winking_Face_width, Winking_Face_height}, // 😉 Winking Face
|
{"\U0001F609", Winking_Face, Winking_Face_width, Winking_Face_height}, // 😉 Winking Face
|
||||||
{"\U0001F601", Grinning_Smiling_Eyes, Grinning_Smiling_Eyes_width, Grinning_Smiling_Eyes_height}, // 😁 Grinning Smiling Eyes
|
{"\U0001F601", Grinning_Smiling_Eyes, Grinning_Smiling_Eyes_width, Grinning_Smiling_Eyes_height}, // 😁 Grinning Smiling Eyes
|
||||||
|
{"\U0001F60D", Heart_eyes, Heart_eyes_width, Heart_eyes_height}, // 😍 Heart Eyes
|
||||||
|
{"\U0001F970", heart_smile, heart_smile_width, heart_smile_height}, // 🥰 Smiling Face with Hearts
|
||||||
|
|
||||||
// --- Question/Alert ---
|
// --- Question/Alert ---
|
||||||
{"\u2753", question, question_width, question_height}, // ❓ Question Mark
|
{"\u2753", question, question_width, question_height}, // ❓ Question Mark
|
||||||
@@ -30,11 +32,15 @@ const Emote emotes[] = {
|
|||||||
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
||||||
{"\U0001F604", Grinning_SmilingEyes2, Grinning_SmilingEyes2_width,
|
{"\U0001F604", Grinning_SmilingEyes2, Grinning_SmilingEyes2_width,
|
||||||
Grinning_SmilingEyes2_height}, // 😄 Grinning Face with Smiling Eyes
|
Grinning_SmilingEyes2_height}, // 😄 Grinning Face with Smiling Eyes
|
||||||
|
{"\U0001F62D", Loudly_Crying_Face, Loudly_Crying_Face_width, Loudly_Crying_Face_height}, // 😭 Loudly Crying Face
|
||||||
|
|
||||||
// --- Gestures and People ---
|
// --- Gestures and People ---
|
||||||
{"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand
|
{"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand
|
||||||
{"\U0001F920", cowboy, cowboy_width, cowboy_height}, // 🤠 Cowboy Hat Face
|
{"\u270C\uFE0F", peace_sign, peace_sign_width, peace_sign_height}, // ✌️ Victory Hand
|
||||||
{"\U0001F3A7", deadmau5, deadmau5_width, deadmau5_height}, // 🎧 Headphones
|
{"\U0001F596", vulcan_salute, vulcan_salute_width, vulcan_salute_height}, // 🖖 Vulcan Salute
|
||||||
|
{"\U0001F64F", Praying, Praying_width, Praying_height}, // 🙏 Praying Hands
|
||||||
|
{"\U0001F920", cowboy, cowboy_width, cowboy_height}, // 🤠 Cowboy Hat Face
|
||||||
|
{"\U0001F3A7", deadmau5, deadmau5_width, deadmau5_height}, // 🎧 Headphones
|
||||||
|
|
||||||
// --- Weather ---
|
// --- Weather ---
|
||||||
{"\u2600", sun, sun_width, sun_height}, // ☀ Sun (without variation selector)
|
{"\u2600", sun, sun_width, sun_height}, // ☀ Sun (without variation selector)
|
||||||
@@ -45,8 +51,12 @@ const Emote emotes[] = {
|
|||||||
|
|
||||||
// --- Misc Faces ---
|
// --- Misc Faces ---
|
||||||
{"\U0001F608", devil, devil_width, devil_height}, // 😈 Smiling Face with Horns
|
{"\U0001F608", devil, devil_width, devil_height}, // 😈 Smiling Face with Horns
|
||||||
|
{"\U0001F921", clown, clown_width, clown_height}, // 🤡 Clown Face
|
||||||
|
{"\U0001F916", robo, robo_width, robo_height}, // 🤖 Robot Face
|
||||||
|
|
||||||
// --- Hearts (Multiple Unicode Aliases) ---
|
// --- Hearts (Multiple Unicode Aliases) ---
|
||||||
|
{"\u2665", heart, heart_width, heart_height}, // ♥ Black Heart Suit
|
||||||
|
{"\u2665\uFE0F", heart, heart_width, heart_height}, // ♥️ Black Heart Suit (emoji presentation)
|
||||||
{"\u2764\uFE0F", heart, heart_width, heart_height}, // ❤️ Red Heart
|
{"\u2764\uFE0F", heart, heart_width, heart_height}, // ❤️ Red Heart
|
||||||
{"\U0001F9E1", heart, heart_width, heart_height}, // 🧡 Orange Heart
|
{"\U0001F9E1", heart, heart_width, heart_height}, // 🧡 Orange Heart
|
||||||
{"\U00002763", heart, heart_width, heart_height}, // ❣ Heart Exclamation
|
{"\U00002763", heart, heart_width, heart_height}, // ❣ Heart Exclamation
|
||||||
@@ -57,223 +67,166 @@ const Emote emotes[] = {
|
|||||||
{"\U0001F498", heart, heart_width, heart_height}, // 💘 Heart with Arrow
|
{"\U0001F498", heart, heart_width, heart_height}, // 💘 Heart with Arrow
|
||||||
|
|
||||||
// --- Objects ---
|
// --- Objects ---
|
||||||
{"\U0001F4A9", poo, poo_width, poo_height}, // 💩 Pile of Poo
|
{"\U0001F4A9", poo, poo_width, poo_height}, // 💩 Pile of Poo
|
||||||
{"\U0001F514", bell_icon, bell_icon_width, bell_icon_height} // 🔔 Bell
|
{"\U0001F514", bell_icon, bell_icon_width, bell_icon_height}, // 🔔 Bell
|
||||||
|
{"\U0001F36A", cookie, cookie_width, cookie_height}, // 🍪 Cookie
|
||||||
|
{"\U0001F525", Fire, Fire_width, Fire_height}, // 🔥 Fire
|
||||||
|
{"\u2728", Sparkles, Sparkles_width, Sparkles_height}, // ✨ Sparkles
|
||||||
|
{"\U0001F573\uFE0F", hole, hole_width, hole_height}, // 🕳️ Hole
|
||||||
|
{"\U0001F3B3", bowling, bowling_width, bowling_height} // 🎳 Bowling
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
const int numEmotes = sizeof(emotes) / sizeof(emotes[0]);
|
const int numEmotes = sizeof(emotes) / sizeof(emotes[0]);
|
||||||
|
|
||||||
#ifndef EXCLUDE_EMOJI
|
#ifndef EXCLUDE_EMOJI
|
||||||
const unsigned char thumbup[] PROGMEM = {
|
const unsigned char thumbup[] PROGMEM = {0x00, 0x03, 0x80, 0x04, 0x80, 0x04, 0x40, 0x04, 0x20, 0x02, 0x18,
|
||||||
0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00,
|
0x02, 0x06, 0x3F, 0x06, 0x40, 0x06, 0x70, 0x06, 0x40, 0x06, 0x70,
|
||||||
0xC0, 0x08, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00,
|
0x06, 0x40, 0x06, 0x30, 0x08, 0x20, 0xF0, 0x1F, 0x00, 0x00};
|
||||||
0x0C, 0xCE, 0x7F, 0x00, 0x04, 0x20, 0x80, 0x00, 0x02, 0x20, 0x80, 0x00, 0x02, 0x60, 0xC0, 0x00, 0x01, 0xF8, 0xFF, 0x01,
|
|
||||||
0x01, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01, 0x01, 0xF8, 0xFF, 0x00, 0x01, 0x10, 0x80, 0x00, 0x01, 0x18, 0x80, 0x00,
|
|
||||||
0x02, 0x30, 0xC0, 0x00, 0x06, 0xE0, 0x3F, 0x00, 0x0C, 0x20, 0x30, 0x00, 0x38, 0x20, 0x10, 0x00, 0xE0, 0xCF, 0x1F, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char thumbdown[] PROGMEM = {
|
const unsigned char thumbdown[] PROGMEM = {0xF0, 0x1F, 0x08, 0x20, 0x06, 0x30, 0x06, 0x40, 0x06, 0x70, 0x06,
|
||||||
0xE0, 0xCF, 0x1F, 0x00, 0x38, 0x20, 0x10, 0x00, 0x0C, 0x20, 0x30, 0x00, 0x06, 0xE0, 0x3F, 0x00, 0x02, 0x30, 0xC0, 0x00,
|
0x40, 0x06, 0x70, 0x06, 0x40, 0x06, 0x3F, 0x18, 0x02, 0x20, 0x02,
|
||||||
0x01, 0x18, 0x80, 0x00, 0x01, 0x10, 0x80, 0x00, 0x01, 0xF8, 0xFF, 0x00, 0x01, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01,
|
0x40, 0x04, 0x80, 0x04, 0x80, 0x04, 0x00, 0x03, 0x00, 0x00};
|
||||||
0x01, 0xF8, 0xFF, 0x01, 0x02, 0x60, 0xC0, 0x00, 0x02, 0x20, 0x80, 0x00, 0x04, 0x20, 0x80, 0x00, 0x0C, 0xCE, 0x7F, 0x00,
|
|
||||||
0x18, 0x02, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00,
|
|
||||||
0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char Smiling_Eyes[] PROGMEM = {
|
const unsigned char Smiling_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
0x4A, 0x02, 0x40, 0x02, 0x40, 0x22, 0x44, 0x22, 0x44, 0xC2, 0x43,
|
||||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf,
|
0x04, 0x20, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0x7e, 0xf8, 0xc3, 0xdf, 0x3e, 0xf0, 0x81, 0xdf, 0xbf, 0xf7, 0xbd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0x3f, 0xff,
|
|
||||||
0x6f, 0xff, 0xdf, 0xfe, 0x6f, 0xff, 0xdf, 0xfe, 0x9f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
|
||||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
|
||||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char Grinning[] PROGMEM = {
|
const unsigned char Grinning[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
0x42, 0x02, 0x40, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf,
|
|
||||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
|
||||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char Slightly_Smiling[] PROGMEM = {
|
const unsigned char Slightly_Smiling[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
0x42, 0x02, 0x40, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
|
||||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
|
||||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char Winking_Face[] PROGMEM = {
|
const unsigned char Winking_Face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x20, 0x42,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
0x46, 0x02, 0x40, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||||
0xf0, 0xf0, 0xff, 0xc3, 0x78, 0xef, 0xc3, 0xc7, 0xb8, 0xdf, 0xbd, 0xcf, 0xfc, 0xf9, 0x7f, 0xcf, 0xfc, 0xf0, 0xff, 0xcf,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xfe, 0xf0, 0xc3, 0xdf, 0xfe, 0xf0, 0x81, 0xdf, 0xff, 0xf0, 0xbf, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
|
||||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
|
||||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char Grinning_Smiling_Eyes[] PROGMEM = {
|
const unsigned char Grinning_Smiling_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
0x4A, 0x02, 0x40, 0xFA, 0x5F, 0x0A, 0x50, 0x0A, 0x50, 0x12, 0x48,
|
||||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf8, 0xe3, 0xcf, 0x7c, 0xf7, 0xdd, 0xcf,
|
0x24, 0x24, 0xC4, 0x23, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xbe, 0xef, 0xbe, 0xdf, 0xbe, 0xef, 0xbe, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x5e, 0x55, 0x55, 0xdf, 0x5e, 0x55, 0x55, 0xdf,
|
|
||||||
0x3c, 0x00, 0x80, 0xcf, 0x7c, 0x55, 0xd5, 0xcf, 0xf8, 0x54, 0xe5, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
|
||||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char question[] PROGMEM = {
|
const unsigned char heart_smile[] PROGMEM = {0x00, 0x00, 0x6C, 0x07, 0x7C, 0x18, 0x7C, 0x20, 0x38, 0x24, 0x52,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00,
|
0x0A, 0x02, 0xD8, 0x02, 0xF8, 0x22, 0xFC, 0x20, 0x74, 0xDB, 0x23,
|
||||||
0xE0, 0xC3, 0x0F, 0x00, 0xF0, 0x81, 0x0F, 0x00, 0xF0, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x0F, 0x00,
|
0x1F, 0x00, 0x1F, 0x20, 0x0E, 0x18, 0xE4, 0x07, 0x00, 0x00};
|
||||||
0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x7C, 0x00, 0x00,
|
|
||||||
0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char bang[] PROGMEM = {
|
const unsigned char Heart_eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x54, 0x2A, 0xFA,
|
||||||
0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x07, 0xF8, 0x3F, 0xFF, 0x07, 0xF8, 0x3F,
|
0x5F, 0x72, 0x4E, 0x22, 0x44, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48,
|
||||||
0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F,
|
0x24, 0x24, 0xC4, 0x23, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xFE, 0x03, 0xF0, 0x1F, 0xFE, 0x03, 0xF0, 0x1F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F,
|
|
||||||
0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x01, 0xE0, 0x0F, 0xFC, 0x01, 0xE0, 0x0F,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0xFC, 0x03, 0xF0, 0x0F, 0xFE, 0x03, 0xF0, 0x1F,
|
|
||||||
0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFC, 0x03, 0xF0, 0x0F, 0xF8, 0x01, 0xE0, 0x07,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char haha[] PROGMEM = {
|
const unsigned char question[] PROGMEM = {0xE0, 0x07, 0x10, 0x08, 0x08, 0x10, 0x88, 0x11, 0x48, 0x12, 0x48,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xf9, 0xf3, 0xc0,
|
0x12, 0x48, 0x12, 0x30, 0x11, 0x80, 0x08, 0x40, 0x04, 0x40, 0x02,
|
||||||
0xf0, 0xfe, 0xef, 0xc1, 0x38, 0xff, 0x9f, 0xc3, 0xd8, 0xff, 0x7f, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xcf,
|
0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x40, 0x02, 0x80, 0x01};
|
||||||
0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xef, 0xff, 0xff, 0xde, 0xe7, 0xff, 0xff, 0xdc, 0xeb, 0xff, 0xff, 0xda,
|
|
||||||
0xed, 0xff, 0xff, 0xd6, 0xee, 0xff, 0xff, 0xce, 0x36, 0x00, 0x80, 0xcd, 0xb8, 0xff, 0xbf, 0xc3, 0x7e, 0x00, 0xc0, 0xdf,
|
|
||||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
|
||||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char ROFL[] PROGMEM = {
|
const unsigned char bang[] PROGMEM = {0x30, 0x0C, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48,
|
||||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0x07, 0xc0, 0x00, 0xff, 0x1f, 0xc0, 0x80, 0xff, 0x7f, 0xc0, 0xc0, 0xff, 0xff, 0xc0,
|
0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x30, 0x0C,
|
||||||
0xe0, 0x9f, 0xff, 0xc1, 0xf0, 0x9f, 0xff, 0xc0, 0xf8, 0x9f, 0x7f, 0xcb, 0xf8, 0x9f, 0xbf, 0xcb, 0xfc, 0x9f, 0xdf, 0xdb,
|
0x00, 0x00, 0x30, 0x0C, 0x48, 0x12, 0x30, 0x0C, 0x00, 0x00};
|
||||||
0xfc, 0x1f, 0x08, 0xdc, 0xfe, 0x1f, 0xf8, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0x1e, 0xf0, 0x7f, 0xfe, 0x1e, 0xf0, 0xbf, 0xfe,
|
|
||||||
0xfe, 0xf3, 0xdf, 0xfe, 0xfe, 0xf3, 0x6f, 0xfe, 0xfe, 0xf3, 0x37, 0xfe, 0xfe, 0xeb, 0x1b, 0xfe, 0xfc, 0xef, 0x0d, 0xde,
|
|
||||||
0xfc, 0xe7, 0x06, 0xcf, 0xf8, 0x6b, 0x83, 0xcf, 0xf8, 0x0d, 0xc0, 0xc7, 0xf0, 0xed, 0xff, 0xc7, 0xe0, 0xee, 0xff, 0xc3,
|
|
||||||
0xc0, 0xee, 0xff, 0xc1, 0x80, 0xee, 0xff, 0xc0, 0x00, 0xe6, 0x3f, 0xc0, 0x00, 0xf0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char Smiling_Closed_Eyes[] PROGMEM = {
|
const unsigned char haha[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
0x4A, 0x0A, 0x50, 0x0E, 0x70, 0xF2, 0x4F, 0x12, 0x48, 0x32, 0x44,
|
||||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0x7c, 0xfe, 0xcf, 0xcf, 0xfc, 0xfc, 0xe7, 0xcf,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xfe, 0xf9, 0xf3, 0xdf, 0xfe, 0xf3, 0xf9, 0xdf, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xfc, 0xe7, 0xff, 0x7f, 0xfe, 0xcf, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf,
|
|
||||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
|
||||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char Grinning_SmilingEyes2[] PROGMEM = {
|
const unsigned char ROFL[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x84, 0x21, 0x84, 0x20, 0x02,
|
||||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xff, 0xff, 0xc0,
|
0x4C, 0x02, 0x4A, 0x1A, 0x49, 0x8A, 0x48, 0x42, 0x48, 0x22, 0x44,
|
||||||
0xf0, 0xff, 0xff, 0xc1, 0xf8, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xc7,
|
0xE4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf,
|
|
||||||
0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0x3f, 0x00, 0x80, 0xdf, 0xbe, 0xff, 0xbf, 0xcf, 0x7e, 0x00, 0xc0, 0xcf,
|
|
||||||
0x7c, 0x00, 0xc0, 0xc7, 0xfc, 0x00, 0xe0, 0xc7, 0xf8, 0x01, 0xf0, 0xc3, 0xf8, 0x03, 0xf8, 0xc3, 0xf0, 0xff, 0xff, 0xc1,
|
|
||||||
0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char wave_icon[] PROGMEM = {
|
const unsigned char Smiling_Closed_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x42,
|
||||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0xc0, 0xc1, 0x00, 0x00, 0x00, 0xc7,
|
0x42, 0x22, 0x44, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||||
0x00, 0x00, 0x1e, 0xcc, 0x00, 0x00, 0x30, 0xc8, 0x00, 0x00, 0x60, 0xd8, 0x00, 0x08, 0xc0, 0xd0, 0x00, 0x1a, 0x81, 0xd1,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0x00, 0x36, 0x03, 0xd3, 0x80, 0x6d, 0x06, 0xd2, 0x00, 0xdb, 0x0c, 0xc2, 0x80, 0xb6, 0x1d, 0xc0, 0x80, 0x6d, 0x1f, 0xc0,
|
|
||||||
0x00, 0xdb, 0x3f, 0xc0, 0x00, 0xf6, 0x7f, 0xc0, 0x00, 0xfc, 0x7f, 0xc0, 0x08, 0xf8, 0x7f, 0xc0, 0x48, 0xf0, 0x7f, 0xc0,
|
|
||||||
0x48, 0xe0, 0x7f, 0xc0, 0xc8, 0xc0, 0x3f, 0xc0, 0x98, 0x81, 0x1f, 0xc0, 0x10, 0x03, 0x00, 0xc0, 0x30, 0x0e, 0x00, 0xc0,
|
|
||||||
0x20, 0x38, 0x00, 0xc0, 0xe0, 0x00, 0x00, 0xc0, 0x80, 0x07, 0x00, 0xc0, 0x00, 0x1e, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char cowboy[] PROGMEM = {
|
const unsigned char Grinning_SmilingEyes2[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||||
0x00, 0x0c, 0x0c, 0xc0, 0x00, 0x02, 0x10, 0xc0, 0x00, 0x01, 0x20, 0xc0, 0xbc, 0x00, 0x40, 0xcf, 0xc2, 0x01, 0xe0, 0xd0,
|
0x4A, 0x02, 0x40, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||||
0x01, 0x01, 0x20, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0xc1, 0x3f, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe1, 0xf2, 0xf3, 0xf3, 0xd3, 0xf4, 0xf1, 0xe3, 0xcb, 0xfc, 0xf1, 0xe3, 0xc7,
|
|
||||||
0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xfb, 0xf7, 0xc7, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xc7,
|
|
||||||
0x70, 0xf8, 0x8f, 0xc3, 0x70, 0x03, 0xb0, 0xc3, 0x70, 0xfe, 0xbf, 0xc3, 0x60, 0x00, 0x80, 0xc1, 0xc0, 0x00, 0xc0, 0xc0,
|
|
||||||
0x80, 0x01, 0x60, 0xc0, 0x00, 0x07, 0x38, 0xc0, 0x00, 0xfe, 0x1f, 0xc0, 0x00, 0xf0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char deadmau5[] PROGMEM = {
|
const unsigned char Loudly_Crying_Face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x34, 0x2C, 0x4A,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00,
|
0x52, 0x12, 0x48, 0x12, 0x48, 0x92, 0x49, 0x52, 0x4A, 0x52, 0x4A,
|
||||||
0x00, 0xFC, 0x03, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x3F, 0x00,
|
0x54, 0x2A, 0x94, 0x29, 0x18, 0x18, 0xF0, 0x0F, 0x00, 0x00};
|
||||||
0xE0, 0xFF, 0xFF, 0x01, 0xF0, 0xFF, 0x7F, 0x00, 0xF0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x07,
|
|
||||||
0xFC, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x00,
|
|
||||||
0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x3F, 0xFC,
|
|
||||||
0x0F, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0x1F, 0xF8, 0x0F, 0xFC, 0x3F, 0x00, 0x80, 0xFF, 0x0F, 0xF8, 0x1F, 0xFC, 0x1F, 0x00,
|
|
||||||
0x00, 0xFF, 0x0F, 0xFC, 0x3F, 0xFC, 0x0F, 0x00, 0x00, 0xF8, 0x1F, 0xFF, 0xFF, 0xFE, 0x01, 0x00, 0x00, 0x00, 0xFC, 0xFF,
|
|
||||||
0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
|
|
||||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x07, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char sun[] PROGMEM = {
|
const unsigned char wave_icon[] PROGMEM = {0x00, 0x00, 0xC0, 0x18, 0x30, 0x21, 0x48, 0x5A, 0x94, 0x64, 0x24,
|
||||||
0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x30, 0xC0, 0x00, 0x03,
|
0x25, 0x4A, 0x24, 0x12, 0x44, 0x22, 0x44, 0x04, 0x40, 0x08, 0x40,
|
||||||
0x70, 0x00, 0x80, 0x03, 0xF0, 0x00, 0xC0, 0x03, 0xF0, 0xF8, 0xC7, 0x03, 0xE0, 0xFC, 0xCF, 0x01, 0x00, 0xFE, 0x1F, 0x00,
|
0x12, 0x40, 0x22, 0x20, 0xC4, 0x10, 0x18, 0x0F, 0x00, 0x00};
|
||||||
0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x8E, 0xFF, 0x7F, 0x1C, 0x9F, 0xFF, 0x7F, 0x3E,
|
|
||||||
0x9F, 0xFF, 0x7F, 0x3E, 0x8E, 0xFF, 0x7F, 0x1C, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0x3F, 0x00,
|
|
||||||
0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0xC0, 0xF9, 0xE7, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0xF0, 0x01, 0xE0, 0x03,
|
|
||||||
0xF0, 0xC0, 0xC0, 0x03, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char rain[] PROGMEM = {
|
const unsigned char cowboy[] PROGMEM = {0x70, 0x0E, 0x8F, 0xF1, 0x11, 0x88, 0x21, 0x84, 0xC2, 0x43, 0x1E,
|
||||||
0xC0, 0x0F, 0xC0, 0x00, 0x40, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x03, 0x38, 0x00,
|
0x78, 0xE2, 0x47, 0x42, 0x42, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||||
0x00, 0x0E, 0x0C, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x20,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x30, 0x02, 0x00,
|
|
||||||
0x00, 0x10, 0x06, 0x00, 0x00, 0x08, 0xFC, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x01, 0x80, 0x00, 0x01, 0x00,
|
|
||||||
0xC0, 0xC0, 0x81, 0x03, 0xA0, 0x60, 0xC1, 0x03, 0x90, 0x20, 0x41, 0x01, 0xF0, 0xE0, 0xC0, 0x01, 0x60, 0x4C,
|
|
||||||
0x98, 0x00, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0x0B, 0x12, 0x00, 0x00, 0x09, 0x1A, 0x00, 0x00, 0x06, 0x0E, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char cloud[] PROGMEM = {
|
const unsigned char deadmau5[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0xE4, 0x27, 0x12, 0x48, 0x0A,
|
||||||
0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x70, 0x30, 0x00, 0x00, 0x10, 0x60, 0x00, 0x80, 0x1F, 0x40, 0x00,
|
0x50, 0x0E, 0x70, 0x11, 0x88, 0x19, 0x98, 0x19, 0x98, 0x19, 0x98,
|
||||||
0xC0, 0x0F, 0xC0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x60, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x01,
|
0x19, 0x98, 0x19, 0x98, 0x11, 0x88, 0x0E, 0x70, 0x00, 0x00};
|
||||||
0x20, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x10,
|
|
||||||
0x02, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20,
|
|
||||||
0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x10,
|
|
||||||
0x02, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x0C, 0xFC, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x03,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char fog[] PROGMEM = {
|
const unsigned char sun[] PROGMEM = {0x00, 0x00, 0x80, 0x01, 0xEC, 0x37, 0xFC, 0x3F, 0xF8, 0x1F, 0xFC,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x3F, 0xFE, 0x7F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFE, 0x7F, 0xFC, 0x3F,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x3C, 0x00, 0xFE, 0x01, 0xFF, 0x00, 0x87, 0xC7, 0xC3, 0x01, 0x03, 0xFE, 0x80, 0x01,
|
0xF8, 0x1F, 0xFC, 0x3F, 0xEC, 0x37, 0x80, 0x01, 0x00, 0x00};
|
||||||
0x00, 0x38, 0x00, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0xFF, 0x83, 0xFF, 0x01, 0x03, 0xFF, 0x81, 0x01, 0x00, 0x7C, 0x00, 0x00,
|
|
||||||
0xF8, 0x00, 0x3E, 0x00, 0xFE, 0x01, 0xFF, 0x00, 0x87, 0xC7, 0xC3, 0x01, 0x03, 0xFE, 0x80, 0x01, 0x00, 0x38, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char devil[] PROGMEM = {
|
const unsigned char rain[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x1F, 0xFC, 0x3F, 0xFE,
|
||||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x0f, 0xfc, 0x0f, 0xfc,
|
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0x00, 0x00, 0x48, 0x12,
|
||||||
0x3f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfc, 0xff, 0xff, 0xcf,
|
0x48, 0x12, 0x24, 0x09, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00};
|
||||||
0xfc, 0xff, 0xff, 0xcf, 0xf8, 0xff, 0xff, 0xc7, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xf1, 0xe3, 0xc3,
|
|
||||||
0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3,
|
|
||||||
0xf0, 0xff, 0xff, 0xc3, 0xe0, 0xfd, 0xef, 0xc1, 0xe0, 0xf3, 0xf3, 0xc1, 0xc0, 0x07, 0xf8, 0xc0, 0x80, 0x1f, 0x7e, 0xc0,
|
|
||||||
0x00, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char heart[] PROGMEM = {
|
const unsigned char cloud[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x1F, 0xFC,
|
||||||
0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x1F, 0x06, 0x0E, 0xFE, 0x3F, 0x03, 0x18,
|
0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F,
|
||||||
0xFE, 0xFF, 0x7F, 0x10, 0xFF, 0xFF, 0xFF, 0x31, 0xFF, 0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0xFF, 0x37, 0xFF, 0xFF, 0xFF, 0x37,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0x1F,
|
|
||||||
0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x03,
|
|
||||||
0xE0, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0xFE, 0x1F, 0x00,
|
|
||||||
0x00, 0xFC, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char poo[] PROGMEM = {
|
const unsigned char fog[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x54, 0x55, 0x22, 0x22, 0x00,
|
||||||
0x00, 0x1c, 0x00, 0xc0, 0x00, 0x7c, 0x00, 0xc0, 0x00, 0xfc, 0x00, 0xc0, 0x00, 0x7c, 0x03, 0xc0, 0x00, 0xbe, 0x03, 0xc0,
|
0x00, 0x44, 0x44, 0xAA, 0x2A, 0x11, 0x11, 0x00, 0x00, 0x88, 0x88,
|
||||||
0x00, 0xdf, 0x0f, 0xc0, 0x80, 0xcf, 0x0f, 0xc0, 0xc0, 0xf1, 0x0f, 0xc0, 0x60, 0xfc, 0x0f, 0xc0, 0x30, 0xff, 0x07, 0xc0,
|
0x54, 0x55, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
0x90, 0xff, 0x3b, 0xc0, 0xc0, 0xff, 0x7d, 0xc0, 0xf8, 0xff, 0xfc, 0xc0, 0xf8, 0x3f, 0xf0, 0xc0, 0x78, 0x88, 0xc0, 0xc0,
|
|
||||||
0x20, 0xe3, 0x18, 0xc0, 0x98, 0xe7, 0xbc, 0xc1, 0x9c, 0x64, 0xa4, 0xc3, 0x9e, 0x64, 0xa4, 0xc7, 0xbe, 0xe4, 0xa4, 0xc7,
|
|
||||||
0xbc, 0x27, 0xbc, 0xc7, 0x38, 0x03, 0xd9, 0xc3, 0x00, 0xf0, 0x63, 0xc0, 0xf8, 0xfc, 0x3f, 0xcf, 0xfc, 0xff, 0x87, 0xdf,
|
|
||||||
0xfe, 0xff, 0xe0, 0xdf, 0xfc, 0x1f, 0xfe, 0xdf, 0xf8, 0x07, 0xf8, 0xcf, 0xf0, 0x03, 0xe0, 0xc7, 0x00, 0x00, 0x00, 0xc0};
|
|
||||||
|
|
||||||
const unsigned char bell_icon[] PROGMEM = {
|
const unsigned char devil[] PROGMEM = {0x06, 0x60, 0xCA, 0x53, 0x32, 0x4C, 0x22, 0x44, 0x44, 0x22, 0x3A,
|
||||||
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11110000,
|
0x5C, 0x32, 0x4C, 0x52, 0x4A, 0x72, 0x4E, 0x02, 0x40, 0x22, 0x44,
|
||||||
0b00000011, 0b00000000, 0b00000000, 0b11111100, 0b00001111, 0b00000000, 0b00000000, 0b00001111, 0b00111100, 0b00000000,
|
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
0b00000000, 0b00000011, 0b00110000, 0b00000000, 0b10000000, 0b00000001, 0b01100000, 0b00000000, 0b11000000, 0b00000000,
|
|
||||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000,
|
const unsigned char heart[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x7E, 0x7E, 0xFE, 0x7F, 0xFE,
|
||||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000,
|
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F,
|
||||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000,
|
0xF0, 0x0F, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00};
|
||||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b01000000, 0b00000000, 0b10000000, 0b00000000, 0b01100000, 0b00000000,
|
|
||||||
0b10000000, 0b00000001, 0b01110000, 0b00000000, 0b10000000, 0b00000011, 0b00110000, 0b00000000, 0b00000000, 0b00000011,
|
const unsigned char poo[] PROGMEM = {0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x04, 0xF0,
|
||||||
0b00011000, 0b00000000, 0b00000000, 0b00000110, 0b11110000, 0b11111111, 0b11111111, 0b00000011, 0b00000000, 0b00001100,
|
0x08, 0x10, 0x10, 0x48, 0x12, 0x08, 0x18, 0xE8, 0x21, 0x1C, 0x40,
|
||||||
0b00001100, 0b00000000, 0b00000000, 0b00011000, 0b00000110, 0b00000000, 0b00000000, 0b11111000, 0b00000111, 0b00000000,
|
0x42, 0x42, 0x82, 0x41, 0x02, 0x30, 0xFC, 0x0F, 0x00, 0x00};
|
||||||
0b00000000, 0b11100000, 0b00000001, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
|
|
||||||
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000};
|
const unsigned char bell_icon[] PROGMEM = {0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0xE0, 0x07, 0xF0, 0x0F, 0xF0,
|
||||||
|
0x0F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F,
|
||||||
|
0xFC, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x01, 0x00, 0x00};
|
||||||
|
|
||||||
|
const unsigned char cookie[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x34, 0x22, 0x32,
|
||||||
|
0x40, 0x02, 0x58, 0x82, 0x5B, 0x92, 0x43, 0x82, 0x43, 0x02, 0x40,
|
||||||
|
0x64, 0x28, 0x64, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
|
|
||||||
|
const unsigned char Fire[] PROGMEM = {0x30, 0x00, 0xF0, 0x00, 0xF8, 0x03, 0xF8, 0x07, 0xFC, 0x1F, 0xFC,
|
||||||
|
0x1F, 0xFE, 0x3E, 0x7E, 0x3E, 0x3E, 0x7C, 0x1E, 0x78, 0x1E, 0x70,
|
||||||
|
0x1C, 0x70, 0x1C, 0x70, 0x38, 0x38, 0x30, 0x38, 0x60, 0x0C};
|
||||||
|
|
||||||
|
const unsigned char peace_sign[] PROGMEM = {0xC0, 0x30, 0x40, 0x29, 0x40, 0x25, 0x40, 0x15, 0x40, 0x12, 0x38,
|
||||||
|
0x0A, 0x54, 0x68, 0x54, 0x58, 0x54, 0x44, 0x3C, 0x22, 0x04, 0x22,
|
||||||
|
0x04, 0x12, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00};
|
||||||
|
|
||||||
|
const unsigned char Praying[] PROGMEM = {0x00, 0x00, 0x40, 0x02, 0xA0, 0x05, 0x90, 0x09, 0x90, 0x09, 0x90,
|
||||||
|
0x09, 0x98, 0x19, 0x94, 0x29, 0xA4, 0x25, 0xA4, 0x25, 0x84, 0x21,
|
||||||
|
0x84, 0x21, 0x86, 0x61, 0x4E, 0x72, 0x7F, 0x7E, 0x3F, 0xFC};
|
||||||
|
|
||||||
|
const unsigned char Sparkles[] PROGMEM = {0x00, 0x00, 0x10, 0x00, 0x38, 0x04, 0x10, 0x04, 0x00, 0x0E, 0x00,
|
||||||
|
0x1F, 0x80, 0x3F, 0xE0, 0xFF, 0x80, 0x3F, 0x10, 0x1F, 0x10, 0x0E,
|
||||||
|
0x38, 0x04, 0xFE, 0x04, 0x38, 0x00, 0x10, 0x00, 0x10, 0x00};
|
||||||
|
|
||||||
|
const unsigned char clown[] PROGMEM = {0x00, 0x00, 0xEE, 0x77, 0x1A, 0x58, 0x06, 0x60, 0x24, 0x24, 0x72,
|
||||||
|
0x4E, 0x22, 0x44, 0x82, 0x41, 0x82, 0x41, 0x1A, 0x58, 0xF2, 0x4F,
|
||||||
|
0x14, 0x28, 0xE4, 0x27, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||||
|
|
||||||
|
const unsigned char robo[] PROGMEM = {0x80, 0x01, 0xC0, 0x03, 0x80, 0x01, 0xFC, 0x3F, 0x04, 0x20, 0x74,
|
||||||
|
0x2E, 0x52, 0x4A, 0x72, 0x4E, 0x02, 0x40, 0x02, 0x40, 0xA2, 0x4A,
|
||||||
|
0x52, 0x45, 0x04, 0x20, 0x04, 0x20, 0xFC, 0x3F, 0x00, 0x00};
|
||||||
|
|
||||||
|
const unsigned char hole[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x3C, 0x3C,
|
||||||
|
0x06, 0x60, 0x0C, 0x30, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
const unsigned char bowling[] PROGMEM = {0x00, 0x38, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x28, 0x00,
|
||||||
|
0x38, 0x00, 0x28, 0x78, 0x44, 0x84, 0x82, 0x22, 0x83, 0x52, 0x83,
|
||||||
|
0x02, 0x83, 0x02, 0x45, 0x84, 0x44, 0x78, 0x38, 0x00, 0x00};
|
||||||
|
|
||||||
|
const unsigned char vulcan_salute[] PROGMEM = {0x08, 0x02, 0x16, 0x0D, 0x15, 0x15, 0x15, 0x15, 0xA9, 0x12, 0x4A,
|
||||||
|
0x0A, 0x02, 0x38, 0x04, 0x48, 0x04, 0x44, 0x04, 0x22, 0x04, 0x22,
|
||||||
|
0x04, 0x12, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
|||||||
+99
-47
@@ -17,98 +17,150 @@ extern const int numEmotes;
|
|||||||
|
|
||||||
#ifndef EXCLUDE_EMOJI
|
#ifndef EXCLUDE_EMOJI
|
||||||
// === Emote Bitmaps ===
|
// === Emote Bitmaps ===
|
||||||
#define thumbs_height 25
|
#define thumbs_height 16
|
||||||
#define thumbs_width 25
|
#define thumbs_width 16
|
||||||
extern const unsigned char thumbup[] PROGMEM;
|
extern const unsigned char thumbup[] PROGMEM;
|
||||||
extern const unsigned char thumbdown[] PROGMEM;
|
extern const unsigned char thumbdown[] PROGMEM;
|
||||||
|
|
||||||
#define Smiling_Eyes_height 30
|
#define Smiling_Eyes_height 16
|
||||||
#define Smiling_Eyes_width 30
|
#define Smiling_Eyes_width 16
|
||||||
extern const unsigned char Smiling_Eyes[] PROGMEM;
|
extern const unsigned char Smiling_Eyes[] PROGMEM;
|
||||||
|
|
||||||
#define Grinning_height 30
|
#define Grinning_height 16
|
||||||
#define Grinning_width 30
|
#define Grinning_width 16
|
||||||
extern const unsigned char Grinning[] PROGMEM;
|
extern const unsigned char Grinning[] PROGMEM;
|
||||||
|
|
||||||
#define Slightly_Smiling_height 30
|
#define Slightly_Smiling_height 16
|
||||||
#define Slightly_Smiling_width 30
|
#define Slightly_Smiling_width 16
|
||||||
extern const unsigned char Slightly_Smiling[] PROGMEM;
|
extern const unsigned char Slightly_Smiling[] PROGMEM;
|
||||||
|
|
||||||
#define Winking_Face_height 30
|
#define Winking_Face_height 16
|
||||||
#define Winking_Face_width 30
|
#define Winking_Face_width 16
|
||||||
extern const unsigned char Winking_Face[] PROGMEM;
|
extern const unsigned char Winking_Face[] PROGMEM;
|
||||||
|
|
||||||
#define Grinning_Smiling_Eyes_height 30
|
#define Grinning_Smiling_Eyes_height 16
|
||||||
#define Grinning_Smiling_Eyes_width 30
|
#define Grinning_Smiling_Eyes_width 16
|
||||||
extern const unsigned char Grinning_Smiling_Eyes[] PROGMEM;
|
extern const unsigned char Grinning_Smiling_Eyes[] PROGMEM;
|
||||||
|
|
||||||
#define question_height 25
|
#define heart_smile_height 16
|
||||||
#define question_width 25
|
#define heart_smile_width 16
|
||||||
|
extern const unsigned char heart_smile[] PROGMEM;
|
||||||
|
|
||||||
|
#define Heart_eyes_height 16
|
||||||
|
#define Heart_eyes_width 16
|
||||||
|
extern const unsigned char Heart_eyes[] PROGMEM;
|
||||||
|
|
||||||
|
#define question_height 16
|
||||||
|
#define question_width 16
|
||||||
extern const unsigned char question[] PROGMEM;
|
extern const unsigned char question[] PROGMEM;
|
||||||
|
|
||||||
#define bang_height 30
|
#define bang_height 16
|
||||||
#define bang_width 30
|
#define bang_width 16
|
||||||
extern const unsigned char bang[] PROGMEM;
|
extern const unsigned char bang[] PROGMEM;
|
||||||
|
|
||||||
#define haha_height 30
|
#define haha_height 16
|
||||||
#define haha_width 30
|
#define haha_width 16
|
||||||
extern const unsigned char haha[] PROGMEM;
|
extern const unsigned char haha[] PROGMEM;
|
||||||
|
|
||||||
#define ROFL_height 30
|
#define ROFL_height 16
|
||||||
#define ROFL_width 30
|
#define ROFL_width 16
|
||||||
extern const unsigned char ROFL[] PROGMEM;
|
extern const unsigned char ROFL[] PROGMEM;
|
||||||
|
|
||||||
#define Smiling_Closed_Eyes_height 30
|
#define Smiling_Closed_Eyes_height 16
|
||||||
#define Smiling_Closed_Eyes_width 30
|
#define Smiling_Closed_Eyes_width 16
|
||||||
extern const unsigned char Smiling_Closed_Eyes[] PROGMEM;
|
extern const unsigned char Smiling_Closed_Eyes[] PROGMEM;
|
||||||
|
|
||||||
#define Grinning_SmilingEyes2_height 30
|
#define Grinning_SmilingEyes2_height 16
|
||||||
#define Grinning_SmilingEyes2_width 30
|
#define Grinning_SmilingEyes2_width 16
|
||||||
extern const unsigned char Grinning_SmilingEyes2[] PROGMEM;
|
extern const unsigned char Grinning_SmilingEyes2[] PROGMEM;
|
||||||
|
|
||||||
#define wave_icon_height 30
|
#define Loudly_Crying_Face_height 16
|
||||||
#define wave_icon_width 30
|
#define Loudly_Crying_Face_width 16
|
||||||
|
extern const unsigned char Loudly_Crying_Face[] PROGMEM;
|
||||||
|
|
||||||
|
#define wave_icon_height 16
|
||||||
|
#define wave_icon_width 16
|
||||||
extern const unsigned char wave_icon[] PROGMEM;
|
extern const unsigned char wave_icon[] PROGMEM;
|
||||||
|
|
||||||
#define cowboy_height 30
|
#define cowboy_height 16
|
||||||
#define cowboy_width 30
|
#define cowboy_width 16
|
||||||
extern const unsigned char cowboy[] PROGMEM;
|
extern const unsigned char cowboy[] PROGMEM;
|
||||||
|
|
||||||
#define deadmau5_height 30
|
#define deadmau5_height 16
|
||||||
#define deadmau5_width 60
|
#define deadmau5_width 16
|
||||||
extern const unsigned char deadmau5[] PROGMEM;
|
extern const unsigned char deadmau5[] PROGMEM;
|
||||||
|
|
||||||
#define sun_height 30
|
#define sun_height 16
|
||||||
#define sun_width 30
|
#define sun_width 16
|
||||||
extern const unsigned char sun[] PROGMEM;
|
extern const unsigned char sun[] PROGMEM;
|
||||||
|
|
||||||
#define rain_height 30
|
#define rain_height 16
|
||||||
#define rain_width 30
|
#define rain_width 16
|
||||||
extern const unsigned char rain[] PROGMEM;
|
extern const unsigned char rain[] PROGMEM;
|
||||||
|
|
||||||
#define cloud_height 30
|
#define cloud_height 16
|
||||||
#define cloud_width 30
|
#define cloud_width 16
|
||||||
extern const unsigned char cloud[] PROGMEM;
|
extern const unsigned char cloud[] PROGMEM;
|
||||||
|
|
||||||
#define fog_height 25
|
#define fog_height 16
|
||||||
#define fog_width 25
|
#define fog_width 16
|
||||||
extern const unsigned char fog[] PROGMEM;
|
extern const unsigned char fog[] PROGMEM;
|
||||||
|
|
||||||
#define devil_height 30
|
#define devil_height 16
|
||||||
#define devil_width 30
|
#define devil_width 16
|
||||||
extern const unsigned char devil[] PROGMEM;
|
extern const unsigned char devil[] PROGMEM;
|
||||||
|
|
||||||
#define heart_height 30
|
#define heart_height 16
|
||||||
#define heart_width 30
|
#define heart_width 16
|
||||||
extern const unsigned char heart[] PROGMEM;
|
extern const unsigned char heart[] PROGMEM;
|
||||||
|
|
||||||
#define poo_height 30
|
#define poo_height 16
|
||||||
#define poo_width 30
|
#define poo_width 16
|
||||||
extern const unsigned char poo[] PROGMEM;
|
extern const unsigned char poo[] PROGMEM;
|
||||||
|
|
||||||
#define bell_icon_width 30
|
#define bell_icon_width 16
|
||||||
#define bell_icon_height 30
|
#define bell_icon_height 16
|
||||||
extern const unsigned char bell_icon[] PROGMEM;
|
extern const unsigned char bell_icon[] PROGMEM;
|
||||||
|
|
||||||
|
#define cookie_width 16
|
||||||
|
#define cookie_height 16
|
||||||
|
extern const unsigned char cookie[] PROGMEM;
|
||||||
|
|
||||||
|
#define Fire_width 16
|
||||||
|
#define Fire_height 16
|
||||||
|
extern const unsigned char Fire[] PROGMEM;
|
||||||
|
|
||||||
|
#define peace_sign_width 16
|
||||||
|
#define peace_sign_height 16
|
||||||
|
extern const unsigned char peace_sign[] PROGMEM;
|
||||||
|
|
||||||
|
#define Praying_width 16
|
||||||
|
#define Praying_height 16
|
||||||
|
extern const unsigned char Praying[] PROGMEM;
|
||||||
|
|
||||||
|
#define Sparkles_width 16
|
||||||
|
#define Sparkles_height 16
|
||||||
|
extern const unsigned char Sparkles[] PROGMEM;
|
||||||
|
|
||||||
|
#define clown_width 16
|
||||||
|
#define clown_height 16
|
||||||
|
extern const unsigned char clown[] PROGMEM;
|
||||||
|
|
||||||
|
#define robo_width 16
|
||||||
|
#define robo_height 16
|
||||||
|
extern const unsigned char robo[] PROGMEM;
|
||||||
|
|
||||||
|
#define hole_width 16
|
||||||
|
#define hole_height 16
|
||||||
|
extern const unsigned char hole[] PROGMEM;
|
||||||
|
|
||||||
|
#define bowling_width 16
|
||||||
|
#define bowling_height 16
|
||||||
|
extern const unsigned char bowling[] PROGMEM;
|
||||||
|
|
||||||
|
#define vulcan_salute_width 16
|
||||||
|
#define vulcan_salute_height 16
|
||||||
|
extern const unsigned char vulcan_salute[] PROGMEM;
|
||||||
#endif // EXCLUDE_EMOJI
|
#endif // EXCLUDE_EMOJI
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
@@ -287,7 +287,7 @@ void InkHUD::MapApplet::getMapCenter(float *lat, float *lng)
|
|||||||
float easternmost = lngCenter;
|
float easternmost = lngCenter;
|
||||||
float westernmost = lngCenter;
|
float westernmost = lngCenter;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||||
|
|
||||||
// Skip if no position
|
// Skip if no position
|
||||||
@@ -474,8 +474,8 @@ void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node)
|
|||||||
// Need at least two, to draw a sensible map
|
// Need at least two, to draw a sensible map
|
||||||
bool InkHUD::MapApplet::enoughMarkers()
|
bool InkHUD::MapApplet::enoughMarkers()
|
||||||
{
|
{
|
||||||
uint8_t count = 0;
|
size_t count = 0;
|
||||||
for (uint8_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||||
|
|
||||||
// Count nodes
|
// Count nodes
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ A pattern / collection of resources for creating custom UIs, to target small gro
|
|||||||
For an example, see the `heltec-vision-master-e290-inkhud` platformio env.
|
For an example, see the `heltec-vision-master-e290-inkhud` platformio env.
|
||||||
|
|
||||||
- platformio.ini
|
- platformio.ini
|
||||||
|
|
||||||
- suppress default Meshtastic components (Screen, ButtonThread, etc)
|
- suppress default Meshtastic components (Screen, ButtonThread, etc)
|
||||||
- define `MESHTASTIC_INCLUDE_NICHE_GRAPHICS`
|
- define `MESHTASTIC_INCLUDE_NICHE_GRAPHICS`
|
||||||
- (possibly) Edit `build_src_filter` to include our new nicheGraphics.h file
|
- (possibly) Edit `build_src_filter` to include our new nicheGraphics.h file
|
||||||
|
|||||||
+1
-1
@@ -1401,7 +1401,7 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// check if the radio chip matches the selected region
|
// check if the radio chip matches the selected region
|
||||||
if ((config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())) {
|
if ((config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) && rIf && (!rIf->wideLora())) {
|
||||||
LOG_WARN("LoRa chip does not support 2.4GHz. Revert to unset");
|
LOG_WARN("LoRa chip does not support 2.4GHz. Revert to unset");
|
||||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
|
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
|
||||||
nodeDB->saveToDisk(SEGMENT_CONFIG);
|
nodeDB->saveToDisk(SEGMENT_CONFIG);
|
||||||
|
|||||||
+5
-1
@@ -29,6 +29,7 @@
|
|||||||
#else
|
#else
|
||||||
#define default_ringtone_nag_secs 15
|
#define default_ringtone_nag_secs 15
|
||||||
#endif
|
#endif
|
||||||
|
#define default_network_ipv6_enabled false
|
||||||
|
|
||||||
#define default_mqtt_address "mqtt.meshtastic.org"
|
#define default_mqtt_address "mqtt.meshtastic.org"
|
||||||
#define default_mqtt_username "meshdev"
|
#define default_mqtt_username "meshdev"
|
||||||
@@ -46,12 +47,15 @@ class Default
|
|||||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
|
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
|
||||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
|
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
|
||||||
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
|
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
|
||||||
|
// Note: numOnlineNodes uses uint32_t to match the public API and allow flexibility,
|
||||||
|
// even though internal node counts use uint16_t (max 65535 nodes)
|
||||||
static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes);
|
static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes);
|
||||||
static uint8_t getConfiguredOrDefaultHopLimit(uint8_t configured);
|
static uint8_t getConfiguredOrDefaultHopLimit(uint8_t configured);
|
||||||
static uint32_t getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue);
|
static uint32_t getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static float congestionScalingCoefficient(int numOnlineNodes)
|
// Note: Kept as uint32_t to match the public API parameter type
|
||||||
|
static float congestionScalingCoefficient(uint32_t numOnlineNodes)
|
||||||
{
|
{
|
||||||
// Increase frequency of broadcasts for small networks regardless of preset
|
// Increase frequency of broadcasts for small networks regardless of preset
|
||||||
if (numOnlineNodes <= 10) {
|
if (numOnlineNodes <= 10) {
|
||||||
|
|||||||
@@ -718,6 +718,12 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||||||
strncpy(config.network.wifi_psk, USERPREFS_NETWORK_WIFI_PSK, sizeof(config.network.wifi_psk));
|
strncpy(config.network.wifi_psk, USERPREFS_NETWORK_WIFI_PSK, sizeof(config.network.wifi_psk));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(USERPREFS_NETWORK_IPV6_ENABLED)
|
||||||
|
config.network.ipv6_enabled = USERPREFS_NETWORK_IPV6_ENABLED;
|
||||||
|
#else
|
||||||
|
config.network.ipv6_enabled = default_network_ipv6_enabled;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DISPLAY_FLIP_SCREEN
|
#ifdef DISPLAY_FLIP_SCREEN
|
||||||
config.display.flip_screen = true;
|
config.display.flip_screen = true;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
|||||||
const pb_msgdesc_t *fields;
|
const pb_msgdesc_t *fields;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint8_t numOnlineNodes = 0;
|
uint16_t numOnlineNodes = 0;
|
||||||
/** Constructor
|
/** Constructor
|
||||||
* name is for debugging output
|
* name is for debugging output
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -334,6 +334,23 @@ bool initWifi()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
|
#if ESP_ARDUINO_VERSION <= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||||
|
// Most of the next 12 lines of code are adapted from espressif/arduino-esp32
|
||||||
|
// Licensed under the GNU Lesser General Public License v2.1
|
||||||
|
// https://github.com/espressif/arduino-esp32/blob/1f038677eb2eaf5e9ca6b6074486803c15468bed/libraries/WiFi/src/WiFiSTA.cpp#L755
|
||||||
|
esp_netif_t *get_esp_interface_netif(esp_interface_t interface);
|
||||||
|
IPv6Address GlobalIPv6()
|
||||||
|
{
|
||||||
|
esp_ip6_addr_t addr;
|
||||||
|
if (WiFiGenericClass::getMode() == WIFI_MODE_NULL) {
|
||||||
|
return IPv6Address();
|
||||||
|
}
|
||||||
|
if (esp_netif_get_ip6_global(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)) {
|
||||||
|
return IPv6Address();
|
||||||
|
}
|
||||||
|
return IPv6Address(addr.addr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Called by the Espressif SDK to
|
// Called by the Espressif SDK to
|
||||||
static void WiFiEvent(WiFiEvent_t event)
|
static void WiFiEvent(WiFiEvent_t event)
|
||||||
{
|
{
|
||||||
@@ -355,6 +372,17 @@ static void WiFiEvent(WiFiEvent_t event)
|
|||||||
break;
|
break;
|
||||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||||
LOG_INFO("Connected to access point");
|
LOG_INFO("Connected to access point");
|
||||||
|
if (config.network.ipv6_enabled) {
|
||||||
|
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||||
|
if (!WiFi.enableIPv6()) {
|
||||||
|
LOG_WARN("Failed to enable IPv6");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!WiFi.enableIpV6()) {
|
||||||
|
LOG_WARN("Failed to enable IPv6");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#ifdef WIFI_LED
|
#ifdef WIFI_LED
|
||||||
digitalWrite(WIFI_LED, HIGH);
|
digitalWrite(WIFI_LED, HIGH);
|
||||||
#endif
|
#endif
|
||||||
@@ -383,7 +411,8 @@ static void WiFiEvent(WiFiEvent_t event)
|
|||||||
LOG_INFO("Obtained Local IP6 address: %s", WiFi.linkLocalIPv6().toString().c_str());
|
LOG_INFO("Obtained Local IP6 address: %s", WiFi.linkLocalIPv6().toString().c_str());
|
||||||
LOG_INFO("Obtained GlobalIP6 address: %s", WiFi.globalIPv6().toString().c_str());
|
LOG_INFO("Obtained GlobalIP6 address: %s", WiFi.globalIPv6().toString().c_str());
|
||||||
#else
|
#else
|
||||||
LOG_INFO("Obtained IP6 address: %s", WiFi.localIPv6().toString().c_str());
|
LOG_INFO("Obtained Local IP6 address: %s", WiFi.localIPv6().toString().c_str());
|
||||||
|
LOG_INFO("Obtained GlobalIP6 address: %s", GlobalIPv6().toString().c_str());
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
|
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
|
||||||
@@ -514,4 +543,4 @@ uint8_t getWifiDisconnectReason()
|
|||||||
{
|
{
|
||||||
return wifiDisconnectReason;
|
return wifiDisconnectReason;
|
||||||
}
|
}
|
||||||
#endif // HAS_WIFI
|
#endif // HAS_WIFI
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ void NeighborInfoModule::printNodeDBNeighbors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
|
/* Send our initial owner announcement 35 seconds after we start (to give
|
||||||
|
* network time to setup) */
|
||||||
NeighborInfoModule::NeighborInfoModule()
|
NeighborInfoModule::NeighborInfoModule()
|
||||||
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
||||||
concurrency::OSThread("NeighborInfo")
|
concurrency::OSThread("NeighborInfo")
|
||||||
@@ -53,8 +54,8 @@ NeighborInfoModule::NeighborInfoModule()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
Collect neighbor info from the nodeDB's history, capping at a maximum number of
|
||||||
Assumes that the neighborInfo packet has been allocated
|
entries and max time Assumes that the neighborInfo packet has been allocated
|
||||||
@returns the number of entries collected
|
@returns the number of entries collected
|
||||||
*/
|
*/
|
||||||
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
||||||
@@ -71,8 +72,8 @@ uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighb
|
|||||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (nbr.node_id != my_node_id)) {
|
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (nbr.node_id != my_node_id)) {
|
||||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = nbr.node_id;
|
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = nbr.node_id;
|
||||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = nbr.snr;
|
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = nbr.snr;
|
||||||
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
|
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs
|
||||||
// the mesh
|
// here, because we don't want to send this over the mesh
|
||||||
neighborInfo->neighbors_count++;
|
neighborInfo->neighbors_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,8 +89,9 @@ void NeighborInfoModule::cleanUpNeighbors()
|
|||||||
uint32_t now = getTime();
|
uint32_t now = getTime();
|
||||||
NodeNum my_node_id = nodeDB->getNodeNum();
|
NodeNum my_node_id = nodeDB->getNodeNum();
|
||||||
for (auto it = neighbors.rbegin(); it != neighbors.rend();) {
|
for (auto it = neighbors.rbegin(); it != neighbors.rend();) {
|
||||||
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
// We will remove a neighbor if we haven't heard from them in twice the
|
||||||
// cannot use isWithinTimespanMs() as it->last_rx_time is seconds since 1970
|
// broadcast interval cannot use isWithinTimespanMs() as it->last_rx_time is
|
||||||
|
// seconds since 1970
|
||||||
if ((now - it->last_rx_time > it->node_broadcast_interval_secs * 2) && (it->node_id != my_node_id)) {
|
if ((now - it->last_rx_time > it->node_broadcast_interval_secs * 2) && (it->node_id != my_node_id)) {
|
||||||
LOG_DEBUG("Remove neighbor with node ID 0x%x", it->node_id);
|
LOG_DEBUG("Remove neighbor with node ID 0x%x", it->node_id);
|
||||||
it = std::vector<meshtastic_Neighbor>::reverse_iterator(
|
it = std::vector<meshtastic_Neighbor>::reverse_iterator(
|
||||||
@@ -132,25 +134,55 @@ int32_t NeighborInfoModule::runOnce()
|
|||||||
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_neighbor_info_broadcast_secs);
|
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_neighbor_info_broadcast_secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *NeighborInfoModule::allocReply()
|
||||||
|
{
|
||||||
|
LOG_INFO("NeighborInfoRequested.");
|
||||||
|
if (lastSentReply && Throttle::isWithinTimespanMs(lastSentReply, 3 * 60 * 1000)) {
|
||||||
|
LOG_DEBUG("Skip Neighbors reply since we sent a reply <3min ago");
|
||||||
|
ignoreRequest = true; // Mark it as ignored for MeshModule
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
meshtastic_NeighborInfo neighborInfo = meshtastic_NeighborInfo_init_zero;
|
||||||
|
collectNeighborInfo(&neighborInfo);
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *reply = allocDataProtobuf(neighborInfo);
|
||||||
|
|
||||||
|
if (reply) {
|
||||||
|
lastSentReply = millis(); // Track when we sent this reply
|
||||||
|
}
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect a received neighbor info packet from another node
|
Collect a received neighbor info packet from another node
|
||||||
Pass it to an upper client; do not persist this data on the mesh
|
Pass it to an upper client; do not persist this data on the mesh
|
||||||
*/
|
*/
|
||||||
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
|
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
|
||||||
{
|
{
|
||||||
|
LOG_DEBUG("NeighborInfo: handleReceivedProtobuf");
|
||||||
if (np) {
|
if (np) {
|
||||||
printNeighborInfo("RECEIVED", np);
|
printNeighborInfo("RECEIVED", np);
|
||||||
updateNeighbors(mp, np);
|
// Ignore dummy/interceptable packets: single neighbor with nodeId 0 and snr 0
|
||||||
|
if (np->neighbors_count != 1 || np->neighbors[0].node_id != 0 || np->neighbors[0].snr != 0.0f) {
|
||||||
|
LOG_DEBUG(" Updating neighbours");
|
||||||
|
updateNeighbors(mp, np);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(" Ignoring dummy neighbor info packet (single neighbor with nodeId 0, snr 0)");
|
||||||
|
}
|
||||||
} else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
|
} else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
|
||||||
|
LOG_DEBUG("Get or create neighbor: %u with snr %f", mp.from, mp.rx_snr);
|
||||||
// If the hopLimit is the same as hopStart, then it is a neighbor
|
// If the hopLimit is the same as hopStart, then it is a neighbor
|
||||||
getOrCreateNeighbor(mp.from, mp.from, 0, mp.rx_snr); // Set the broadcast interval to 0, as we don't know it
|
getOrCreateNeighbor(mp.from, mp.from, 0,
|
||||||
|
mp.rx_snr); // Set the broadcast interval to 0, as we don't know it
|
||||||
}
|
}
|
||||||
// Allow others to handle this packet
|
// Allow others to handle this packet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copy the content of a current NeighborInfo packet into a new one and update the last_sent_by_id to our NodeNum
|
Copy the content of a current NeighborInfo packet into a new one and update the
|
||||||
|
last_sent_by_id to our NodeNum
|
||||||
*/
|
*/
|
||||||
void NeighborInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_NeighborInfo *n)
|
void NeighborInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_NeighborInfo *n)
|
||||||
{
|
{
|
||||||
@@ -168,8 +200,10 @@ void NeighborInfoModule::resetNeighbors()
|
|||||||
|
|
||||||
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
||||||
{
|
{
|
||||||
// The last sent ID will be 0 if the packet is from the phone, which we don't count as
|
LOG_DEBUG("updateNeighbors");
|
||||||
// an edge. So we assume that if it's zero, then this packet is from our node.
|
// The last sent ID will be 0 if the packet is from the phone, which we don't
|
||||||
|
// count as an edge. So we assume that if it's zero, then this packet is from
|
||||||
|
// our node.
|
||||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
||||||
getOrCreateNeighbor(mp.from, np->last_sent_by_id, np->node_broadcast_interval_secs, mp.rx_snr);
|
getOrCreateNeighbor(mp.from, np->last_sent_by_id, np->node_broadcast_interval_secs, mp.rx_snr);
|
||||||
}
|
}
|
||||||
@@ -188,7 +222,8 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
|
|||||||
// if found, update it
|
// if found, update it
|
||||||
neighbors[i].snr = snr;
|
neighbors[i].snr = snr;
|
||||||
neighbors[i].last_rx_time = getTime();
|
neighbors[i].last_rx_time = getTime();
|
||||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
// Only if this is the original sender, the broadcast interval corresponds
|
||||||
|
// to it
|
||||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||||
neighbors[i].node_broadcast_interval_secs = node_broadcast_interval_secs;
|
neighbors[i].node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||||
return &neighbors[i];
|
return &neighbors[i];
|
||||||
@@ -200,10 +235,12 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
|
|||||||
new_nbr.node_id = n;
|
new_nbr.node_id = n;
|
||||||
new_nbr.snr = snr;
|
new_nbr.snr = snr;
|
||||||
new_nbr.last_rx_time = getTime();
|
new_nbr.last_rx_time = getTime();
|
||||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
// Only if this is the original sender, the broadcast interval corresponds to
|
||||||
|
// it
|
||||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||||
new_nbr.node_broadcast_interval_secs = node_broadcast_interval_secs;
|
new_nbr.node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||||
else // Assume the same broadcast interval as us for the neighbor if we don't know it
|
else // Assume the same broadcast interval as us for the neighbor if we don't
|
||||||
|
// know it
|
||||||
new_nbr.node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
new_nbr.node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||||
|
|
||||||
if (neighbors.size() < MAX_NUM_NEIGHBORS) {
|
if (neighbors.size() < MAX_NUM_NEIGHBORS) {
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
|||||||
*/
|
*/
|
||||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override;
|
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *nb) override;
|
||||||
|
|
||||||
|
/* Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||||
|
virtual meshtastic_MeshPacket *allocReply() override;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
* Collect neighbor info from the nodeDB's history, capping at a maximum number of entries and max time
|
||||||
* @return the number of entries collected
|
* @return the number of entries collected
|
||||||
@@ -66,5 +70,8 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
|||||||
/* These are for debugging only */
|
/* These are for debugging only */
|
||||||
void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
|
void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
|
||||||
void printNodeDBNeighbors();
|
void printNodeDBNeighbors();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t lastSentReply = 0; // Last time we sent a position reply (used for reply throttling only)
|
||||||
};
|
};
|
||||||
extern NeighborInfoModule *neighborInfoModule;
|
extern NeighborInfoModule *neighborInfoModule;
|
||||||
@@ -134,6 +134,10 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
|||||||
#include "Sensor/TSL2561Sensor.h"
|
#include "Sensor/TSL2561Sensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<BH1750_WE.h>)
|
||||||
|
#include "Sensor/BH1750Sensor.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||||
|
|
||||||
@@ -262,6 +266,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
#if __has_include(<SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h>)
|
#if __has_include(<SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h>)
|
||||||
addSensor<NAU7802Sensor>(i2cScanner, ScanI2C::DeviceType::NAU7802);
|
addSensor<NAU7802Sensor>(i2cScanner, ScanI2C::DeviceType::NAU7802);
|
||||||
#endif
|
#endif
|
||||||
|
#if __has_include(<BH1750_WE.h>)
|
||||||
|
addSensor<BH1750Sensor>(i2cScanner, ScanI2C::DeviceType::BH1750);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<BH1750_WE.h>)
|
||||||
|
|
||||||
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "BH1750Sensor.h"
|
||||||
|
#include "TelemetrySensor.h"
|
||||||
|
#include <BH1750_WE.h>
|
||||||
|
|
||||||
|
#ifndef BH1750_SENSOR_MODE
|
||||||
|
#define BH1750_SENSOR_MODE BH1750Mode::CHM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BH1750Sensor::BH1750Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BH1750, "BH1750") {}
|
||||||
|
|
||||||
|
bool BH1750Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
|
{
|
||||||
|
LOG_INFO("Init sensor: %s with mode %d", sensorName, BH1750_SENSOR_MODE);
|
||||||
|
|
||||||
|
bh1750 = BH1750_WE(bus, dev->address.address);
|
||||||
|
status = bh1750.init();
|
||||||
|
if (!status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bh1750.setMode(BH1750_SENSOR_MODE);
|
||||||
|
|
||||||
|
initI2CSensor();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BH1750Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* An OTH and OTH_2 measurement takes ~120 ms. I suggest to wait
|
||||||
|
140 ms to be on the safe side.
|
||||||
|
An OTL measurement takes about 16 ms. I suggest to wait 20 ms
|
||||||
|
to be on the safe side. */
|
||||||
|
if (BH1750_SENSOR_MODE == BH1750Mode::OTH || BH1750_SENSOR_MODE == BH1750Mode::OTH_2) {
|
||||||
|
bh1750.setMode(BH1750_SENSOR_MODE);
|
||||||
|
delay(140); // wait for measurement to be completed
|
||||||
|
} else if (BH1750_SENSOR_MODE == BH1750Mode::OTL) {
|
||||||
|
bh1750.setMode(BH1750_SENSOR_MODE);
|
||||||
|
delay(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
measurement->variant.environment_metrics.has_lux = true;
|
||||||
|
float lightIntensity = bh1750.getLux();
|
||||||
|
|
||||||
|
measurement->variant.environment_metrics.lux = lightIntensity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<BH1750_WE.h>)
|
||||||
|
|
||||||
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "TelemetrySensor.h"
|
||||||
|
#include <BH1750_WE.h>
|
||||||
|
|
||||||
|
class BH1750Sensor : public TelemetrySensor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
BH1750_WE bh1750;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BH1750Sensor();
|
||||||
|
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||||
|
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+1
-1
@@ -692,7 +692,7 @@ void MQTT::publishNodeInfo()
|
|||||||
}
|
}
|
||||||
void MQTT::publishQueuedMessages()
|
void MQTT::publishQueuedMessages()
|
||||||
{
|
{
|
||||||
if (mqttQueue.isEmpty() || !isConnected)
|
if (mqttQueue.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!moduleConfig.mqtt.proxy_to_client_enabled && !isConnected)
|
if (!moduleConfig.mqtt.proxy_to_client_enabled && !isConnected)
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
|
#include "power.h"
|
||||||
|
|
||||||
|
#include <hal/nrf_lpcomp.h>
|
||||||
|
|
||||||
#ifdef BQ25703A_ADDR
|
#ifdef BQ25703A_ADDR
|
||||||
#include "BQ25713.h"
|
#include "BQ25713.h"
|
||||||
@@ -389,6 +392,23 @@ void cpuDeepSleep(uint32_t msecToWake)
|
|||||||
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BATTERY_LPCOMP_INPUT
|
||||||
|
// Wake up if power rises again
|
||||||
|
nrf_lpcomp_config_t c;
|
||||||
|
c.reference = BATTERY_LPCOMP_THRESHOLD;
|
||||||
|
c.detection = NRF_LPCOMP_DETECT_UP;
|
||||||
|
c.hyst = NRF_LPCOMP_HYST_NOHYST;
|
||||||
|
nrf_lpcomp_configure(NRF_LPCOMP, &c);
|
||||||
|
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT);
|
||||||
|
nrf_lpcomp_enable(NRF_LPCOMP);
|
||||||
|
|
||||||
|
battery_adcEnable();
|
||||||
|
|
||||||
|
nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
|
||||||
|
while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY))
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
auto ok = sd_power_system_off();
|
auto ok = sd_power_system_off();
|
||||||
if (ok != NRF_SUCCESS) {
|
if (ok != NRF_SUCCESS) {
|
||||||
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
||||||
@@ -420,4 +440,4 @@ void enterDfuMode()
|
|||||||
#else
|
#else
|
||||||
enterUf2Dfu();
|
enterUf2Dfu();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ bool yamlOnly = false;
|
|||||||
|
|
||||||
const char *argp_program_version = optstr(APP_VERSION);
|
const char *argp_program_version = optstr(APP_VERSION);
|
||||||
|
|
||||||
|
char stdoutBuffer[512];
|
||||||
|
|
||||||
// FIXME - move setBluetoothEnable into a HALPlatform class
|
// FIXME - move setBluetoothEnable into a HALPlatform class
|
||||||
void setBluetoothEnable(bool enable)
|
void setBluetoothEnable(bool enable)
|
||||||
{
|
{
|
||||||
@@ -144,6 +146,20 @@ void getMacAddr(uint8_t *dmac)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string cleanupNameForAutoconf(std::string name)
|
||||||
|
{
|
||||||
|
// Convert spaces -> dashes, lowercase
|
||||||
|
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) {
|
||||||
|
if (c == ' ') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return (char)std::tolower(c);
|
||||||
|
});
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/** apps run under portduino can optionally define a portduinoSetup() to
|
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||||
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
||||||
* before running 'arduino' code.
|
* before running 'arduino' code.
|
||||||
@@ -154,6 +170,9 @@ void portduinoSetup()
|
|||||||
std::string gpioChipName = "gpiochip";
|
std::string gpioChipName = "gpiochip";
|
||||||
portduino_config.displayPanel = no_screen;
|
portduino_config.displayPanel = no_screen;
|
||||||
|
|
||||||
|
// Force stdout to be line buffered
|
||||||
|
setvbuf(stdout, stdoutBuffer, _IOLBF, sizeof(stdoutBuffer));
|
||||||
|
|
||||||
if (portduino_config.force_simradio == true) {
|
if (portduino_config.force_simradio == true) {
|
||||||
portduino_config.lora_module = use_simradio;
|
portduino_config.lora_module = use_simradio;
|
||||||
} else if (configPath != nullptr) {
|
} else if (configPath != nullptr) {
|
||||||
@@ -213,6 +232,11 @@ void portduinoSetup()
|
|||||||
// If LoRa `Module: auto` (default in config.yaml),
|
// If LoRa `Module: auto` (default in config.yaml),
|
||||||
// attempt to auto config based on Product Strings
|
// attempt to auto config based on Product Strings
|
||||||
if (portduino_config.lora_module == use_autoconf) {
|
if (portduino_config.lora_module == use_autoconf) {
|
||||||
|
bool found_hat = false;
|
||||||
|
bool found_rak_eeprom = false;
|
||||||
|
bool found_ch341 = false;
|
||||||
|
|
||||||
|
char hat_vendor[96] = {0};
|
||||||
char autoconf_product[96] = {0};
|
char autoconf_product[96] = {0};
|
||||||
// Try CH341
|
// Try CH341
|
||||||
try {
|
try {
|
||||||
@@ -222,21 +246,32 @@ void portduinoSetup()
|
|||||||
ch341Hal->getProductString(autoconf_product, 95);
|
ch341Hal->getProductString(autoconf_product, 95);
|
||||||
delete ch341Hal;
|
delete ch341Hal;
|
||||||
std::cout << "autoconf: Found CH341 device " << autoconf_product << std::endl;
|
std::cout << "autoconf: Found CH341 device " << autoconf_product << std::endl;
|
||||||
|
|
||||||
|
found_ch341 = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cout << "autoconf: Could not locate CH341 device" << std::endl;
|
std::cout << "autoconf: Could not locate CH341 device" << std::endl;
|
||||||
}
|
}
|
||||||
// Try Pi HAT+
|
// Try Pi HAT+
|
||||||
if (strlen(autoconf_product) < 6) {
|
if (strlen(autoconf_product) < 6) {
|
||||||
std::cout << "autoconf: Looking for Pi HAT+..." << std::endl;
|
std::cout << "autoconf: Looking for Pi HAT+..." << std::endl;
|
||||||
|
if (access("/proc/device-tree/hat/vendor", R_OK) == 0) {
|
||||||
|
std::ifstream hatVendorFile("/proc/device-tree/hat/vendor");
|
||||||
|
if (hatVendorFile.is_open()) {
|
||||||
|
hatVendorFile.read(hat_vendor, 95);
|
||||||
|
hatVendorFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (access("/proc/device-tree/hat/product", R_OK) == 0) {
|
if (access("/proc/device-tree/hat/product", R_OK) == 0) {
|
||||||
std::ifstream hatProductFile("/proc/device-tree/hat/product");
|
std::ifstream hatProductFile("/proc/device-tree/hat/product");
|
||||||
if (hatProductFile.is_open()) {
|
if (hatProductFile.is_open()) {
|
||||||
hatProductFile.read(autoconf_product, 95);
|
hatProductFile.read(autoconf_product, 95);
|
||||||
hatProductFile.close();
|
hatProductFile.close();
|
||||||
}
|
}
|
||||||
std::cout << "autoconf: Found Pi HAT+ " << autoconf_product << " at /proc/device-tree/hat/product" << std::endl;
|
std::cout << "autoconf: Found Pi HAT+ " << hat_vendor << " " << autoconf_product << " at /proc/device-tree/hat"
|
||||||
|
<< std::endl;
|
||||||
|
found_hat = true;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat/product" << std::endl;
|
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// attempt to load autoconf data from an EEPROM on 0x50
|
// attempt to load autoconf data from an EEPROM on 0x50
|
||||||
@@ -292,6 +327,7 @@ void portduinoSetup()
|
|||||||
autoconf_product[0] = 0x0;
|
autoconf_product[0] = 0x0;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "autoconf: Found eeprom data " << autoconf_raw << std::endl;
|
std::cout << "autoconf: Found eeprom data " << autoconf_raw << std::endl;
|
||||||
|
found_rak_eeprom = true;
|
||||||
if (mac_start != nullptr) {
|
if (mac_start != nullptr) {
|
||||||
std::cout << "autoconf: Found mac data " << mac_start << std::endl;
|
std::cout << "autoconf: Found mac data " << mac_start << std::endl;
|
||||||
if (strlen(mac_start) == 12)
|
if (strlen(mac_start) == 12)
|
||||||
@@ -320,12 +356,29 @@ void portduinoSetup()
|
|||||||
if (strlen(autoconf_product) > 0) {
|
if (strlen(autoconf_product) > 0) {
|
||||||
// From configProducts map in PortduinoGlue.h
|
// From configProducts map in PortduinoGlue.h
|
||||||
std::string product_config = "";
|
std::string product_config = "";
|
||||||
try {
|
|
||||||
|
if (configProducts.find(autoconf_product) != configProducts.end()) {
|
||||||
product_config = configProducts.at(autoconf_product);
|
product_config = configProducts.at(autoconf_product);
|
||||||
} catch (std::out_of_range &e) {
|
} else {
|
||||||
std::cerr << "autoconf: Unable to find config for " << autoconf_product << std::endl;
|
if (found_hat) {
|
||||||
exit(EXIT_FAILURE);
|
product_config =
|
||||||
|
cleanupNameForAutoconf("lora-hat-" + std::string(hat_vendor) + "-" + autoconf_product + ".yaml");
|
||||||
|
} else if (found_ch341) {
|
||||||
|
product_config = cleanupNameForAutoconf("lora-usb-" + std::string(autoconf_product) + ".yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't try to automatically find config for a device with RAK eeprom.
|
||||||
|
if (found_rak_eeprom) {
|
||||||
|
std::cerr << "autoconf: Found unknown RAK product " << autoconf_product << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (access((portduino_config.available_directory + product_config).c_str(), R_OK) != 0) {
|
||||||
|
std::cerr << "autoconf: Unable to find config for " << autoconf_product << "(tried " << product_config << ")"
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadConfig((portduino_config.available_directory + product_config).c_str())) {
|
if (loadConfig((portduino_config.available_directory + product_config).c_str())) {
|
||||||
std::cout << "autoconf: Using " << product_config << " as config file for " << autoconf_product << std::endl;
|
std::cout << "autoconf: Using " << product_config << " as config file for " << autoconf_product << std::endl;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,3 +26,31 @@ void getMacAddr(uint8_t *dmac)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cpuDeepSleep(uint32_t msecToWake) {}
|
void cpuDeepSleep(uint32_t msecToWake) {}
|
||||||
|
|
||||||
|
// Hacks to force more code and data out.
|
||||||
|
|
||||||
|
// By default __assert_func uses fiprintf which pulls in stdio.
|
||||||
|
extern "C" void __wrap___assert_func(const char *, int, const char *, const char *)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default strerror has a lot of strings we probably don't use. Make it return an empty string instead.
|
||||||
|
char empty = 0;
|
||||||
|
extern "C" char *__wrap_strerror(int)
|
||||||
|
{
|
||||||
|
return ∅
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_EXCLUDE_TZ
|
||||||
|
struct _reent;
|
||||||
|
|
||||||
|
// Even if you don't use timezones, mktime will try to set the timezone anyway with _tzset_unlocked(), which pulls in scanf and
|
||||||
|
// friends. The timezone is initialized to UTC by default.
|
||||||
|
extern "C" void __wrap__tzset_unlocked_r(struct _reent *reent_ptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -144,4 +144,6 @@ class Power : private concurrency::OSThread
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void battery_adcEnable();
|
||||||
|
|
||||||
extern Power *power;
|
extern Power *power;
|
||||||
|
|||||||
@@ -56,5 +56,6 @@
|
|||||||
// "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME",
|
// "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME",
|
||||||
// "USERPREFS_RINGTONE_NAG_SECS": "60",
|
// "USERPREFS_RINGTONE_NAG_SECS": "60",
|
||||||
"USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",
|
"USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",
|
||||||
|
// "USERPREFS_NETWORK_IPV6_ENABLED": "1",
|
||||||
"USERPREFS_TZ_STRING": "tzplaceholder "
|
"USERPREFS_TZ_STRING": "tzplaceholder "
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "RadioLib.h"
|
||||||
|
|
||||||
|
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||||
|
|
||||||
|
static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||||
|
// mode DIO5 DIO6
|
||||||
|
{LR11x0::MODE_STBY, {LOW, LOW}}, {LR11x0::MODE_RX, {HIGH, LOW}},
|
||||||
|
{LR11x0::MODE_TX, {LOW, HIGH}}, {LR11x0::MODE_TX_HP, {LOW, HIGH}},
|
||||||
|
{LR11x0::MODE_TX_HF, {LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW}},
|
||||||
|
{LR11x0::MODE_WIFI, {LOW, LOW}}, END_OF_MODE_TABLE,
|
||||||
|
};
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
// not found then probe for SX1262
|
// not found then probe for SX1262
|
||||||
#define USE_SX1262
|
#define USE_SX1262
|
||||||
#define USE_SX1268
|
#define USE_SX1268
|
||||||
|
#define USE_LR1121
|
||||||
|
|
||||||
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
||||||
#define LORA_RESET 5
|
#define LORA_RESET 5
|
||||||
@@ -34,6 +35,19 @@
|
|||||||
// code)
|
// code)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// LR1121
|
||||||
|
#ifdef USE_LR1121
|
||||||
|
#define LR1121_IRQ_PIN 1
|
||||||
|
#define LR1121_NRESET_PIN LORA_RESET
|
||||||
|
#define LR1121_BUSY_PIN 4
|
||||||
|
#define LR1121_SPI_NSS_PIN 10
|
||||||
|
#define LR1121_SPI_SCK_PIN 12
|
||||||
|
#define LR1121_SPI_MOSI_PIN 11
|
||||||
|
#define LR1121_SPI_MISO_PIN 13
|
||||||
|
#define LR11X0_DIO3_TCXO_VOLTAGE 3.0
|
||||||
|
#define LR11X0_DIO_AS_RF_SWITCH
|
||||||
|
#endif
|
||||||
|
|
||||||
// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
|
// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
|
||||||
// and waking from light sleep
|
// and waking from light sleep
|
||||||
// #define PMU_IRQ 40
|
// #define PMU_IRQ 40
|
||||||
@@ -64,4 +78,4 @@
|
|||||||
// has 32768 Hz crystal
|
// has 32768 Hz crystal
|
||||||
#define HAS_32768HZ 1
|
#define HAS_32768HZ 1
|
||||||
|
|
||||||
#define USE_SH1106
|
#define USE_SH1106
|
||||||
@@ -210,6 +210,16 @@ No longer populated on PCB
|
|||||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
#define ADC_MULTIPLIER (4.916F)
|
#define ADC_MULTIPLIER (4.916F)
|
||||||
|
|
||||||
|
// rf52840 AIN2 = Pin 4
|
||||||
|
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_2
|
||||||
|
|
||||||
|
// We have AIN2 with a VBAT divider so AIN2 = VBAT * (100/490)
|
||||||
|
// We have the device going deep sleep under 3.1V, which is AIN2 = 0.63V
|
||||||
|
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN2 = 0.67V
|
||||||
|
// Ratio 0.67/3.3 = 0.20, so we can pick a bit higher, 2/8 VDD, which means
|
||||||
|
// VBAT=4.04V
|
||||||
|
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_2_8
|
||||||
|
|
||||||
#define HAS_RTC 0
|
#define HAS_RTC 0
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ No longer populated on PCB
|
|||||||
#undef AREF_VOLTAGE
|
#undef AREF_VOLTAGE
|
||||||
#define AREF_VOLTAGE 3.0
|
#define AREF_VOLTAGE 3.0
|
||||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
#define ADC_MULTIPLIER (4.90F)
|
#define ADC_MULTIPLIER (4.6425F)
|
||||||
|
|
||||||
#undef HAS_GPS
|
#undef HAS_GPS
|
||||||
#define HAS_GPS 0
|
#define HAS_GPS 0
|
||||||
@@ -129,4 +129,4 @@ No longer populated on PCB
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -267,6 +267,20 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
|||||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
#define ADC_MULTIPLIER 1.73
|
#define ADC_MULTIPLIER 1.73
|
||||||
|
|
||||||
|
// RAK4630 AIN0 = nrf52840 AIN3 = Pin 5
|
||||||
|
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_3
|
||||||
|
|
||||||
|
// We have AIN3 with a VBAT divider so AIN3 = VBAT * (1.5/2.5)
|
||||||
|
// We have the device going deep sleep under 3.1V, which is AIN3 = 1.86V
|
||||||
|
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN3 = 1.98V
|
||||||
|
// 1.98/3.3 = 6/10, but that's close to the VBAT divider, so we
|
||||||
|
// pick 6/8VDD, which means VBAT=4.1V.
|
||||||
|
// Reference:
|
||||||
|
// VDD=3.3V AIN3=5/8*VDD=2.06V VBAT=1.66*AIN3=3.41V
|
||||||
|
// VDD=3.3V AIN3=11/16*VDD=2.26V VBAT=1.66*AIN3=3.76V
|
||||||
|
// VDD=3.3V AIN3=6/8*VDD=2.47V VBAT=1.66*AIN3=4.1V
|
||||||
|
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_11_16
|
||||||
|
|
||||||
#define HAS_RTC 1
|
#define HAS_RTC 1
|
||||||
|
|
||||||
#define HAS_ETHERNET 1
|
#define HAS_ETHERNET 1
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Do not expect a working Meshtastic device with this target.
|
|||||||
#define USE_STM32WLx
|
#define USE_STM32WLx
|
||||||
|
|
||||||
#define LED_PIN PB5
|
#define LED_PIN PB5
|
||||||
#define LED_STATE_ON 1
|
#define LED_STATE_ON 0
|
||||||
|
|
||||||
#define WIO_E5
|
#define WIO_E5
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 2
|
major = 2
|
||||||
minor = 7
|
minor = 7
|
||||||
build = 15
|
build = 16
|
||||||
Reference in New Issue
Block a user