mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-22 03:02:08 +10:00
Merge remote-tracking branch 'remotes/origin/master' into arduino-esp32-v3.2
# Conflicts: # arch/esp32/esp32.ini # src/graphics/draw/MenuHandler.cpp # src/modules/Modules.cpp # variants/esp32s3/seeed-sensecap-indicator/platformio.ini
This commit is contained in:
+218
-8
@@ -20,6 +20,11 @@
|
||||
#include "meshUtils.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
#include "api/WiFiServerAPI.h"
|
||||
#include "input/LinuxInputImpl.h"
|
||||
#endif
|
||||
|
||||
// Working USB detection for powered/charging states on the RAK platform
|
||||
#ifdef NRF_APM
|
||||
#include "nrfx_power.h"
|
||||
@@ -103,7 +108,7 @@ NullSensor ina3221Sensor;
|
||||
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL)
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
#include "modules/Telemetry/Sensor/MAX17048Sensor.h"
|
||||
#include <utility>
|
||||
extern std::pair<uint8_t, TwoWire *> nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
|
||||
@@ -120,6 +125,15 @@ NullSensor max17048Sensor;
|
||||
RAK9154Sensor rak9154Sensor;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PPM
|
||||
// note: XPOWERS_CHIP_XXX must be defined in variant.h
|
||||
#include <XPowersLib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAS_BQ27220
|
||||
#include "bq27220.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PMU
|
||||
XPowersLibInterface *PMU = NULL;
|
||||
#else
|
||||
@@ -278,7 +292,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAS_TELEMETRY && !defined(ARCH_STM32WL) && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
#if HAS_TELEMETRY && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
if (hasINA()) {
|
||||
return getINAVoltage();
|
||||
}
|
||||
@@ -456,8 +470,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
#ifdef EXT_CHRG_DETECT
|
||||
return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value;
|
||||
#else
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_STM32WL) && \
|
||||
!defined(DISABLE_INA_CHARGING_DETECTION)
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(DISABLE_INA_CHARGING_DETECTION)
|
||||
if (hasINA()) {
|
||||
// get current flow from INA sensor - negative value means power flowing into the battery
|
||||
// default assuming BATTERY+ <--> INA_VIN+ <--> SHUNT RESISTOR <--> INA_VIN- <--> LOAD
|
||||
@@ -503,7 +516,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_STM32WL)
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
uint16_t getINAVoltage()
|
||||
{
|
||||
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {
|
||||
@@ -666,6 +679,8 @@ bool Power::setup()
|
||||
found = true;
|
||||
} else if (lipoInit()) {
|
||||
found = true;
|
||||
} else if (lipoChargerInit()) {
|
||||
found = true;
|
||||
} else if (analogInit()) {
|
||||
found = true;
|
||||
}
|
||||
@@ -680,9 +695,59 @@ bool Power::setup()
|
||||
return found;
|
||||
}
|
||||
|
||||
void Power::powerCommandsCheck()
|
||||
{
|
||||
if (rebootAtMsec && millis() > rebootAtMsec) {
|
||||
LOG_INFO("Rebooting");
|
||||
reboot();
|
||||
}
|
||||
|
||||
if (shutdownAtMsec && millis() > shutdownAtMsec) {
|
||||
shutdownAtMsec = 0;
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void Power::reboot()
|
||||
{
|
||||
notifyReboot.notifyObservers(NULL);
|
||||
#if defined(ARCH_ESP32)
|
||||
ESP.restart();
|
||||
#elif defined(ARCH_NRF52)
|
||||
NVIC_SystemReset();
|
||||
#elif defined(ARCH_RP2040)
|
||||
rp2040.reboot();
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
deInitApiServer();
|
||||
if (aLinuxInputImpl)
|
||||
aLinuxInputImpl->deInit();
|
||||
SPI.end();
|
||||
Wire.end();
|
||||
Serial1.end();
|
||||
if (screen)
|
||||
delete screen;
|
||||
LOG_DEBUG("final reboot!");
|
||||
reboot();
|
||||
#elif defined(ARCH_STM32WL)
|
||||
HAL_NVIC_SystemReset();
|
||||
#else
|
||||
rebootAtMsec = -1;
|
||||
LOG_WARN("FIXME implement reboot for this platform. Note that some settings require a restart to be applied");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Power::shutdown()
|
||||
{
|
||||
LOG_INFO("Shutting Down");
|
||||
|
||||
#if HAS_SCREEN
|
||||
if (screen) {
|
||||
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
|
||||
}
|
||||
#endif
|
||||
#if !defined(ARCH_STM32WL)
|
||||
playShutdownMelody();
|
||||
#endif
|
||||
nodeDB->saveToDisk();
|
||||
|
||||
#if defined(ARCH_NRF52) || defined(ARCH_ESP32) || defined(ARCH_RP2040)
|
||||
#ifdef PIN_LED1
|
||||
@@ -694,7 +759,11 @@ void Power::shutdown()
|
||||
#ifdef PIN_LED3
|
||||
ledOff(PIN_LED3);
|
||||
#endif
|
||||
doDeepSleep(DELAY_FOREVER, false, false);
|
||||
doDeepSleep(DELAY_FOREVER, false, true);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
exit(EXIT_SUCCESS);
|
||||
#else
|
||||
LOG_WARN("FIXME implement shutdown for this platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1161,7 +1230,7 @@ bool Power::axpChipInit()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
#if !MESHTASTIC_EXCLUDE_I2C && __has_include(<Adafruit_MAX1704X.h>)
|
||||
|
||||
/**
|
||||
* Wrapper class for an I2C MAX17048 Lipo battery sensor.
|
||||
@@ -1238,3 +1307,144 @@ bool Power::lipoInit()
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAS_PPM) && HAS_PPM
|
||||
|
||||
/**
|
||||
* Adapter class for BQ25896/BQ27220 Lipo battery charger.
|
||||
*/
|
||||
class LipoCharger : public HasBatteryLevel
|
||||
{
|
||||
private:
|
||||
XPowersPPM *ppm = nullptr;
|
||||
BQ27220 *bq = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Init the I2C BQ25896 Lipo battery charger
|
||||
*/
|
||||
bool runOnce()
|
||||
{
|
||||
if (ppm == nullptr) {
|
||||
ppm = new XPowersPPM;
|
||||
bool result = ppm->init(Wire, I2C_SDA, I2C_SCL, BQ25896_ADDR);
|
||||
if (result) {
|
||||
LOG_INFO("PPM BQ25896 init succeeded");
|
||||
// Set the minimum operating voltage. Below this voltage, the PPM will protect
|
||||
// ppm->setSysPowerDownVoltage(3100);
|
||||
|
||||
// Set input current limit, default is 500mA
|
||||
// ppm->setInputCurrentLimit(800);
|
||||
|
||||
// Disable current limit pin
|
||||
// ppm->disableCurrentLimitPin();
|
||||
|
||||
// Set the charging target voltage, Range:3840 ~ 4608mV ,step:16 mV
|
||||
ppm->setChargeTargetVoltage(4288);
|
||||
|
||||
// Set the precharge current , Range: 64mA ~ 1024mA ,step:64mA
|
||||
// ppm->setPrechargeCurr(64);
|
||||
|
||||
// The premise is that limit pin is disabled, or it will
|
||||
// only follow the maximum charging current set by limit pin.
|
||||
// Set the charging current , Range:0~5056mA ,step:64mA
|
||||
ppm->setChargerConstantCurr(1024);
|
||||
|
||||
// To obtain voltage data, the ADC must be enabled first
|
||||
ppm->enableMeasure();
|
||||
|
||||
// Turn on charging function
|
||||
// If there is no battery connected, do not turn on the charging function
|
||||
ppm->enableCharge();
|
||||
} else {
|
||||
LOG_WARN("PPM BQ25896 init failed");
|
||||
delete ppm;
|
||||
ppm = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (bq == nullptr) {
|
||||
bq = new BQ27220;
|
||||
bq->setDefaultCapacity(BQ27220_DESIGN_CAPACITY);
|
||||
|
||||
bool result = bq->init();
|
||||
if (result) {
|
||||
LOG_DEBUG("BQ27220 design capacity: %d", bq->getDesignCapacity());
|
||||
LOG_DEBUG("BQ27220 fullCharge capacity: %d", bq->getFullChargeCapacity());
|
||||
LOG_DEBUG("BQ27220 remaining capacity: %d", bq->getRemainingCapacity());
|
||||
return true;
|
||||
} else {
|
||||
LOG_WARN("BQ27220 init failed");
|
||||
delete bq;
|
||||
bq = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||
*/
|
||||
virtual int getBatteryPercent() override
|
||||
{
|
||||
return -1;
|
||||
// return bq->getChargePercent(); // don't use BQ27220 for battery percent, it is not calibrated
|
||||
}
|
||||
|
||||
/**
|
||||
* The raw voltage of the battery in millivolts, or NAN if unknown
|
||||
*/
|
||||
virtual uint16_t getBattVoltage() override { return bq->getVoltage(); }
|
||||
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() override { return ppm->getBattVoltage() > 0; }
|
||||
|
||||
/**
|
||||
* return true if there is an external power source detected
|
||||
*/
|
||||
virtual bool isVbusIn() override { return ppm->getVbusVoltage() > 0; }
|
||||
|
||||
/**
|
||||
* return true if the battery is currently charging
|
||||
*/
|
||||
virtual bool isCharging() override
|
||||
{
|
||||
bool isCharging = ppm->isCharging();
|
||||
if (isCharging) {
|
||||
LOG_DEBUG("BQ27220 time to full charge: %d min", bq->getTimeToFull());
|
||||
} else {
|
||||
if (!ppm->isVbusIn()) {
|
||||
LOG_DEBUG("BQ27220 time to empty: %d min (%d mAh)", bq->getTimeToEmpty(), bq->getRemainingCapacity());
|
||||
}
|
||||
}
|
||||
return isCharging;
|
||||
}
|
||||
};
|
||||
|
||||
LipoCharger lipoCharger;
|
||||
|
||||
/**
|
||||
* Init the Lipo battery charger
|
||||
*/
|
||||
bool Power::lipoChargerInit()
|
||||
{
|
||||
bool result = lipoCharger.runOnce();
|
||||
LOG_DEBUG("Power::lipoChargerInit lipo sensor is %s", result ? "ready" : "not ready yet");
|
||||
if (!result)
|
||||
return false;
|
||||
batteryLevel = &lipoCharger;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
/**
|
||||
* The Lipo battery level sensor is unavailable - default to AnalogBatteryLevel
|
||||
*/
|
||||
bool Power::lipoChargerInit()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ extern Power *power;
|
||||
static void shutdownEnter()
|
||||
{
|
||||
LOG_DEBUG("State: SHUTDOWN");
|
||||
power->shutdown();
|
||||
shutdownAtMsec = millis();
|
||||
}
|
||||
|
||||
#include "error.h"
|
||||
|
||||
@@ -47,10 +47,6 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
|
||||
playComboTune(); // Ping sent feedback
|
||||
break;
|
||||
|
||||
case INPUT_BROKER_SHUTDOWN:
|
||||
playShutdownMelody(); // Shutdown feedback
|
||||
break;
|
||||
|
||||
default:
|
||||
// For other events, check if it's a printable character
|
||||
if (event->kbchar >= 32 && event->kbchar <= 126) {
|
||||
@@ -69,10 +65,7 @@ int32_t BuzzerFeedbackThread::runOnce()
|
||||
// This thread is primarily event-driven, but we can use runOnce
|
||||
// for any periodic tasks if needed in the future
|
||||
|
||||
if (needsUpdate) {
|
||||
needsUpdate = false;
|
||||
// Could add any periodic processing here
|
||||
}
|
||||
needsUpdate = false;
|
||||
|
||||
// Run every 100ms when active, less frequently when idle
|
||||
return needsUpdate ? 100 : 1000;
|
||||
|
||||
+2
-1
@@ -13,5 +13,6 @@ enum class Cmd {
|
||||
START_FIRMWARE_UPDATE_SCREEN,
|
||||
STOP_BOOT_SCREEN,
|
||||
SHOW_PREV_FRAME,
|
||||
SHOW_NEXT_FRAME
|
||||
SHOW_NEXT_FRAME,
|
||||
NOOP
|
||||
};
|
||||
+8
-2
@@ -150,11 +150,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Define if screen should be mirrored left to right
|
||||
// #define SCREEN_MIRROR
|
||||
|
||||
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
|
||||
// I2C Keyboards (M5Stack, RAK14004, T-Deck, T-Deck Pro, T-Lora Pager, CardKB, BBQ10, MPR121, TCA8418)
|
||||
#define CARDKB_ADDR 0x5F
|
||||
#define TDECK_KB_ADDR 0x55
|
||||
#define BBQ10_KB_ADDR 0x1F
|
||||
#define MPR121_KB_ADDR 0x5A
|
||||
#define TCA8418_KB_ADDR 0x34
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SENSOR
|
||||
@@ -193,8 +194,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MLX90614_ADDR_DEF 0x5A
|
||||
#define CGRADSENS_ADDR 0x66
|
||||
#define LTR390UV_ADDR 0x53
|
||||
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418
|
||||
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418_KB
|
||||
#define PCT2075_ADDR 0x37
|
||||
#define BQ27220_ADDR 0x55 // same address as TDECK_KB
|
||||
#define BQ25896_ADDR 0x6B
|
||||
#define LTR553ALS_ADDR 0x23
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ACCELEROMETER
|
||||
@@ -208,6 +212,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define BMX160_ADDR 0x69
|
||||
#define ICM20948_ADDR 0x69
|
||||
#define ICM20948_ADDR_ALT 0x68
|
||||
#define BHI260AP_ADDR 0x28
|
||||
#define BMM150_ADDR 0x13
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -230,6 +235,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Touchscreen
|
||||
// -----------------------------------------------------------------------------
|
||||
#define FT6336U_ADDR 0x48
|
||||
#define CST328_ADDR 0x1A
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected)
|
||||
|
||||
@@ -74,7 +74,12 @@ class ScanI2C
|
||||
RAK12035,
|
||||
TCA8418KB,
|
||||
PCT2075,
|
||||
BMM150,
|
||||
CST328,
|
||||
BQ25896,
|
||||
BQ27220,
|
||||
LTR553ALS,
|
||||
BHI260AP,
|
||||
BMM150
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
@@ -206,7 +206,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
}
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address);
|
||||
case TDECK_KB_ADDR:
|
||||
// Do we have the T-Deck keyboard or the T-Deck Pro battery sensor?
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
|
||||
if (registerValue != 0) {
|
||||
logFoundDevice("BQ27220", (uint8_t)addr.address);
|
||||
type = BQ27220;
|
||||
} else {
|
||||
logFoundDevice("TDECKKB", (uint8_t)addr.address);
|
||||
type = TDECKKB;
|
||||
}
|
||||
break;
|
||||
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address);
|
||||
|
||||
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address);
|
||||
@@ -396,6 +406,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
logFoundDevice("BQ24295", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x14), 1); // get ID
|
||||
if ((registerValue & 0b00000011) == 0b00000010) {
|
||||
type = BQ25896;
|
||||
logFoundDevice("BQ25896", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 1); // get ID
|
||||
if (registerValue == 0x6A) {
|
||||
type = LSM6DS3;
|
||||
@@ -447,6 +463,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(CST328_ADDR, CST328, "CST328", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(LTR553ALS_ADDR, LTR553ALS, "LTR553ALS", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(BHI260AP_ADDR, BHI260AP, "BHI260AP", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(SCD4X_ADDR, SCD4X, "SCD4X", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(BMM150_ADDR, BMM150, "BMM150", (uint8_t)addr.address);
|
||||
#ifdef HAS_TPS65233
|
||||
|
||||
+17
-6
@@ -39,9 +39,9 @@ template <typename T, std::size_t N> std::size_t array_count(const T (&)[N])
|
||||
return N;
|
||||
}
|
||||
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
||||
#if defined(RAK2560)
|
||||
HardwareSerial *GPS::_serial_gps = &Serial2;
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
|
||||
#if defined(GPS_SERIAL_PORT)
|
||||
HardwareSerial *GPS::_serial_gps = &GPS_SERIAL_PORT;
|
||||
#else
|
||||
HardwareSerial *GPS::_serial_gps = &Serial1;
|
||||
#endif
|
||||
@@ -643,8 +643,16 @@ bool GPS::setup()
|
||||
delay(250);
|
||||
} else if (IS_ONE_OF(gnssModel, GNSS_MODEL_AG3335, GNSS_MODEL_AG3352)) {
|
||||
|
||||
_serial_gps->write("$PAIR066,1,0,1,0,0,1*3B\r\n"); // Enable GPS+GALILEO+NAVIC
|
||||
|
||||
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_IN ||
|
||||
config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_NP_865) {
|
||||
_serial_gps->write("$PAIR066,1,0,1,0,0,1*3B\r\n"); // Enable GPS+GALILEO+NAVIC
|
||||
// GPS GLONASS GALILEO BDS QZSS NAVIC
|
||||
// 1 0 1 0 0 1
|
||||
} else {
|
||||
_serial_gps->write("$PAIR066,1,1,1,1,0,0*3A\r\n"); // Enable GPS+GLONASS+GALILEO+BDS
|
||||
// GPS GLONASS GALILEO BDS QZSS NAVIC
|
||||
// 1 1 1 1 0 0
|
||||
}
|
||||
// Configure NMEA (sentences will output once per fix)
|
||||
_serial_gps->write("$PAIR062,0,1*3F\r\n"); // GGA ON
|
||||
_serial_gps->write("$PAIR062,1,0*3F\r\n"); // GLL OFF
|
||||
@@ -1536,7 +1544,10 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
if (t.tm_mon > -1) {
|
||||
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
|
||||
t.tm_sec, ti.age());
|
||||
perhapsSetRTC(RTCQualityGPS, t);
|
||||
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultInvalidTime) {
|
||||
// Clear the GPS buffer if we got an invalid time
|
||||
clearBuffer();
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
|
||||
+18
-7
@@ -105,7 +105,7 @@ void readFromRTC()
|
||||
*
|
||||
* If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
*/
|
||||
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
|
||||
RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
|
||||
{
|
||||
static uint32_t lastSetMsec = 0;
|
||||
uint32_t now = millis();
|
||||
@@ -113,7 +113,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
|
||||
#ifdef BUILD_EPOCH
|
||||
if (tv->tv_sec < BUILD_EPOCH) {
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return false;
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -184,9 +184,9 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
|
||||
readFromRTC();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return RTCSetResultSuccess;
|
||||
} else {
|
||||
return false;
|
||||
return RTCSetResultNotSet; // RTC was already set with a higher quality time
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ const char *RtcName(RTCQuality quality)
|
||||
* @param t The time to potentially set the RTC to.
|
||||
* @return True if the RTC was set to the provided time, false otherwise.
|
||||
*/
|
||||
bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
{
|
||||
/* Convert to unix time
|
||||
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
|
||||
@@ -226,12 +226,19 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
time_t res = gm_mktime(&t);
|
||||
struct timeval tv;
|
||||
tv.tv_sec = res;
|
||||
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
|
||||
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
|
||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||
#ifdef BUILD_EPOCH
|
||||
if (tv.tv_sec < BUILD_EPOCH) {
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
// LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
if (t.tm_year < 0 || t.tm_year >= 300) {
|
||||
// LOG_DEBUG("Ignore invalid GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
return false;
|
||||
return RTCSetResultInvalidTime;
|
||||
} else {
|
||||
return perhapsSetRTC(q, &tv);
|
||||
}
|
||||
@@ -244,11 +251,15 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
*/
|
||||
int32_t getTZOffset()
|
||||
{
|
||||
#if MESHTASTIC_EXCLUDE_TZ
|
||||
return 0;
|
||||
#else
|
||||
time_t now = getTime(false);
|
||||
struct tm *gmt;
|
||||
gmt = gmtime(&now);
|
||||
gmt->tm_isdst = -1;
|
||||
return (int32_t)difftime(now, mktime(gmt));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+11
-2
@@ -22,13 +22,22 @@ enum RTCQuality {
|
||||
RTCQualityGPS = 4
|
||||
};
|
||||
|
||||
/// The RTC set result codes
|
||||
/// Used to indicate the result of an attempt to set the RTC.
|
||||
enum RTCSetResult {
|
||||
RTCSetResultNotSet = 0, ///< RTC was set successfully
|
||||
RTCSetResultSuccess = 1, ///< RTC was set successfully
|
||||
RTCSetResultInvalidTime = 3, ///< The provided time was invalid (e.g., before the build epoch)
|
||||
RTCSetResultError = 4 ///< An error occurred while setting the RTC
|
||||
};
|
||||
|
||||
RTCQuality getRTCQuality();
|
||||
|
||||
extern uint32_t lastSetFromPhoneNtpOrGps;
|
||||
|
||||
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false);
|
||||
bool perhapsSetRTC(RTCQuality q, struct tm &t);
|
||||
RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false);
|
||||
RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t);
|
||||
|
||||
/// Return a string name for the quality
|
||||
const char *RtcName(RTCQuality quality);
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include "main.h"
|
||||
#include <SPI.h>
|
||||
|
||||
#ifdef GXEPD2_DRIVER_0
|
||||
#include "einkDetect.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
The macros EINK_DISPLAY_MODEL, EINK_WIDTH, and EINK_HEIGHT are defined as build_flags in a variant's platformio.ini
|
||||
Previously, these macros were defined at the top of this file.
|
||||
@@ -174,9 +178,8 @@ bool EInkDisplay::connect()
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \
|
||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
||||
{
|
||||
// Start HSPI
|
||||
hspi = new SPIClass(HSPI);
|
||||
@@ -203,7 +206,7 @@ bool EInkDisplay::connect()
|
||||
adafruitDisplay->setRotation(0);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||
}
|
||||
#elif defined(M5_COREINK)
|
||||
#elif defined(M5_COREINK) || defined(T_DECK_PRO)
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
@@ -232,6 +235,23 @@ bool EInkDisplay::connect()
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
}
|
||||
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
||||
|
||||
// Detect display model, before starting SPI
|
||||
EInkDetectionResult displayModel = detectEInk();
|
||||
|
||||
// Start HSPI
|
||||
hspi = new SPIClass(HSPI);
|
||||
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
|
||||
|
||||
// Create GxEPD2 object
|
||||
adafruitDisplay = new GxEPD2_Multi<GXEPD2_DRIVER_0, GXEPD2_DRIVER_1>((uint8_t)displayModel, PIN_EINK_CS, PIN_EINK_DC,
|
||||
PIN_EINK_RES, PIN_EINK_BUSY, *hspi);
|
||||
|
||||
// Init GxEPD2
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include "GxEPD2_BW.h"
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
#ifdef GXEPD2_DRIVER_0 // If variant has multiple possible display models
|
||||
#include "GxEPD2Multi.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation.
|
||||
*
|
||||
@@ -63,8 +67,15 @@ class EInkDisplay : public OLEDDisplay
|
||||
// Connect to the display
|
||||
virtual bool connect() override;
|
||||
|
||||
// AdafruitGFX display object - instantiated in connect(), variant specific
|
||||
#ifdef GXEPD2_DRIVER_0
|
||||
// AdafruitGFX display object - wrapper for multiple drivers
|
||||
// Allows runtime detection of multiple displays
|
||||
// Avoid this situation if possible!
|
||||
GxEPD2_Multi<GXEPD2_DRIVER_0, GXEPD2_DRIVER_1> *adafruitDisplay = NULL;
|
||||
#else
|
||||
// AdafruitGFX display object (for single display model) - instantiated in connect(), variant specific
|
||||
GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT> *adafruitDisplay = NULL;
|
||||
#endif
|
||||
|
||||
// If display uses HSPI
|
||||
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
// Wrapper class for GxEPD2_BW
|
||||
|
||||
// Generic signature at build-time, so that we can detect display model at run-time
|
||||
// Workaround for issue of GxEPD2_BW objects not having a shared base class
|
||||
// Only exposes methods which we are actually using
|
||||
|
||||
template <typename Driver0, typename Driver1> class GxEPD2_Multi
|
||||
{
|
||||
public:
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->drawPixel(x, y, color);
|
||||
else
|
||||
driver1->drawPixel(x, y, color);
|
||||
}
|
||||
|
||||
bool nextPage()
|
||||
{
|
||||
if (which == 0)
|
||||
return driver0->nextPage();
|
||||
else
|
||||
return driver1->nextPage();
|
||||
}
|
||||
|
||||
void hibernate()
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->hibernate();
|
||||
else
|
||||
driver1->hibernate();
|
||||
}
|
||||
|
||||
void init(uint32_t serial_diag_bitrate = 0)
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->init(serial_diag_bitrate);
|
||||
else
|
||||
driver1->init(serial_diag_bitrate);
|
||||
}
|
||||
|
||||
void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false)
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
|
||||
else
|
||||
driver1->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
|
||||
}
|
||||
|
||||
void setRotation(uint8_t x)
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->setRotation(x);
|
||||
else
|
||||
driver1->setRotation(x);
|
||||
}
|
||||
|
||||
void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->setPartialWindow(x, y, w, h);
|
||||
else
|
||||
driver1->setPartialWindow(x, y, w, h);
|
||||
}
|
||||
|
||||
void setFullWindow()
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->setFullWindow();
|
||||
else
|
||||
driver1->setFullWindow();
|
||||
}
|
||||
|
||||
int16_t width()
|
||||
{
|
||||
if (which == 0)
|
||||
return driver0->width();
|
||||
else
|
||||
return driver1->width();
|
||||
}
|
||||
|
||||
int16_t height()
|
||||
{
|
||||
if (which == 0)
|
||||
return driver0->height();
|
||||
else
|
||||
return driver1->height();
|
||||
}
|
||||
|
||||
void clearScreen(uint8_t value = 0xFF)
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->clearScreen();
|
||||
else
|
||||
driver1->clearScreen();
|
||||
}
|
||||
|
||||
void endAsyncFull()
|
||||
{
|
||||
if (which == 0)
|
||||
driver0->endAsyncFull();
|
||||
else
|
||||
driver1->endAsyncFull();
|
||||
}
|
||||
|
||||
// Exposes methods of the GxEPD2_EPD object which is usually available as GxEPD2_BW::epd
|
||||
class Epd2Wrapper
|
||||
{
|
||||
public:
|
||||
bool isBusy() { return m_epd2->isBusy(); }
|
||||
GxEPD2_EPD *m_epd2;
|
||||
} epd2;
|
||||
|
||||
// Constructor
|
||||
// Select driver by passing whichDriver as 0 or 1
|
||||
GxEPD2_Multi(uint8_t whichDriver, int16_t cs, int16_t dc, int16_t rst, int16_t busy, SPIClass &spi)
|
||||
{
|
||||
assert(whichDriver == 0 || whichDriver == 1);
|
||||
which = whichDriver;
|
||||
LOG_DEBUG("GxEPD2_Multi driver: %d", which);
|
||||
|
||||
if (which == 0) {
|
||||
driver0 = new GxEPD2_BW<Driver0, Driver0::HEIGHT>(Driver0(cs, dc, rst, busy, spi));
|
||||
epd2.m_epd2 = &(driver0->epd2);
|
||||
} else if (which == 1) {
|
||||
driver1 = new GxEPD2_BW<Driver1, Driver1::HEIGHT>(Driver1(cs, dc, rst, busy, spi));
|
||||
epd2.m_epd2 = &(driver1->epd2);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t which;
|
||||
GxEPD2_BW<Driver0, Driver0::HEIGHT> *driver0;
|
||||
GxEPD2_BW<Driver1, Driver1::HEIGHT> *driver1;
|
||||
};
|
||||
+217
-96
@@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "Screen.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerMon.h"
|
||||
#include "Throttle.h"
|
||||
#include "configuration.h"
|
||||
@@ -44,7 +45,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endif
|
||||
#include "FSCommon.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "error.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
@@ -69,6 +69,8 @@ using graphics::Emote;
|
||||
using graphics::emotes;
|
||||
using graphics::numEmotes;
|
||||
|
||||
extern uint16_t TFT_MESH;
|
||||
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
@@ -135,9 +137,64 @@ extern bool hasUnreadMessage;
|
||||
// Displays a temporary centered banner message (e.g., warning, status, etc.)
|
||||
// The banner appears in the center of the screen and disappears after the specified duration
|
||||
|
||||
void Screen::showSimpleBanner(const char *message, uint32_t durationMs)
|
||||
{
|
||||
BannerOverlayOptions options;
|
||||
options.message = message;
|
||||
options.durationMs = durationMs;
|
||||
options.notificationType = notificationTypeEnum::text_banner;
|
||||
showOverlayBanner(options);
|
||||
}
|
||||
|
||||
// Called to trigger a banner with custom message and duration
|
||||
void Screen::showOverlayBanner(const char *message, uint32_t durationMs, const char **optionsArrayPtr, uint8_t options,
|
||||
std::function<void(int)> bannerCallback, int8_t InitialSelected)
|
||||
void Screen::showOverlayBanner(BannerOverlayOptions banner_overlay_options)
|
||||
{
|
||||
#ifdef USE_EINK
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
|
||||
#endif
|
||||
// Store the message and set the expiration timestamp
|
||||
strncpy(NotificationRenderer::alertBannerMessage, banner_overlay_options.message, 255);
|
||||
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
||||
NotificationRenderer::alertBannerUntil =
|
||||
(banner_overlay_options.durationMs == 0) ? 0 : millis() + banner_overlay_options.durationMs;
|
||||
NotificationRenderer::optionsArrayPtr = banner_overlay_options.optionsArrayPtr;
|
||||
NotificationRenderer::optionsEnumPtr = banner_overlay_options.optionsEnumPtr;
|
||||
NotificationRenderer::alertBannerOptions = banner_overlay_options.optionsCount;
|
||||
NotificationRenderer::alertBannerCallback = banner_overlay_options.bannerCallback;
|
||||
NotificationRenderer::curSelected = banner_overlay_options.InitialSelected;
|
||||
NotificationRenderer::pauseBanner = false;
|
||||
NotificationRenderer::current_notification_type = notificationTypeEnum::selection_picker;
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
ui->setTargetFPS(60);
|
||||
ui->update();
|
||||
}
|
||||
|
||||
// Called to trigger a banner with custom message and duration
|
||||
void Screen::showNodePicker(const char *message, uint32_t durationMs, std::function<void(uint32_t)> bannerCallback)
|
||||
{
|
||||
#ifdef USE_EINK
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
|
||||
#endif
|
||||
nodeDB->pause_sort(true);
|
||||
// Store the message and set the expiration timestamp
|
||||
strncpy(NotificationRenderer::alertBannerMessage, message, 255);
|
||||
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
||||
NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs;
|
||||
NotificationRenderer::alertBannerCallback = bannerCallback;
|
||||
NotificationRenderer::pauseBanner = false;
|
||||
NotificationRenderer::curSelected = 0;
|
||||
NotificationRenderer::current_notification_type = notificationTypeEnum::node_picker;
|
||||
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
ui->setTargetFPS(60);
|
||||
ui->update();
|
||||
}
|
||||
|
||||
// Called to trigger a banner with custom message and duration
|
||||
void Screen::showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits,
|
||||
std::function<void(uint32_t)> bannerCallback)
|
||||
{
|
||||
#ifdef USE_EINK
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
|
||||
@@ -146,14 +203,16 @@ void Screen::showOverlayBanner(const char *message, uint32_t durationMs, const c
|
||||
strncpy(NotificationRenderer::alertBannerMessage, message, 255);
|
||||
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
||||
NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs;
|
||||
NotificationRenderer::optionsArrayPtr = optionsArrayPtr;
|
||||
NotificationRenderer::alertBannerOptions = options;
|
||||
NotificationRenderer::alertBannerCallback = bannerCallback;
|
||||
NotificationRenderer::curSelected = InitialSelected;
|
||||
NotificationRenderer::pauseBanner = false;
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawAlertBannerOverlay};
|
||||
NotificationRenderer::curSelected = 0;
|
||||
NotificationRenderer::current_notification_type = notificationTypeEnum::number_picker;
|
||||
NotificationRenderer::numDigits = digits;
|
||||
NotificationRenderer::currentNumber = 0;
|
||||
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
setFastFramerate(); // Draw ASAP
|
||||
ui->setTargetFPS(60);
|
||||
ui->update();
|
||||
}
|
||||
|
||||
@@ -230,6 +289,20 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32)
|
||||
{
|
||||
graphics::normalFrames = new FrameCallback[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||
|
||||
LOG_INFO("Protobuf Value uiconfig.screen_rgb_color: %d", uiconfig.screen_rgb_color);
|
||||
int32_t rawRGB = uiconfig.screen_rgb_color;
|
||||
if (rawRGB > 0 && rawRGB <= 255255255) {
|
||||
uint8_t TFT_MESH_r = (rawRGB >> 16) & 0xFF;
|
||||
uint8_t TFT_MESH_g = (rawRGB >> 8) & 0xFF;
|
||||
uint8_t TFT_MESH_b = rawRGB & 0xFF;
|
||||
LOG_INFO("Values of r,g,b: %d, %d, %d", TFT_MESH_r, TFT_MESH_g, TFT_MESH_b);
|
||||
|
||||
if (TFT_MESH_r <= 255 && TFT_MESH_g <= 255 && TFT_MESH_b <= 255) {
|
||||
TFT_MESH = COLOR565(TFT_MESH_r, TFT_MESH_g, TFT_MESH_b);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||
dispdev = new SH1106Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
@@ -239,8 +312,8 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
ST7789_MISO, ST7789_SCK);
|
||||
#else
|
||||
dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
||||
static_cast<ST7789Spi *>(dispdev)->setRGB(COLOR565(255, 255, 128));
|
||||
#endif
|
||||
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||
#elif defined(USE_SSD1306)
|
||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
@@ -313,9 +386,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
#ifdef T_WATCH_S3
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||
#endif
|
||||
#ifdef HELTEC_TRACKER_V1_X
|
||||
uint8_t tft_vext_enabled = digitalRead(VEXT_ENABLE);
|
||||
#endif
|
||||
|
||||
#if !ARCH_PORTDUINO
|
||||
dispdev->displayOn();
|
||||
#endif
|
||||
@@ -327,10 +398,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
|
||||
dispdev->displayOn();
|
||||
#ifdef HELTEC_TRACKER_V1_X
|
||||
// If the TFT VEXT power is not enabled, initialize the UI.
|
||||
if (!tft_vext_enabled) {
|
||||
ui->init();
|
||||
}
|
||||
ui->init();
|
||||
#endif
|
||||
#ifdef USE_ST7789
|
||||
pinMode(VTFT_CTRL, OUTPUT);
|
||||
@@ -386,9 +454,22 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
|
||||
void Screen::setup()
|
||||
{
|
||||
|
||||
// === Enable display rendering ===
|
||||
useDisplay = true;
|
||||
|
||||
// === Load saved brightness from UI config ===
|
||||
// For OLED displays (SSD1306), default brightness is 255 if not set
|
||||
if (uiconfig.screen_brightness == 0) {
|
||||
#if defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||
brightness = 255; // Default for OLED
|
||||
#else
|
||||
brightness = BRIGHTNESS_DEFAULT;
|
||||
#endif
|
||||
} else {
|
||||
brightness = uiconfig.screen_brightness;
|
||||
}
|
||||
|
||||
// === Detect OLED subtype (if supported by board variant) ===
|
||||
#ifdef AutoOLEDWire_h
|
||||
if (isAUTOOled)
|
||||
@@ -416,6 +497,14 @@ void Screen::setup()
|
||||
ui->disableAllIndicators(); // Disable page indicator dots
|
||||
ui->getUiState()->userData = this; // Allow static callbacks to access Screen instance
|
||||
|
||||
// === Apply loaded brightness ===
|
||||
#if defined(ST7789_CS)
|
||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||
dispdev->setBrightness(brightness);
|
||||
#endif
|
||||
LOG_INFO("Applied screen brightness: %d", brightness);
|
||||
|
||||
// === Set custom overlay callbacks ===
|
||||
static OverlayCallback overlays[] = {
|
||||
graphics::UIRenderer::drawNavigationBar // Custom indicator icons for each frame
|
||||
@@ -490,7 +579,7 @@ void Screen::setup()
|
||||
touchScreenImpl1->init();
|
||||
}
|
||||
}
|
||||
#elif HAS_TOUCHSCREEN
|
||||
#elif HAS_TOUCHSCREEN && !defined(USE_EINK)
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
touchScreenImpl1->init();
|
||||
@@ -546,6 +635,11 @@ void Screen::forceDisplay(bool forceUiUpdate)
|
||||
|
||||
// Tell EInk class to update the display
|
||||
static_cast<EInkDisplay *>(dispdev)->forceDisplay();
|
||||
#else
|
||||
// No delay between UI frame rendering
|
||||
if (forceUiUpdate) {
|
||||
setFastFramerate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -562,7 +656,7 @@ int32_t Screen::runOnce()
|
||||
if (displayHeight == 0) {
|
||||
displayHeight = dispdev->getHeight();
|
||||
}
|
||||
menuHandler::handleMenuSwitch();
|
||||
menuHandler::handleMenuSwitch(dispdev);
|
||||
|
||||
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
|
||||
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
|
||||
@@ -595,7 +689,7 @@ int32_t Screen::runOnce()
|
||||
}
|
||||
#endif
|
||||
if (!NotificationRenderer::isOverlayBannerShowing() && rebootAtMsec != 0) {
|
||||
showOverlayBanner("Rebooting...", 0);
|
||||
showSimpleBanner("Rebooting...", 0);
|
||||
}
|
||||
|
||||
// Process incoming commands.
|
||||
@@ -642,6 +736,8 @@ int32_t Screen::runOnce()
|
||||
EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame
|
||||
setFrames();
|
||||
break;
|
||||
case Cmd::NOOP:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Invalid screen cmd");
|
||||
}
|
||||
@@ -768,6 +864,8 @@ void Screen::setFrames(FrameFocus focus)
|
||||
uint8_t previousFrameCount = framesetInfo.frameCount;
|
||||
FramesetInfo fsi; // Location of specific frames, for applying focus parameter
|
||||
|
||||
graphics::UIRenderer::rebuildFavoritedNodes();
|
||||
|
||||
LOG_DEBUG("Show standard frames");
|
||||
showingNormalScreen = true;
|
||||
|
||||
@@ -785,8 +883,8 @@ void Screen::setFrames(FrameFocus focus)
|
||||
|
||||
#if defined(DISPLAY_CLOCK_FRAME)
|
||||
fsi.positions.clock = numframes;
|
||||
normalFrames[numframes++] = graphics::ClockRenderer::digitalWatchFace ? graphics::ClockRenderer::drawDigitalClockFrame
|
||||
: &graphics::ClockRenderer::drawAnalogClockFrame;
|
||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||
: graphics::ClockRenderer::drawDigitalClockFrame;
|
||||
indicatorIcons.push_back(digital_icon_clock);
|
||||
#endif
|
||||
|
||||
@@ -842,27 +940,11 @@ void Screen::setFrames(FrameFocus focus)
|
||||
}
|
||||
#if !defined(DISPLAY_CLOCK_FRAME)
|
||||
fsi.positions.clock = numframes;
|
||||
normalFrames[numframes++] = graphics::ClockRenderer::digitalWatchFace ? graphics::ClockRenderer::drawDigitalClockFrame
|
||||
: graphics::ClockRenderer::drawAnalogClockFrame;
|
||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||
: graphics::ClockRenderer::drawDigitalClockFrame;
|
||||
indicatorIcons.push_back(digital_icon_clock);
|
||||
#endif
|
||||
|
||||
// We don't show the node info of our node (if we have it yet - we should)
|
||||
size_t numMeshNodes = nodeDB->getNumMeshNodes();
|
||||
if (numMeshNodes > 0)
|
||||
numMeshNodes--;
|
||||
|
||||
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
|
||||
if (fsi.positions.firstFavorite == 255)
|
||||
fsi.positions.firstFavorite = numframes;
|
||||
fsi.positions.lastFavorite = numframes;
|
||||
normalFrames[numframes++] = graphics::UIRenderer::drawNodeInfo;
|
||||
indicatorIcons.push_back(icon_node);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
if (!dismissedFrames.wifi && isWifiAvailable()) {
|
||||
fsi.positions.wifi = numframes;
|
||||
@@ -872,7 +954,7 @@ void Screen::setFrames(FrameFocus focus)
|
||||
#endif
|
||||
|
||||
// Beware of what changes you make in this code!
|
||||
// We pass numfames into GetMeshModulesWithUIFrames() which is highly important!
|
||||
// We pass numframes into GetMeshModulesWithUIFrames() which is highly important!
|
||||
// Inside of that callback, goes over to MeshModule.cpp and we run
|
||||
// modulesWithUIFrames.resize(startIndex, nullptr), to insert nullptr
|
||||
// entries until we're ready to start building the matching entries.
|
||||
@@ -901,6 +983,34 @@ void Screen::setFrames(FrameFocus focus)
|
||||
|
||||
LOG_DEBUG("Added modules. numframes: %d", numframes);
|
||||
|
||||
// We don't show the node info of our node (if we have it yet - we should)
|
||||
size_t numMeshNodes = nodeDB->getNumMeshNodes();
|
||||
if (numMeshNodes > 0)
|
||||
numMeshNodes--;
|
||||
|
||||
// Temporary array to hold favorite node frames
|
||||
std::vector<FrameCallback> favoriteFrames;
|
||||
|
||||
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
|
||||
favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert favorite frames *after* collecting them all
|
||||
if (!favoriteFrames.empty()) {
|
||||
fsi.positions.firstFavorite = numframes;
|
||||
for (const auto &f : favoriteFrames) {
|
||||
normalFrames[numframes++] = f;
|
||||
indicatorIcons.push_back(icon_node);
|
||||
}
|
||||
fsi.positions.lastFavorite = numframes - 1;
|
||||
} else {
|
||||
fsi.positions.firstFavorite = 255;
|
||||
fsi.positions.lastFavorite = 255;
|
||||
}
|
||||
|
||||
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
|
||||
this->frameCount = numframes; // ✅ Save frame count for use in custom overlay
|
||||
LOG_DEBUG("Finished build frames. numframes: %d", numframes);
|
||||
@@ -909,11 +1019,10 @@ void Screen::setFrames(FrameFocus focus)
|
||||
ui->disableAllIndicators();
|
||||
|
||||
// Add overlays: frame icons and alert banner)
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawAlertBannerOverlay};
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||
// just changed)
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list just changed)
|
||||
|
||||
// Focus on a specific frame, in the frame set we just created
|
||||
switch (focus) {
|
||||
@@ -937,6 +1046,9 @@ void Screen::setFrames(FrameFocus focus)
|
||||
// If no module requested focus, will show the first frame instead
|
||||
ui->switchToFrame(fsi.positions.clock);
|
||||
break;
|
||||
case FOCUS_SYSTEM:
|
||||
ui->switchToFrame(fsi.positions.memory);
|
||||
break;
|
||||
|
||||
case FOCUS_PRESERVE:
|
||||
// No more adjustment — force stay on same index
|
||||
@@ -1147,40 +1259,45 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
||||
devicestate.has_rx_text_message = true; // Needed to include the message frame
|
||||
hasUnreadMessage = true; // Enables mail icon in the header
|
||||
setFrames(FOCUS_PRESERVE); // Refresh frame list without switching view
|
||||
forceDisplay(); // Forces screen redraw
|
||||
|
||||
// === Prepare banner content ===
|
||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from);
|
||||
const char *longName = (node && node->has_user) ? node->user.long_name : nullptr;
|
||||
// Only wake/force display if the configuration allows it
|
||||
if (shouldWakeOnReceivedMessage()) {
|
||||
setOn(true); // Wake up the screen first
|
||||
forceDisplay(); // Forces screen redraw
|
||||
|
||||
const char *msgRaw = reinterpret_cast<const char *>(packet->decoded.payload.bytes);
|
||||
// === Prepare banner content ===
|
||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from);
|
||||
const char *longName = (node && node->has_user) ? node->user.long_name : nullptr;
|
||||
|
||||
char banner[256];
|
||||
const char *msgRaw = reinterpret_cast<const char *>(packet->decoded.payload.bytes);
|
||||
|
||||
// Check for bell character in message to determine alert type
|
||||
bool isAlert = false;
|
||||
for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) {
|
||||
if (msgRaw[i] == '\x07') {
|
||||
isAlert = true;
|
||||
break;
|
||||
char banner[256];
|
||||
|
||||
// Check for bell character in message to determine alert type
|
||||
bool isAlert = false;
|
||||
for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) {
|
||||
if (msgRaw[i] == '\x07') {
|
||||
isAlert = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAlert) {
|
||||
if (longName && longName[0]) {
|
||||
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
||||
if (isAlert) {
|
||||
if (longName && longName[0]) {
|
||||
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
||||
} else {
|
||||
strcpy(banner, "Alert Received");
|
||||
}
|
||||
} else {
|
||||
strcpy(banner, "Alert Received");
|
||||
if (longName && longName[0]) {
|
||||
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
||||
} else {
|
||||
strcpy(banner, "New Message");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (longName && longName[0]) {
|
||||
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
||||
} else {
|
||||
strcpy(banner, "New Message");
|
||||
}
|
||||
}
|
||||
|
||||
screen->showOverlayBanner(banner, 3000);
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1219,31 +1336,15 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
setFastFramerate(); // Draw ASAP
|
||||
#endif
|
||||
if (NotificationRenderer::isOverlayBannerShowing()) {
|
||||
NotificationRenderer::inEvent = event->inputEvent;
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar,
|
||||
NotificationRenderer::drawAlertBannerOverlay};
|
||||
NotificationRenderer::inEvent = *event;
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
setFastFramerate(); // Draw ASAP
|
||||
ui->update();
|
||||
|
||||
menuHandler::handleMenuSwitch();
|
||||
menuHandler::handleMenuSwitch(dispdev);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
#if defined(DISPLAY_CLOCK_FRAME)
|
||||
// For the T-Watch, intercept touches to the 'toggle digital/analog watch face' button
|
||||
uint8_t watchFaceFrame = error_code ? 1 : 0;
|
||||
|
||||
if (this->ui->getUiState()->currentFrame == watchFaceFrame && event->touchX >= 204 && event->touchX <= 240 &&
|
||||
event->touchY >= 204 && event->touchY <= 240) {
|
||||
screen->digitalWatchFace = !screen->digitalWatchFace;
|
||||
|
||||
setFrames();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
// Use left or right input from a keyboard to move between frames,
|
||||
// so long as a mesh module isn't using these events for some other purpose
|
||||
@@ -1265,13 +1366,8 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
|
||||
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
|
||||
menuHandler::homeBaseMenu();
|
||||
#if HAS_TFT
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
||||
menuHandler::switchToMUIMenu();
|
||||
#else
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
||||
menuHandler::BuzzerModeMenu();
|
||||
#endif
|
||||
menuHandler::systemBaseMenu();
|
||||
#if HAS_GPS
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) {
|
||||
menuHandler::positionBaseMenu();
|
||||
@@ -1280,9 +1376,12 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
menuHandler::clockMenu();
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
|
||||
menuHandler::LoraRegionPicker();
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage &&
|
||||
devicestate.rx_text_message.from) {
|
||||
menuHandler::messageResponseMenu();
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) {
|
||||
if (devicestate.rx_text_message.from) {
|
||||
menuHandler::messageResponseMenu();
|
||||
} else {
|
||||
menuHandler::textMessageBaseMenu();
|
||||
}
|
||||
} else if (framesetInfo.positions.firstFavorite != 255 &&
|
||||
this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite &&
|
||||
this->ui->getUiState()->currentFrame <= framesetInfo.positions.lastFavorite) {
|
||||
@@ -1294,6 +1393,8 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_hopsignal ||
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_bearings) {
|
||||
menuHandler::nodeListMenu();
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.wifi) {
|
||||
menuHandler::wifiBaseMenu();
|
||||
}
|
||||
} else if (event->inputEvent == INPUT_BROKER_BACK) {
|
||||
showPrevFrame();
|
||||
@@ -1332,3 +1433,23 @@ bool Screen::isOverlayBannerShowing()
|
||||
#else
|
||||
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||
#endif // HAS_SCREEN
|
||||
|
||||
bool shouldWakeOnReceivedMessage()
|
||||
{
|
||||
/*
|
||||
The goal here is to determine when we do NOT wake up the screen on message received:
|
||||
- Any ext. notifications are turned on
|
||||
- If role is not client / client_mute
|
||||
- If the battery level is very low
|
||||
*/
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
return false;
|
||||
}
|
||||
if (!meshtastic_Config_DeviceConfig_Role_CLIENT && !meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) {
|
||||
return false;
|
||||
}
|
||||
if (powerStatus && powerStatus->getBatteryChargePercent() < 10) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+41
-8
@@ -5,10 +5,28 @@
|
||||
#include "detect/ScanI2C.h"
|
||||
#include "mesh/generated/meshtastic/config.pb.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
|
||||
namespace graphics
|
||||
{
|
||||
enum notificationTypeEnum { none, text_banner, selection_picker, node_picker, number_picker };
|
||||
|
||||
struct BannerOverlayOptions {
|
||||
const char *message;
|
||||
uint32_t durationMs = 30000;
|
||||
const char **optionsArrayPtr = nullptr;
|
||||
const int *optionsEnumPtr = nullptr;
|
||||
uint8_t optionsCount = 0;
|
||||
std::function<void(int)> bannerCallback = nullptr;
|
||||
int8_t InitialSelected = 0;
|
||||
notificationTypeEnum notificationType = notificationTypeEnum::text_banner;
|
||||
};
|
||||
} // namespace graphics
|
||||
|
||||
bool shouldWakeOnReceivedMessage();
|
||||
|
||||
#if !HAS_SCREEN
|
||||
#include "power.h"
|
||||
@@ -25,6 +43,7 @@ class Screen
|
||||
FOCUS_TEXTMESSAGE,
|
||||
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
||||
FOCUS_CLOCK,
|
||||
FOCUS_SYSTEM,
|
||||
};
|
||||
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
@@ -39,10 +58,8 @@ class Screen
|
||||
void setFunctionSymbol(std::string) {}
|
||||
void removeFunctionSymbol(std::string) {}
|
||||
void startAlert(const char *) {}
|
||||
void showOverlayBanner(const char *message, uint32_t durationMs = 3000, const char **optionsArrayPtr = nullptr,
|
||||
uint8_t options = 0, std::function<void(int)> bannerCallback = NULL, int8_t InitialSelected = 0)
|
||||
{
|
||||
}
|
||||
void showSimpleBanner(const char *message, uint32_t durationMs = 0) {}
|
||||
void showOverlayBanner(BannerOverlayOptions) {}
|
||||
void setFrames(FrameFocus focus) {}
|
||||
void endAlert() {}
|
||||
};
|
||||
@@ -77,6 +94,7 @@ class Screen
|
||||
#include "commands.h"
|
||||
#include "concurrency/LockGuard.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "graphics/draw/MenuHandler.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "mesh/MeshModule.h"
|
||||
#include "modules/AdminModule.h"
|
||||
@@ -199,6 +217,7 @@ class Screen : public concurrency::OSThread
|
||||
CallbackObserver<Screen, AdminModule_ObserverData *>(this, &Screen::handleAdminMessage);
|
||||
|
||||
public:
|
||||
OLEDDisplay *getDisplayDevice() { return dispdev; }
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
size_t frameCount = 0; // Total number of active frames
|
||||
~Screen();
|
||||
@@ -211,6 +230,7 @@ class Screen : public concurrency::OSThread
|
||||
FOCUS_TEXTMESSAGE,
|
||||
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
||||
FOCUS_CLOCK,
|
||||
FOCUS_SYSTEM,
|
||||
};
|
||||
|
||||
// Regenerate the normal set of frames, focusing a specific frame if requested
|
||||
@@ -225,8 +245,6 @@ class Screen : public concurrency::OSThread
|
||||
meshtastic_Config_DisplayConfig_OledType model;
|
||||
OLEDDISPLAY_GEOMETRY geometry;
|
||||
|
||||
bool ignoreCompass = false;
|
||||
|
||||
bool isOverlayBannerShowing();
|
||||
|
||||
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||
@@ -290,8 +308,17 @@ class Screen : public concurrency::OSThread
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
void showOverlayBanner(const char *message, uint32_t durationMs = 3000, const char **optionsArrayPtr = nullptr,
|
||||
uint8_t options = 0, std::function<void(int)> bannerCallback = NULL, int8_t InitialSelected = 0);
|
||||
void showSimpleBanner(const char *message, uint32_t durationMs = 0);
|
||||
void showOverlayBanner(BannerOverlayOptions);
|
||||
|
||||
void showNodePicker(const char *message, uint32_t durationMs, std::function<void(uint32_t)> bannerCallback);
|
||||
void showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits, std::function<void(uint32_t)> bannerCallback);
|
||||
|
||||
void requestMenu(graphics::menuHandler::screenMenus menuToShow)
|
||||
{
|
||||
graphics::menuHandler::menuQueue = menuToShow;
|
||||
runNow();
|
||||
}
|
||||
|
||||
void startFirmwareUpdateScreen()
|
||||
{
|
||||
@@ -325,6 +352,12 @@ class Screen : public concurrency::OSThread
|
||||
/// Stops showing the boot screen.
|
||||
void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); }
|
||||
|
||||
void runNow()
|
||||
{
|
||||
setFastFramerate();
|
||||
enqueueCmd(ScreenCmd{.cmd = Cmd::NOOP});
|
||||
}
|
||||
|
||||
/// Overrides the default utf8 character conversion, to replace empty space with question marks
|
||||
static char customFontTableLookup(const uint8_t ch)
|
||||
{
|
||||
|
||||
@@ -99,10 +99,17 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
|
||||
// === Battery State ===
|
||||
int chargePercent = powerStatus->getBatteryChargePercent();
|
||||
bool isCharging = powerStatus->getIsCharging() == meshtastic::OptionalBool::OptTrue;
|
||||
if (chargePercent == 100) {
|
||||
bool isCharging = powerStatus->getIsCharging();
|
||||
bool usbPowered = powerStatus->getHasUSB();
|
||||
|
||||
if (chargePercent >= 100) {
|
||||
isCharging = false;
|
||||
}
|
||||
if (chargePercent == 101) {
|
||||
usbPowered = true; // Forcing this flag on for the express purpose that some devices have no concept of having a USB cable
|
||||
// plugged in
|
||||
}
|
||||
|
||||
uint32_t now = millis();
|
||||
|
||||
#ifndef USE_EINK
|
||||
@@ -115,48 +122,63 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
bool useHorizontalBattery = (isHighResolution && screenW >= screenH);
|
||||
const int textY = y + (highlightHeight - FONT_HEIGHT_SMALL) / 2;
|
||||
|
||||
int batteryX = 1;
|
||||
int batteryY = HEADER_OFFSET_Y + 1;
|
||||
|
||||
// === Battery Icons ===
|
||||
if (useHorizontalBattery) {
|
||||
int batteryX = 2;
|
||||
int batteryY = HEADER_OFFSET_Y + 3;
|
||||
display->drawXbm(batteryX, batteryY, 9, 13, batteryBitmap_h_bottom);
|
||||
display->drawXbm(batteryX + 9, batteryY, 9, 13, batteryBitmap_h_top);
|
||||
if (isCharging && isBoltVisibleShared)
|
||||
display->drawXbm(batteryX + 4, batteryY, 9, 13, lightning_bolt_h);
|
||||
else {
|
||||
display->drawLine(batteryX + 5, batteryY, batteryX + 10, batteryY);
|
||||
display->drawLine(batteryX + 5, batteryY + 12, batteryX + 10, batteryY + 12);
|
||||
int fillWidth = 14 * chargePercent / 100;
|
||||
display->fillRect(batteryX + 1, batteryY + 1, fillWidth, 11);
|
||||
if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging
|
||||
batteryX += 1;
|
||||
batteryY += 2;
|
||||
if (isHighResolution) {
|
||||
display->drawXbm(batteryX, batteryY, 19, 12, imgUSB_HighResolution);
|
||||
batteryX += 20; // Icon + 1 pixel
|
||||
} else {
|
||||
display->drawXbm(batteryX, batteryY, 10, 8, imgUSB);
|
||||
batteryX += 11; // Icon + 1 pixel
|
||||
}
|
||||
} else {
|
||||
int batteryX = 1;
|
||||
int batteryY = HEADER_OFFSET_Y + 1;
|
||||
if (useHorizontalBattery) {
|
||||
batteryX += 1;
|
||||
batteryY += 2;
|
||||
display->drawXbm(batteryX, batteryY, 9, 13, batteryBitmap_h_bottom);
|
||||
display->drawXbm(batteryX + 9, batteryY, 9, 13, batteryBitmap_h_top);
|
||||
if (isCharging && isBoltVisibleShared)
|
||||
display->drawXbm(batteryX + 4, batteryY, 9, 13, lightning_bolt_h);
|
||||
else {
|
||||
display->drawLine(batteryX + 5, batteryY, batteryX + 10, batteryY);
|
||||
display->drawLine(batteryX + 5, batteryY + 12, batteryX + 10, batteryY + 12);
|
||||
int fillWidth = 14 * chargePercent / 100;
|
||||
display->fillRect(batteryX + 1, batteryY + 1, fillWidth, 11);
|
||||
}
|
||||
batteryX += 18; // Icon + 2 pixels
|
||||
} else {
|
||||
#ifdef USE_EINK
|
||||
batteryY += 2;
|
||||
batteryY += 2;
|
||||
#endif
|
||||
display->drawXbm(batteryX, batteryY, 7, 11, batteryBitmap_v);
|
||||
if (isCharging && isBoltVisibleShared)
|
||||
display->drawXbm(batteryX + 1, batteryY + 3, 5, 5, lightning_bolt_v);
|
||||
else {
|
||||
display->drawXbm(batteryX - 1, batteryY + 4, 8, 3, batteryBitmap_sidegaps_v);
|
||||
int fillHeight = 8 * chargePercent / 100;
|
||||
int fillY = batteryY - fillHeight;
|
||||
display->fillRect(batteryX + 1, fillY + 10, 5, fillHeight);
|
||||
display->drawXbm(batteryX, batteryY, 7, 11, batteryBitmap_v);
|
||||
if (isCharging && isBoltVisibleShared)
|
||||
display->drawXbm(batteryX + 1, batteryY + 3, 5, 5, lightning_bolt_v);
|
||||
else {
|
||||
display->drawXbm(batteryX - 1, batteryY + 4, 8, 3, batteryBitmap_sidegaps_v);
|
||||
int fillHeight = 8 * chargePercent / 100;
|
||||
int fillY = batteryY - fillHeight;
|
||||
display->fillRect(batteryX + 1, fillY + 10, 5, fillHeight);
|
||||
}
|
||||
batteryX += 9; // Icon + 2 pixels
|
||||
}
|
||||
}
|
||||
|
||||
// === Battery % Display ===
|
||||
char chargeStr[4];
|
||||
snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent);
|
||||
int chargeNumWidth = display->getStringWidth(chargeStr);
|
||||
const int batteryOffset = useHorizontalBattery ? 19 : 9;
|
||||
const int percentX = x + batteryOffset;
|
||||
display->drawString(percentX, textY, chargeStr);
|
||||
display->drawString(percentX + chargeNumWidth - 1, textY, "%");
|
||||
if (isBold) {
|
||||
display->drawString(percentX + 1, textY, chargeStr);
|
||||
display->drawString(percentX + chargeNumWidth, textY, "%");
|
||||
if (chargePercent != 101) {
|
||||
// === Battery % Display ===
|
||||
char chargeStr[4];
|
||||
snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent);
|
||||
int chargeNumWidth = display->getStringWidth(chargeStr);
|
||||
display->drawString(batteryX, textY, chargeStr);
|
||||
display->drawString(batteryX + chargeNumWidth - 1, textY, "%");
|
||||
if (isBold) {
|
||||
display->drawString(batteryX + 1, textY, chargeStr);
|
||||
display->drawString(batteryX + chargeNumWidth, textY, "%");
|
||||
}
|
||||
}
|
||||
|
||||
// === Time and Right-aligned Icons ===
|
||||
@@ -184,7 +206,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
timeX = screenW - xOffset - timeStrWidth + 3;
|
||||
|
||||
// === Show Mail or Mute Icon to the Left of Time ===
|
||||
int iconRightEdge = timeX - 1;
|
||||
int iconRightEdge = timeX - 2;
|
||||
|
||||
bool showMail = false;
|
||||
|
||||
@@ -343,4 +365,30 @@ const int *getTextPositions(OLEDDisplay *display)
|
||||
return textPositions;
|
||||
}
|
||||
|
||||
bool isAllowedPunctuation(char c)
|
||||
{
|
||||
const std::string allowed = ".,!?;:-_()[]{}'\"@#$/\\&+=%~^ ";
|
||||
return allowed.find(c) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string sanitizeString(const std::string &input)
|
||||
{
|
||||
std::string output;
|
||||
bool inReplacement = false;
|
||||
|
||||
for (char c : input) {
|
||||
if (std::isalnum(static_cast<unsigned char>(c)) || isAllowedPunctuation(c)) {
|
||||
output += c;
|
||||
inReplacement = false;
|
||||
} else {
|
||||
if (!inReplacement) {
|
||||
output += 0xbf; // ISO-8859-1 for inverted question mark
|
||||
inReplacement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <OLEDDisplay.h>
|
||||
#include <string>
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
@@ -52,4 +53,8 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
|
||||
const int *getTextPositions(OLEDDisplay *display);
|
||||
|
||||
bool isAllowedPunctuation(char c);
|
||||
|
||||
std::string sanitizeString(const std::string &input);
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
@@ -14,8 +15,10 @@
|
||||
extern SX1509 gpioExtender;
|
||||
#endif
|
||||
|
||||
#ifndef TFT_MESH
|
||||
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
|
||||
#ifdef TFT_MESH_OVERRIDE
|
||||
uint16_t TFT_MESH = TFT_MESH_OVERRIDE;
|
||||
#else
|
||||
uint16_t TFT_MESH = COLOR565(0x67, 0xEA, 0x94);
|
||||
#endif
|
||||
|
||||
#if defined(ST7735S)
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace graphics
|
||||
|
||||
namespace ClockRenderer
|
||||
{
|
||||
bool digitalWatchFace = true;
|
||||
|
||||
void drawSegmentedDisplayColon(OLEDDisplay *display, int x, int y, float scale)
|
||||
{
|
||||
@@ -187,7 +186,7 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
{
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
int line = 1;
|
||||
|
||||
// === Set Title, Blank for Clock
|
||||
const char *titleStr = "";
|
||||
// === Header ===
|
||||
@@ -219,7 +218,6 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
hour %= 12;
|
||||
if (hour == 0)
|
||||
hour = 12;
|
||||
bool isPM = hour >= 12;
|
||||
snprintf(timeString, sizeof(timeString), "%d:%02d", hour, minute);
|
||||
} else {
|
||||
snprintf(timeString, sizeof(timeString), "%02d:%02d", hour, minute);
|
||||
@@ -231,6 +229,8 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
float scale = 1.5;
|
||||
#elif defined(CHATTER_2)
|
||||
float scale = 1.1;
|
||||
#else
|
||||
float scale = 0.75;
|
||||
if (isHighResolution) {
|
||||
@@ -284,6 +284,12 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
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) {
|
||||
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2,
|
||||
isPM ? "pm" : "am");
|
||||
@@ -360,7 +366,7 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
// hour hand radius and y coordinate
|
||||
int16_t hourHandRadius = radius * 0.35;
|
||||
if (isHighResolution) {
|
||||
int16_t hourHandRadius = radius * 0.55;
|
||||
hourHandRadius = radius * 0.55;
|
||||
}
|
||||
int16_t hourHandNoonY = centerY - hourHandRadius;
|
||||
|
||||
@@ -379,7 +385,7 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
|
||||
bool isPM = hour >= 12;
|
||||
if (config.display.use_12h_clock) {
|
||||
bool isPM = hour >= 12;
|
||||
isPM = hour >= 12;
|
||||
display->setFont(FONT_SMALL);
|
||||
int yOffset = isHighResolution ? 1 : 0;
|
||||
#ifdef USE_EINK
|
||||
|
||||
@@ -11,8 +11,6 @@ class Screen;
|
||||
|
||||
namespace ClockRenderer
|
||||
{
|
||||
// Whether we are showing the digital watch face or the analog one
|
||||
extern bool digitalWatchFace;
|
||||
|
||||
// Clock frame functions
|
||||
void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
@@ -50,7 +50,7 @@ void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY,
|
||||
radius += 4;
|
||||
}
|
||||
Point north(0, -radius);
|
||||
if (!config.display.compass_north_top)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING)
|
||||
north.rotate(-myHeading);
|
||||
north.translate(compassX, compassY);
|
||||
|
||||
|
||||
@@ -412,9 +412,9 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
float freq = RadioLibInterface::instance->getFreq();
|
||||
snprintf(freqStr, sizeof(freqStr), "%.3f", freq);
|
||||
if (config.lora.channel_num == 0) {
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %smhz", freqStr);
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %sMHz", freqStr);
|
||||
} else {
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %smhz (%d)", freqStr, config.lora.channel_num);
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %sMHz (%d)", freqStr, config.lora.channel_num);
|
||||
}
|
||||
size_t len = strlen(frequencyslot);
|
||||
if (len >= 4 && strcmp(frequencyslot + len - 4, " (0)") == 0) {
|
||||
@@ -483,7 +483,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
}
|
||||
|
||||
// ****************************
|
||||
// * Memory Screen *
|
||||
// * System Screen *
|
||||
// ****************************
|
||||
void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -501,7 +501,10 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
int line = 1;
|
||||
const int barHeight = 6;
|
||||
const int labelX = x;
|
||||
const int barsOffset = (isHighResolution) ? 24 : 0;
|
||||
int barsOffset = (isHighResolution) ? 24 : 0;
|
||||
#ifdef USE_EINK
|
||||
barsOffset -= 12;
|
||||
#endif
|
||||
const int barX = x + 40 + barsOffset;
|
||||
|
||||
auto drawUsageRow = [&](const char *label, uint32_t used, uint32_t total, bool isHeap = false) {
|
||||
@@ -590,7 +593,19 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
}
|
||||
line += 1;
|
||||
char appversionstr[35];
|
||||
snprintf(appversionstr, sizeof(appversionstr), "Ver.: %s", optstr(APP_VERSION));
|
||||
snprintf(appversionstr, sizeof(appversionstr), "Ver: %s", optstr(APP_VERSION));
|
||||
char appversionstr_formatted[40];
|
||||
char *lastDot = strrchr(appversionstr, '.');
|
||||
if (lastDot) {
|
||||
size_t prefixLen = lastDot - appversionstr;
|
||||
strncpy(appversionstr_formatted, appversionstr, prefixLen);
|
||||
appversionstr_formatted[prefixLen] = '\0';
|
||||
strncat(appversionstr_formatted, " (", sizeof(appversionstr_formatted) - strlen(appversionstr_formatted) - 1);
|
||||
strncat(appversionstr_formatted, lastDot + 1, sizeof(appversionstr_formatted) - strlen(appversionstr_formatted) - 1);
|
||||
strncat(appversionstr_formatted, ")", sizeof(appversionstr_formatted) - strlen(appversionstr_formatted) - 1);
|
||||
strncpy(appversionstr, appversionstr_formatted, sizeof(appversionstr) - 1);
|
||||
appversionstr[sizeof(appversionstr) - 1] = '\0';
|
||||
}
|
||||
int textWidth = display->getStringWidth(appversionstr);
|
||||
int nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line], appversionstr);
|
||||
|
||||
+910
-195
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
#if HAS_SCREEN
|
||||
#include "configuration.h"
|
||||
namespace graphics
|
||||
{
|
||||
@@ -13,30 +15,71 @@ class menuHandler
|
||||
clock_face_picker,
|
||||
clock_menu,
|
||||
position_base_menu,
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
gps_toggle_menu,
|
||||
#endif
|
||||
compass_point_north_menu,
|
||||
reset_node_db_menu
|
||||
reset_node_db_menu,
|
||||
buzzermodemenupicker,
|
||||
mui_picker,
|
||||
tftcolormenupicker,
|
||||
brightness_picker,
|
||||
reboot_menu,
|
||||
shutdown_menu,
|
||||
add_favorite,
|
||||
remove_favorite,
|
||||
test_menu,
|
||||
number_test,
|
||||
wifi_toggle_menu,
|
||||
bluetooth_toggle_menu,
|
||||
notifications_menu,
|
||||
screen_options_menu,
|
||||
power_menu,
|
||||
system_base_menu,
|
||||
key_verification_init,
|
||||
key_verification_final_prompt,
|
||||
trace_route_menu,
|
||||
throttle_message,
|
||||
};
|
||||
static screenMenus menuQueue;
|
||||
|
||||
static void LoraRegionPicker(uint32_t duration = 30000);
|
||||
static void handleMenuSwitch();
|
||||
static void handleMenuSwitch(OLEDDisplay *display);
|
||||
static void clockMenu();
|
||||
static void TZPicker();
|
||||
static void TwelveHourPicker();
|
||||
static void ClockFacePicker();
|
||||
static void messageResponseMenu();
|
||||
static void homeBaseMenu();
|
||||
static void textMessageBaseMenu();
|
||||
static void systemBaseMenu();
|
||||
static void favoriteBaseMenu();
|
||||
static void positionBaseMenu();
|
||||
static void compassNorthMenu();
|
||||
static void GPSToggleMenu();
|
||||
static void BuzzerModeMenu();
|
||||
static void switchToMUIMenu();
|
||||
static void TFTColorPickerMenu(OLEDDisplay *display);
|
||||
static void nodeListMenu();
|
||||
static void resetNodeDBMenu();
|
||||
static void BrightnessPickerMenu();
|
||||
static void rebootMenu();
|
||||
static void shutdownMenu();
|
||||
static void addFavoriteMenu();
|
||||
static void removeFavoriteMenu();
|
||||
static void traceRouteMenu();
|
||||
static void testMenu();
|
||||
static void numberTest();
|
||||
static void wifiBaseMenu();
|
||||
static void wifiToggleMenu();
|
||||
static void notificationsMenu();
|
||||
static void screenOptionsMenu();
|
||||
static void powerMenu();
|
||||
|
||||
private:
|
||||
static void saveUIConfig();
|
||||
static void keyVerificationInitMenu();
|
||||
static void keyVerificationFinalPrompt();
|
||||
static void BluetoothToggleMenu();
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -66,10 +66,10 @@ const char *getSafeNodeName(meshtastic_NodeInfoLite *node)
|
||||
strncpy(nodeName, name, sizeof(nodeName) - 1);
|
||||
nodeName[sizeof(nodeName) - 1] = '\0';
|
||||
} else {
|
||||
snprintf(nodeName, sizeof(nodeName), "%04X", (uint16_t)(node->num & 0xFFFF));
|
||||
snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF));
|
||||
}
|
||||
} else {
|
||||
strcpy(nodeName, "?");
|
||||
snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF));
|
||||
}
|
||||
return nodeName;
|
||||
}
|
||||
@@ -522,7 +522,7 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
double lat = DegD(ourNode->position.latitude_i);
|
||||
double lon = DegD(ourNode->position.longitude_i);
|
||||
|
||||
if (!screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
#if HAS_GPS
|
||||
if (screen->hasHeading()) {
|
||||
heading = screen->getHeading(); // degrees
|
||||
|
||||
@@ -26,14 +26,27 @@ extern bool hasUnreadMessage;
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
char NotificationRenderer::inEvent = INPUT_BROKER_NONE;
|
||||
InputEvent NotificationRenderer::inEvent;
|
||||
int8_t NotificationRenderer::curSelected = 0;
|
||||
char NotificationRenderer::alertBannerMessage[256] = {0};
|
||||
uint32_t NotificationRenderer::alertBannerUntil = 0; // 0 is a special case meaning forever
|
||||
uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are seelctable options
|
||||
const char **NotificationRenderer::optionsArrayPtr = nullptr;
|
||||
const int *NotificationRenderer::optionsEnumPtr = nullptr;
|
||||
std::function<void(int)> NotificationRenderer::alertBannerCallback = NULL;
|
||||
bool NotificationRenderer::pauseBanner = false;
|
||||
notificationTypeEnum NotificationRenderer::current_notification_type = notificationTypeEnum::none;
|
||||
uint32_t NotificationRenderer::numDigits = 0;
|
||||
uint32_t NotificationRenderer::currentNumber = 0;
|
||||
|
||||
uint32_t pow_of_10(uint32_t n)
|
||||
{
|
||||
uint32_t ret = 1;
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
ret *= 10;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Used on boot when a certificate is being created
|
||||
void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@@ -55,29 +68,242 @@ void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
void NotificationRenderer::resetBanner()
|
||||
{
|
||||
alertBannerMessage[0] = '\0';
|
||||
current_notification_type = notificationTypeEnum::none;
|
||||
|
||||
inEvent.inputEvent = INPUT_BROKER_NONE;
|
||||
inEvent.kbchar = 0;
|
||||
curSelected = 0;
|
||||
alertBannerOptions = 0; // last x lines are seelctable options
|
||||
optionsArrayPtr = nullptr;
|
||||
optionsEnumPtr = nullptr;
|
||||
alertBannerCallback = NULL;
|
||||
pauseBanner = false;
|
||||
numDigits = 0;
|
||||
currentNumber = 0;
|
||||
|
||||
nodeDB->pause_sort(false);
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
if (!isOverlayBannerShowing() && alertBannerMessage[0] != '\0')
|
||||
resetBanner();
|
||||
if (!isOverlayBannerShowing() || pauseBanner)
|
||||
return;
|
||||
switch (current_notification_type) {
|
||||
case notificationTypeEnum::none:
|
||||
// Do nothing - no notification to display
|
||||
break;
|
||||
case notificationTypeEnum::text_banner:
|
||||
case notificationTypeEnum::selection_picker:
|
||||
drawAlertBannerOverlay(display, state);
|
||||
break;
|
||||
case notificationTypeEnum::node_picker:
|
||||
drawNodePicker(display, state);
|
||||
break;
|
||||
case notificationTypeEnum::number_picker:
|
||||
drawNumberPicker(display, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
const char *lineStarts[MAX_LINES + 1] = {0};
|
||||
uint16_t lineCount = 0;
|
||||
|
||||
// Parse lines
|
||||
char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage));
|
||||
lineStarts[lineCount] = alertBannerMessage;
|
||||
|
||||
// Find lines
|
||||
while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) {
|
||||
lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n');
|
||||
if (lineStarts[lineCount + 1][0] == '\n')
|
||||
lineStarts[lineCount + 1] += 1;
|
||||
lineCount++;
|
||||
}
|
||||
// modulo to extract
|
||||
uint8_t this_digit = (currentNumber % (pow_of_10(numDigits - curSelected))) / (pow_of_10(numDigits - curSelected - 1));
|
||||
// Handle input
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
if (this_digit == 9) {
|
||||
currentNumber -= 9 * (pow_of_10(numDigits - curSelected - 1));
|
||||
} else {
|
||||
currentNumber += (pow_of_10(numDigits - curSelected - 1));
|
||||
}
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
if (this_digit == 0) {
|
||||
currentNumber += 9 * (pow_of_10(numDigits - curSelected - 1));
|
||||
} else {
|
||||
currentNumber -= (pow_of_10(numDigits - curSelected - 1));
|
||||
}
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_ANYKEY) {
|
||||
if (inEvent.kbchar > 47 && inEvent.kbchar < 58) { // have a digit
|
||||
currentNumber -= this_digit * (pow_of_10(numDigits - curSelected - 1));
|
||||
currentNumber += (inEvent.kbchar - 48) * (pow_of_10(numDigits - curSelected - 1));
|
||||
curSelected++;
|
||||
}
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT || inEvent.inputEvent == INPUT_BROKER_RIGHT) {
|
||||
curSelected++;
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_LEFT) {
|
||||
curSelected--;
|
||||
} else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) &&
|
||||
alertBannerUntil != 0) {
|
||||
resetBanner();
|
||||
return;
|
||||
}
|
||||
if (curSelected == static_cast<int8_t>(numDigits)) {
|
||||
alertBannerCallback(currentNumber);
|
||||
resetBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
inEvent.inputEvent = INPUT_BROKER_NONE;
|
||||
if (alertBannerMessage[0] == '\0')
|
||||
return;
|
||||
|
||||
uint16_t totalLines = lineCount + 2;
|
||||
const char *linePointers[totalLines + 1] = {0}; // this is sort of a dynamic allocation
|
||||
|
||||
// copy the linestarts to display to the linePointers holder
|
||||
for (uint16_t i = 0; i < lineCount; i++) {
|
||||
linePointers[i] = lineStarts[i];
|
||||
}
|
||||
std::string digits = " ";
|
||||
std::string arrowPointer = " ";
|
||||
for (uint16_t i = 0; i < numDigits; i++) {
|
||||
// Modulo minus modulo to return just the current number
|
||||
digits += std::to_string((currentNumber % (pow_of_10(numDigits - i))) / (pow_of_10(numDigits - i - 1))) + " ";
|
||||
if (curSelected == i) {
|
||||
arrowPointer += "^ ";
|
||||
} else {
|
||||
arrowPointer += "_ ";
|
||||
}
|
||||
}
|
||||
|
||||
linePointers[lineCount++] = digits.c_str();
|
||||
linePointers[lineCount++] = arrowPointer.c_str();
|
||||
|
||||
drawNotificationBox(display, state, linePointers, totalLines, 0);
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawNodePicker(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
static uint32_t selectedNodenum = 0;
|
||||
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t hPadding = 5;
|
||||
constexpr uint16_t vPadding = 2;
|
||||
constexpr uint8_t lineSpacing = 1;
|
||||
alertBannerOptions = nodeDB->getNumMeshNodes() - 1;
|
||||
|
||||
bool needs_bell = (strstr(alertBannerMessage, "Alert Received") != nullptr);
|
||||
// let the box drawing function calculate the widths?
|
||||
|
||||
// Setup font and alignment
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
const char *lineStarts[MAX_LINES + 1] = {0};
|
||||
uint16_t lineCount = 0;
|
||||
|
||||
// Parse lines
|
||||
char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage));
|
||||
lineStarts[lineCount] = alertBannerMessage;
|
||||
|
||||
while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) {
|
||||
lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n');
|
||||
if (lineStarts[lineCount + 1][0] == '\n')
|
||||
lineStarts[lineCount + 1] += 1;
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
// Handle input
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
curSelected--;
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
curSelected++;
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||
alertBannerCallback(selectedNodenum);
|
||||
resetBanner();
|
||||
return;
|
||||
} else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) &&
|
||||
alertBannerUntil != 0) {
|
||||
resetBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
if (curSelected == -1)
|
||||
curSelected = alertBannerOptions - 1;
|
||||
if (curSelected == alertBannerOptions)
|
||||
curSelected = 0;
|
||||
|
||||
inEvent.inputEvent = INPUT_BROKER_NONE;
|
||||
if (alertBannerMessage[0] == '\0')
|
||||
return;
|
||||
|
||||
uint16_t totalLines = lineCount + alertBannerOptions;
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint8_t linesShown = lineCount;
|
||||
const char *linePointers[visibleTotalLines + 1] = {0}; // this is sort of a dynamic allocation
|
||||
|
||||
// copy the linestarts to display to the linePointers holder
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
linePointers[i] = lineStarts[i];
|
||||
}
|
||||
char scratchLineBuffer[visibleTotalLines - lineCount][40];
|
||||
|
||||
uint8_t firstOptionToShow = 0;
|
||||
if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount) {
|
||||
if (curSelected > alertBannerOptions - visibleTotalLines + lineCount)
|
||||
firstOptionToShow = alertBannerOptions - visibleTotalLines + lineCount;
|
||||
else
|
||||
firstOptionToShow = curSelected - 1;
|
||||
} else {
|
||||
firstOptionToShow = 0;
|
||||
}
|
||||
int scratchLineNum = 0;
|
||||
for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
char temp_name[16] = {0};
|
||||
if (nodeDB->getMeshNodeByIndex(i + 1)->has_user) {
|
||||
std::string sanitized = sanitizeString(nodeDB->getMeshNodeByIndex(i + 1)->user.long_name);
|
||||
strncpy(temp_name, sanitized.c_str(), sizeof(temp_name) - 1);
|
||||
|
||||
} else {
|
||||
snprintf(temp_name, sizeof(temp_name), "(%04X)", (uint16_t)(nodeDB->getMeshNodeByIndex(i + 1)->num & 0xFFFF));
|
||||
}
|
||||
// make temp buffer for name
|
||||
// fi
|
||||
if (i == curSelected) {
|
||||
selectedNodenum = nodeDB->getMeshNodeByIndex(i + 1)->num;
|
||||
if (isHighResolution) {
|
||||
strncpy(scratchLineBuffer[scratchLineNum], "> ", 3);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + 2, temp_name, 36);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + strlen(temp_name) + 2, " <", 3);
|
||||
} else {
|
||||
strncpy(scratchLineBuffer[scratchLineNum], ">", 2);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + 1, temp_name, 37);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + strlen(temp_name) + 1, "<", 2);
|
||||
}
|
||||
scratchLineBuffer[scratchLineNum][39] = '\0';
|
||||
} else {
|
||||
strncpy(scratchLineBuffer[scratchLineNum], temp_name, 36);
|
||||
}
|
||||
linePointers[linesShown] = scratchLineBuffer[scratchLineNum++];
|
||||
}
|
||||
drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow);
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t vPadding = 2;
|
||||
|
||||
constexpr int MAX_LINES = 5;
|
||||
uint16_t optionWidths[alertBannerOptions] = {0};
|
||||
uint16_t maxWidth = 0;
|
||||
uint16_t arrowsWidth = display->getStringWidth("> <", 4, true);
|
||||
uint16_t lineWidths[MAX_LINES] = {0};
|
||||
uint16_t lineLengths[MAX_LINES] = {0};
|
||||
char *lineStarts[MAX_LINES + 1];
|
||||
const char *lineStarts[MAX_LINES + 1] = {0};
|
||||
uint16_t lineCount = 0;
|
||||
char lineBuffer[40] = {0};
|
||||
|
||||
@@ -86,7 +312,7 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
lineStarts[lineCount] = alertBannerMessage;
|
||||
|
||||
while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) {
|
||||
lineStarts[lineCount + 1] = std::find(lineStarts[lineCount], alertEnd, '\n');
|
||||
lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n');
|
||||
lineLengths[lineCount] = lineStarts[lineCount + 1] - lineStarts[lineCount];
|
||||
if (lineStarts[lineCount + 1][0] == '\n')
|
||||
lineStarts[lineCount + 1] += 1;
|
||||
@@ -107,15 +333,23 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
|
||||
// Handle input
|
||||
if (alertBannerOptions > 0) {
|
||||
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
curSelected--;
|
||||
} else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) {
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
curSelected++;
|
||||
} else if (inEvent == INPUT_BROKER_SELECT) {
|
||||
alertBannerCallback(curSelected);
|
||||
alertBannerMessage[0] = '\0';
|
||||
} else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) {
|
||||
alertBannerMessage[0] = '\0';
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||
if (optionsEnumPtr != nullptr) {
|
||||
alertBannerCallback(optionsEnumPtr[curSelected]);
|
||||
optionsEnumPtr = nullptr;
|
||||
} else {
|
||||
alertBannerCallback(curSelected);
|
||||
}
|
||||
resetBanner();
|
||||
return;
|
||||
} else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) &&
|
||||
alertBannerUntil != 0) {
|
||||
resetBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
if (curSelected == -1)
|
||||
@@ -123,16 +357,102 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
if (curSelected == alertBannerOptions)
|
||||
curSelected = 0;
|
||||
} else {
|
||||
if (inEvent == INPUT_BROKER_SELECT || inEvent == INPUT_BROKER_ALT_LONG || inEvent == INPUT_BROKER_CANCEL) {
|
||||
alertBannerMessage[0] = '\0';
|
||||
if (inEvent.inputEvent == INPUT_BROKER_SELECT || inEvent.inputEvent == INPUT_BROKER_ALT_LONG ||
|
||||
inEvent.inputEvent == INPUT_BROKER_CANCEL) {
|
||||
resetBanner();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inEvent = INPUT_BROKER_NONE;
|
||||
inEvent.inputEvent = INPUT_BROKER_NONE;
|
||||
if (alertBannerMessage[0] == '\0')
|
||||
return;
|
||||
|
||||
// === Box Size Calculation ===
|
||||
uint16_t totalLines = lineCount + alertBannerOptions;
|
||||
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint8_t linesShown = lineCount;
|
||||
const char *linePointers[visibleTotalLines + 1] = {0}; // this is sort of a dynamic allocation
|
||||
|
||||
// copy the linestarts to display to the linePointers holder
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
linePointers[i] = lineStarts[i];
|
||||
}
|
||||
|
||||
uint8_t firstOptionToShow = 0;
|
||||
if (alertBannerOptions > 0) {
|
||||
if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount) {
|
||||
if (curSelected > alertBannerOptions - visibleTotalLines + lineCount)
|
||||
firstOptionToShow = alertBannerOptions - visibleTotalLines + lineCount;
|
||||
else
|
||||
firstOptionToShow = curSelected - 1;
|
||||
} else {
|
||||
firstOptionToShow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
if (i == curSelected) {
|
||||
if (isHighResolution) {
|
||||
strncpy(lineBuffer, "> ", 3);
|
||||
strncpy(lineBuffer + 2, optionsArrayPtr[i], 36);
|
||||
strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 2, " <", 3);
|
||||
} else {
|
||||
strncpy(lineBuffer, ">", 2);
|
||||
strncpy(lineBuffer + 1, optionsArrayPtr[i], 37);
|
||||
strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 1, "<", 2);
|
||||
}
|
||||
lineBuffer[39] = '\0';
|
||||
linePointers[linesShown] = lineBuffer;
|
||||
} else {
|
||||
linePointers[linesShown] = optionsArrayPtr[i];
|
||||
}
|
||||
}
|
||||
if (alertBannerOptions > 0) {
|
||||
drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow, maxWidth);
|
||||
} else {
|
||||
drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[],
|
||||
uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth)
|
||||
{
|
||||
|
||||
bool is_picker = false;
|
||||
uint16_t lineCount = 0;
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t hPadding = 5;
|
||||
constexpr uint16_t vPadding = 2;
|
||||
bool needs_bell = false;
|
||||
uint16_t lineWidths[totalLines] = {0};
|
||||
uint16_t lineLengths[totalLines] = {0};
|
||||
|
||||
if (maxWidth != 0)
|
||||
is_picker = true;
|
||||
|
||||
// Setup font and alignment
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
while (lines[lineCount] != nullptr) {
|
||||
auto newlinePointer = strchr(lines[lineCount], '\n');
|
||||
if (newlinePointer)
|
||||
lineLengths[lineCount] = (newlinePointer - lines[lineCount]); // Check for newlines first
|
||||
else // if the newline wasn't found, then pull string length from strlen
|
||||
lineLengths[lineCount] = strlen(lines[lineCount]);
|
||||
lineWidths[lineCount] = display->getStringWidth(lines[lineCount], lineLengths[lineCount], true);
|
||||
if (!is_picker) {
|
||||
needs_bell |= (strstr(alertBannerMessage, "Alert Received") != nullptr);
|
||||
if (lineWidths[lineCount] > maxWidth)
|
||||
maxWidth = lineWidths[lineCount];
|
||||
}
|
||||
lineCount++;
|
||||
}
|
||||
// count lines
|
||||
|
||||
uint16_t boxWidth = hPadding * 2 + maxWidth;
|
||||
if (needs_bell) {
|
||||
if (isHighResolution && boxWidth <= 150)
|
||||
@@ -141,14 +461,19 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
boxWidth += 20;
|
||||
}
|
||||
|
||||
uint16_t totalLines = lineCount + alertBannerOptions;
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(lineCount, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint16_t contentHeight = visibleTotalLines * effectiveLineHeight;
|
||||
uint16_t boxHeight = contentHeight + vPadding * 2;
|
||||
if (visibleTotalLines == 1) {
|
||||
boxHeight += (isHighResolution) ? 4 : 3;
|
||||
}
|
||||
|
||||
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
|
||||
if (totalLines > visibleTotalLines) {
|
||||
boxWidth += (isHighResolution) ? 4 : 2;
|
||||
}
|
||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
||||
|
||||
// === Draw Box ===
|
||||
@@ -169,21 +494,18 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
|
||||
// === Draw Content ===
|
||||
int16_t lineY = boxTop + vPadding;
|
||||
uint8_t linesShown = 0;
|
||||
|
||||
for (int i = 0; i < lineCount && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
strncpy(lineBuffer, lineStarts[i], 40);
|
||||
lineBuffer[lineLengths[i] > 39 ? 39 : lineLengths[i]] = '\0';
|
||||
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
|
||||
if (needs_bell && i == 0) {
|
||||
int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2;
|
||||
display->drawXbm(textX - 10, bellY, 8, 8, bell_alert);
|
||||
display->drawXbm(textX + lineWidths[i] + 2, bellY, 8, 8, bell_alert);
|
||||
}
|
||||
|
||||
char lineBuffer[lineLengths[i] + 1];
|
||||
strncpy(lineBuffer, lines[i], lineLengths[i]);
|
||||
lineBuffer[lineLengths[i]] = '\0';
|
||||
// Determine if this is a pop-up or a pick list
|
||||
if (alertBannerOptions > 0) {
|
||||
if (alertBannerOptions > 0 && i == 0) {
|
||||
// Pick List
|
||||
display->setColor(WHITE);
|
||||
int background_yOffset = 1;
|
||||
@@ -199,39 +521,14 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
lineY += (effectiveLineHeight - 2 - background_yOffset);
|
||||
} else {
|
||||
// Pop-up
|
||||
display->drawString(textX, lineY - 2, lineBuffer);
|
||||
display->drawString(textX, lineY, lineBuffer);
|
||||
lineY += (effectiveLineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t firstOptionToShow = 0;
|
||||
if (alertBannerOptions > 0) {
|
||||
if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount)
|
||||
firstOptionToShow = curSelected - 1;
|
||||
else
|
||||
firstOptionToShow = 0;
|
||||
}
|
||||
|
||||
for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
if (i == curSelected) {
|
||||
strncpy(lineBuffer, "> ", 3);
|
||||
strncpy(lineBuffer + 2, optionsArrayPtr[i], 36);
|
||||
strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 2, " <", 3);
|
||||
lineBuffer[39] = '\0';
|
||||
} else {
|
||||
strncpy(lineBuffer, optionsArrayPtr[i], 40);
|
||||
lineBuffer[39] = '\0';
|
||||
}
|
||||
|
||||
int16_t textX = boxLeft + (boxWidth - optionWidths[i] - (i == curSelected ? arrowsWidth : 0)) / 2;
|
||||
display->drawString(textX, lineY, lineBuffer);
|
||||
lineY += effectiveLineHeight;
|
||||
}
|
||||
|
||||
// === Scroll Bar (Thicker, inside box, not over title) ===
|
||||
if (totalLines > visibleTotalLines) {
|
||||
const uint8_t scrollBarWidth = 5;
|
||||
const uint8_t scrollPadding = 2;
|
||||
|
||||
int16_t scrollBarX = boxLeft + boxWidth - scrollBarWidth - 2;
|
||||
int16_t scrollBarY = boxTop + vPadding + effectiveLineHeight; // start after title line
|
||||
@@ -239,7 +536,7 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
|
||||
float ratio = (float)visibleTotalLines / totalLines;
|
||||
uint16_t indicatorHeight = std::max((int)(scrollBarHeight * ratio), 4);
|
||||
float scrollRatio = (float)(firstOptionToShow + linesShown - visibleTotalLines) / (totalLines - visibleTotalLines);
|
||||
float scrollRatio = (float)(firstOptionToShow + lineCount - visibleTotalLines) / (totalLines - visibleTotalLines);
|
||||
uint16_t indicatorY = scrollBarY + scrollRatio * (scrollBarHeight - indicatorHeight);
|
||||
|
||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "OLEDDisplay.h"
|
||||
#include "OLEDDisplayUi.h"
|
||||
#include "graphics/Screen.h"
|
||||
#define MAX_LINES 5
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
@@ -9,21 +11,34 @@ namespace graphics
|
||||
class NotificationRenderer
|
||||
{
|
||||
public:
|
||||
static char inEvent;
|
||||
static InputEvent inEvent;
|
||||
static char inKeypress;
|
||||
static int8_t curSelected;
|
||||
static char alertBannerMessage[256];
|
||||
static uint32_t alertBannerUntil; // 0 is a special case meaning forever
|
||||
static const char **optionsArrayPtr;
|
||||
static const int *optionsEnumPtr;
|
||||
static uint8_t alertBannerOptions; // last x lines are seelctable options
|
||||
static std::function<void(int)> alertBannerCallback;
|
||||
static uint32_t numDigits;
|
||||
static uint32_t currentNumber;
|
||||
|
||||
static bool pauseBanner;
|
||||
|
||||
static void resetBanner();
|
||||
static void drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawNodePicker(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[MAX_LINES + 1],
|
||||
uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth = 0);
|
||||
|
||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static bool isOverlayBannerShowing();
|
||||
|
||||
static graphics::notificationTypeEnum current_notification_type;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -18,38 +18,29 @@
|
||||
#include <RTC.h>
|
||||
#include <cstring>
|
||||
|
||||
bool isAllowedPunctuation(char c)
|
||||
{
|
||||
const std::string allowed = ".,!?;:-_()[]{}'\"@#$/\\&+=%~^ ";
|
||||
return allowed.find(c) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string sanitizeString(const std::string &input)
|
||||
{
|
||||
std::string output;
|
||||
bool inReplacement = false;
|
||||
|
||||
for (char c : input) {
|
||||
if (std::isalnum(static_cast<unsigned char>(c)) || isAllowedPunctuation(c)) {
|
||||
output += c;
|
||||
inReplacement = false;
|
||||
} else {
|
||||
if (!inReplacement) {
|
||||
output += 0xbf; // ISO-8859-1 for inverted question mark
|
||||
inReplacement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// External variables
|
||||
extern graphics::Screen *screen;
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
NodeNum UIRenderer::currentFavoriteNodeNum = 0;
|
||||
std::vector<meshtastic_NodeInfoLite *> graphics::UIRenderer::favoritedNodes;
|
||||
|
||||
void graphics::UIRenderer::rebuildFavoritedNodes()
|
||||
{
|
||||
favoritedNodes.clear();
|
||||
size_t total = nodeDB->getNumMeshNodes();
|
||||
for (size_t i = 0; i < total; i++) {
|
||||
meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||
if (!n || n->num == nodeDB->getNodeNum())
|
||||
continue;
|
||||
if (n->is_favorite)
|
||||
favoritedNodes.push_back(n);
|
||||
}
|
||||
|
||||
std::sort(favoritedNodes.begin(), favoritedNodes.end(),
|
||||
[](const meshtastic_NodeInfoLite *a, const meshtastic_NodeInfoLite *b) { return a->num < b->num; });
|
||||
}
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
// GeoCoord object for coordinate conversions
|
||||
@@ -227,27 +218,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
||||
// **********************
|
||||
void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// --- Cache favorite nodes for the current frame only, to save computation ---
|
||||
static std::vector<meshtastic_NodeInfoLite *> favoritedNodes;
|
||||
static int prevFrame = -1;
|
||||
|
||||
// --- Only rebuild favorites list if we're on a new frame ---
|
||||
if (state->currentFrame != prevFrame) {
|
||||
prevFrame = state->currentFrame;
|
||||
favoritedNodes.clear();
|
||||
size_t total = nodeDB->getNumMeshNodes();
|
||||
for (size_t i = 0; i < total; i++) {
|
||||
meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||
// Skip nulls and ourself
|
||||
if (!n || n->num == nodeDB->getNodeNum())
|
||||
continue;
|
||||
if (n->is_favorite)
|
||||
favoritedNodes.push_back(n);
|
||||
}
|
||||
// Keep a stable, consistent display order
|
||||
std::sort(favoritedNodes.begin(), favoritedNodes.end(),
|
||||
[](const meshtastic_NodeInfoLite *a, const meshtastic_NodeInfoLite *b) { return a->num < b->num; });
|
||||
}
|
||||
if (favoritedNodes.empty())
|
||||
return;
|
||||
|
||||
@@ -443,7 +414,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
*/
|
||||
float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
if (screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
myHeading = 0;
|
||||
} else {
|
||||
bearing -= myHeading;
|
||||
@@ -488,7 +459,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
|
||||
const auto &op = ourNode->position;
|
||||
float myHeading = 0;
|
||||
if (!screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180
|
||||
: screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
}
|
||||
@@ -500,7 +471,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
*/
|
||||
float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
if (!screen->ignoreCompass)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING)
|
||||
bearing -= myHeading;
|
||||
graphics::CompassRenderer::drawNodeHeading(display, compassX, compassY, compassRadius * 2, bearing);
|
||||
|
||||
@@ -600,7 +571,11 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
|
||||
int chutil_bar_width = (isHighResolution) ? 100 : 50;
|
||||
if (!config.bluetooth.enabled) {
|
||||
#if defined(USE_EINK)
|
||||
chutil_bar_width = (isHighResolution) ? 50 : 30;
|
||||
#else
|
||||
chutil_bar_width = (isHighResolution) ? 80 : 40;
|
||||
#endif
|
||||
}
|
||||
int chutil_bar_height = (isHighResolution) ? 12 : 7;
|
||||
int extraoffset = (isHighResolution) ? 6 : 3;
|
||||
@@ -679,7 +654,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
|
||||
char combinedName[50];
|
||||
snprintf(combinedName, sizeof(combinedName), "%s (%s)", longNameStr.empty() ? "" : longNameStr.c_str(), shortnameble);
|
||||
if (SCREEN_WIDTH - (display->getStringWidth(longName) + display->getStringWidth(shortnameble)) > 10) {
|
||||
if (SCREEN_WIDTH - (display->getStringWidth(combinedName)) > 10) {
|
||||
size_t len = strlen(combinedName);
|
||||
if (len >= 3 && strcmp(combinedName + len - 3, " ()") == 0) {
|
||||
combinedName[len - 3] = '\0'; // Remove the last three characters
|
||||
@@ -690,7 +665,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
nameX, ((rows == 4) ? getTextPositions(display)[line++] : getTextPositions(display)[line++]) + yOffset, combinedName);
|
||||
} else {
|
||||
// === LongName Centered ===
|
||||
textWidth = display->getStringWidth(longName);
|
||||
textWidth = display->getStringWidth(longNameStr.c_str());
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], longNameStr.c_str());
|
||||
|
||||
@@ -933,7 +908,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
// === Determine Compass Heading ===
|
||||
float heading = 0;
|
||||
bool validHeading = false;
|
||||
if (screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
validHeading = true;
|
||||
} else {
|
||||
if (screen->hasHeading()) {
|
||||
@@ -999,7 +974,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
|
||||
// "N" label
|
||||
float northAngle = 0;
|
||||
if (!config.display.compass_north_top)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING)
|
||||
northAngle = -heading;
|
||||
float radius = compassRadius;
|
||||
int16_t nX = compassX + (radius - 1) * sin(northAngle);
|
||||
@@ -1042,7 +1017,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
|
||||
// "N" label
|
||||
float northAngle = 0;
|
||||
if (!config.display.compass_north_top)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING)
|
||||
northAngle = -heading;
|
||||
float radius = compassRadius;
|
||||
int16_t nX = compassX + (radius - 1) * sin(northAngle);
|
||||
@@ -1066,9 +1041,16 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
void UIRenderer::drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
static const uint8_t xbm[] = USERPREFS_OEM_IMAGE_DATA;
|
||||
display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2,
|
||||
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH,
|
||||
USERPREFS_OEM_IMAGE_HEIGHT, xbm);
|
||||
if (isHighResolution) {
|
||||
display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2,
|
||||
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH,
|
||||
USERPREFS_OEM_IMAGE_HEIGHT, xbm);
|
||||
} else {
|
||||
|
||||
display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2,
|
||||
y + (SCREEN_HEIGHT - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH,
|
||||
USERPREFS_OEM_IMAGE_HEIGHT, xbm);
|
||||
}
|
||||
|
||||
switch (USERPREFS_OEM_FONT_SIZE) {
|
||||
case 0:
|
||||
@@ -1084,7 +1066,9 @@ void UIRenderer::drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, O
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
const char *title = USERPREFS_OEM_TEXT;
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
if (isHighResolution) {
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
}
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
// Draw region in upper left
|
||||
|
||||
@@ -61,6 +61,8 @@ class UIRenderer
|
||||
static void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
static NodeNum currentFavoriteNodeNum;
|
||||
static std::vector<meshtastic_NodeInfoLite *> favoritedNodes;
|
||||
static void rebuildFavoritedNodes();
|
||||
|
||||
// OEM screens
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
|
||||
+103
-51
@@ -11,11 +11,11 @@ const Emote emotes[] = {
|
||||
{"\U0001F44E", thumbdown, thumbs_width, thumbs_height}, // 👎 Thumbs Down
|
||||
|
||||
// --- Smileys (Multiple Unicode Aliases) ---
|
||||
{"\U0001F60A", smiley, smiley_width, smiley_height}, // 😊 Smiling Face with Smiling Eyes
|
||||
{"\U0001F600", smiley, smiley_width, smiley_height}, // 😀 Grinning Face
|
||||
{"\U0001F642", smiley, smiley_width, smiley_height}, // 🙂 Slightly Smiling Face
|
||||
{"\U0001F609", smiley, smiley_width, smiley_height}, // 😉 Winking Face
|
||||
{"\U0001F601", smiley, smiley_width, smiley_height}, // 😁 Grinning Face with Smiling Eyes
|
||||
{"\U0001F60A", Smiling_Eyes, Smiling_Eyes_width, Smiling_Eyes_height}, // 😊 Smiling Eyes
|
||||
{"\U0001F600", Grinning, Grinning_width, Grinning_height}, // 😀 Grinning Face
|
||||
{"\U0001F642", Slightly_Smiling, Slightly_Smiling_width, Slightly_Smiling_height}, // 🙂 Slightly Smiling 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
|
||||
|
||||
// --- Question/Alert ---
|
||||
{"\u2753", question, question_width, question_height}, // ❓ Question Mark
|
||||
@@ -23,10 +23,11 @@ const Emote emotes[] = {
|
||||
|
||||
// --- Laughing Faces ---
|
||||
{"\U0001F602", haha, haha_width, haha_height}, // 😂 Face with Tears of Joy
|
||||
{"\U0001F923", haha, haha_width, haha_height}, // 🤣 Rolling on the Floor Laughing
|
||||
{"\U0001F606", haha, haha_width, haha_height}, // 😆 Smiling with Open Mouth and Closed Eyes
|
||||
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
||||
{"\U0001F604", haha, haha_width, haha_height}, // 😄 Grinning Face with Smiling Eyes
|
||||
{"\U0001F923", ROFL, ROFL_width, ROFL_height}, // 🤣 Rolling on the Floor Laughing
|
||||
{"\U0001F606", Smiling_Closed_Eyes, Smiling_Closed_Eyes_width, Smiling_Closed_Eyes_height}, // 😆 Smiling Closed Eyes
|
||||
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
||||
{"\U0001F604", Grinning_SmilingEyes2, Grinning_SmilingEyes2_width,
|
||||
Grinning_SmilingEyes2_height}, // 😄 Grinning Face with Smiling Eyes
|
||||
|
||||
// --- Gestures and People ---
|
||||
{"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand
|
||||
@@ -78,13 +79,45 @@ const unsigned char thumbdown[] PROGMEM = {
|
||||
0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char smiley[] PROGMEM = {
|
||||
0x00, 0xfe, 0x0f, 0x00, 0x80, 0x01, 0x30, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02,
|
||||
0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x0e, 0x0e, 0x10, 0x02, 0x09, 0x12, 0x10,
|
||||
0x01, 0x09, 0x12, 0x20, 0x01, 0x0f, 0x1e, 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, 0x20, 0x81, 0x00, 0x20, 0x20,
|
||||
0x82, 0x00, 0x20, 0x10, 0x02, 0x01, 0x10, 0x10, 0x04, 0x02, 0x08, 0x08, 0x04, 0xfc, 0x07, 0x08, 0x08, 0x00, 0x00, 0x04,
|
||||
0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0xc0, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0xfe, 0x0f, 0x00};
|
||||
const unsigned char Smiling_Eyes[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf,
|
||||
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 = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
||||
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 = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
||||
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 = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xf0, 0xff, 0xc3, 0x78, 0xef, 0xc3, 0xc7, 0xb8, 0xdf, 0xbd, 0xcf, 0xfc, 0xf9, 0x7f, 0xcf, 0xfc, 0xf0, 0xff, 0xcf,
|
||||
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 = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf8, 0xe3, 0xcf, 0x7c, 0xf7, 0xdd, 0xcf,
|
||||
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 = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00,
|
||||
@@ -104,31 +137,52 @@ const unsigned char bang[] PROGMEM = {
|
||||
};
|
||||
|
||||
const unsigned char haha[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00,
|
||||
0x00, 0xFC, 0x0F, 0x00, 0x00, 0x1F, 0x3E, 0x00, 0x80, 0x03, 0x70, 0x00, 0xC0, 0x01, 0xE0, 0x00, 0xC0, 0x00, 0xC2, 0x00,
|
||||
0x60, 0x00, 0x03, 0x00, 0x60, 0x00, 0xC1, 0x1F, 0x60, 0x80, 0x8F, 0x31, 0x30, 0x0E, 0x80, 0x31, 0x30, 0x10, 0x30, 0x1F,
|
||||
0x30, 0x08, 0x58, 0x00, 0x30, 0x04, 0x6C, 0x03, 0x60, 0x00, 0xF3, 0x01, 0x60, 0xC0, 0xFC, 0x01, 0x80, 0x38, 0xBF, 0x01,
|
||||
0xE0, 0xC5, 0xDF, 0x00, 0xB0, 0xF9, 0xEF, 0x00, 0x30, 0xF1, 0x73, 0x00, 0xB0, 0x1D, 0x3E, 0x00, 0xF0, 0xFD, 0x0F, 0x00,
|
||||
0xE0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xf9, 0xf3, 0xc0,
|
||||
0xf0, 0xfe, 0xef, 0xc1, 0x38, 0xff, 0x9f, 0xc3, 0xd8, 0xff, 0x7f, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xcf,
|
||||
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 = {
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0x07, 0xc0, 0x00, 0xff, 0x1f, 0xc0, 0x80, 0xff, 0x7f, 0xc0, 0xc0, 0xff, 0xff, 0xc0,
|
||||
0xe0, 0x9f, 0xff, 0xc1, 0xf0, 0x9f, 0xff, 0xc0, 0xf8, 0x9f, 0x7f, 0xcb, 0xf8, 0x9f, 0xbf, 0xcb, 0xfc, 0x9f, 0xdf, 0xdb,
|
||||
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 = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0x7c, 0xfe, 0xcf, 0xcf, 0xfc, 0xfc, 0xe7, 0xcf,
|
||||
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 = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xff, 0xff, 0xc0,
|
||||
0xf0, 0xff, 0xff, 0xc1, 0xf8, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xc7,
|
||||
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 = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xC0, 0x00,
|
||||
0x00, 0x0C, 0x9C, 0x01, 0x80, 0x17, 0x20, 0x01, 0x80, 0x26, 0x46, 0x02, 0x80, 0x44, 0x88, 0x02, 0xC0, 0x89, 0x8A, 0x02,
|
||||
0x40, 0x93, 0x8B, 0x02, 0x40, 0x26, 0x13, 0x00, 0x80, 0x44, 0x16, 0x00, 0xC0, 0x89, 0x24, 0x00, 0x40, 0x93, 0x60, 0x00,
|
||||
0x40, 0x26, 0x40, 0x00, 0x80, 0x0C, 0x80, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x06, 0x80, 0x00,
|
||||
0x50, 0x0C, 0x80, 0x00, 0x50, 0x08, 0x40, 0x00, 0x90, 0x10, 0x20, 0x00, 0xB0, 0x21, 0x10, 0x00, 0x20, 0x47, 0x18, 0x00,
|
||||
0x40, 0x80, 0x0F, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0xc0, 0xc1, 0x00, 0x00, 0x00, 0xc7,
|
||||
0x00, 0x00, 0x1e, 0xcc, 0x00, 0x00, 0x30, 0xc8, 0x00, 0x00, 0x60, 0xd8, 0x00, 0x08, 0xc0, 0xd0, 0x00, 0x1a, 0x81, 0xd1,
|
||||
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 = {
|
||||
0x00, 0xF0, 0x03, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x3C, 0xFE, 0x1F, 0x0F,
|
||||
0xFE, 0xFE, 0xDF, 0x1F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F,
|
||||
0x3E, 0xC0, 0x00, 0x1F, 0x1E, 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x0E, 0x1C, 0x04, 0x00, 0x0E, 0x1C, 0x00,
|
||||
0x04, 0x0E, 0x1C, 0x08, 0x04, 0x0E, 0x1C, 0x08, 0x04, 0x04, 0x08, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x08,
|
||||
0x8C, 0x07, 0x70, 0x0C, 0x88, 0xFC, 0x4F, 0x04, 0x88, 0x01, 0x40, 0x04, 0x90, 0xFF, 0x7F, 0x02, 0x30, 0x03, 0x30, 0x03,
|
||||
0x60, 0x0E, 0x9C, 0x01, 0xC0, 0xF8, 0xC7, 0x00, 0x80, 0x01, 0x60, 0x00, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0xF8, 0x07, 0x00,
|
||||
};
|
||||
0x00, 0x0c, 0x0c, 0xc0, 0x00, 0x02, 0x10, 0xc0, 0x00, 0x01, 0x20, 0xc0, 0xbc, 0x00, 0x40, 0xcf, 0xc2, 0x01, 0xe0, 0xd0,
|
||||
0x01, 0x01, 0x20, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
|
||||
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 = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00,
|
||||
@@ -181,13 +235,12 @@ const unsigned char fog[] PROGMEM = {
|
||||
};
|
||||
|
||||
const unsigned char devil[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x03, 0xC0, 0x01, 0x38, 0x07, 0x7C, 0x0F, 0x38, 0x1F, 0x03, 0x30, 0x1E,
|
||||
0xFE, 0x01, 0xE0, 0x1F, 0x7E, 0x00, 0x80, 0x1F, 0x3C, 0x00, 0x00, 0x0F, 0x1C, 0x00, 0x00, 0x0E, 0x18, 0x00, 0x00, 0x06,
|
||||
0x08, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x0E, 0x1C, 0x0C,
|
||||
0x0C, 0x18, 0x06, 0x0C, 0x0C, 0x1C, 0x06, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x0C, 0x06, 0x0C,
|
||||
0x08, 0x00, 0x00, 0x06, 0x18, 0x02, 0x10, 0x06, 0x10, 0x0C, 0x0C, 0x03, 0x30, 0xF8, 0x07, 0x03, 0x60, 0xE0, 0x80, 0x01,
|
||||
0xC0, 0x00, 0xC0, 0x00, 0x80, 0x01, 0x70, 0x00, 0x00, 0x06, 0x1C, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x0f, 0xfc, 0x0f, 0xfc,
|
||||
0x3f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfc, 0xff, 0xff, 0xcf,
|
||||
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 = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x1F, 0x06, 0x0E, 0xFE, 0x3F, 0x03, 0x18,
|
||||
@@ -199,13 +252,12 @@ const unsigned char heart[] PROGMEM = {
|
||||
};
|
||||
|
||||
const unsigned char poo[] PROGMEM = {
|
||||
0x00, 0x1C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xEC, 0x01, 0x00, 0x00, 0x8C, 0x07, 0x00, 0x00, 0x0C, 0x06, 0x00,
|
||||
0x00, 0x24, 0x0C, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x1F, 0x08, 0x00, 0xC0, 0x0F, 0x08, 0x00, 0xC0, 0x00, 0x3C, 0x00,
|
||||
0x60, 0x00, 0x7C, 0x00, 0x60, 0x00, 0xC6, 0x00, 0x20, 0x00, 0xCB, 0x00, 0xA0, 0xC7, 0xFF, 0x00, 0xE0, 0x7F, 0xF7, 0x00,
|
||||
0xF0, 0x18, 0xE3, 0x03, 0x78, 0x18, 0x41, 0x03, 0x6C, 0x9B, 0x5D, 0x06, 0x64, 0x9B, 0x5D, 0x04, 0x44, 0x1A, 0x41, 0x04,
|
||||
0x4C, 0xD8, 0x63, 0x06, 0xF8, 0xFC, 0x36, 0x06, 0xFE, 0x0F, 0x9C, 0x1F, 0x07, 0x03, 0xC0, 0x30, 0x03, 0x00, 0x78, 0x20,
|
||||
0x01, 0x00, 0x1F, 0x20, 0x03, 0xE0, 0x03, 0x20, 0x07, 0x7E, 0x04, 0x30, 0xFE, 0x0F, 0xFC, 0x1F, 0xF0, 0x00, 0xF0, 0x0F,
|
||||
};
|
||||
0x00, 0x1c, 0x00, 0xc0, 0x00, 0x7c, 0x00, 0xc0, 0x00, 0xfc, 0x00, 0xc0, 0x00, 0x7c, 0x03, 0xc0, 0x00, 0xbe, 0x03, 0xc0,
|
||||
0x00, 0xdf, 0x0f, 0xc0, 0x80, 0xcf, 0x0f, 0xc0, 0xc0, 0xf1, 0x0f, 0xc0, 0x60, 0xfc, 0x0f, 0xc0, 0x30, 0xff, 0x07, 0xc0,
|
||||
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 = {
|
||||
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11110000,
|
||||
|
||||
+31
-3
@@ -22,9 +22,25 @@ extern const int numEmotes;
|
||||
extern const unsigned char thumbup[] PROGMEM;
|
||||
extern const unsigned char thumbdown[] PROGMEM;
|
||||
|
||||
#define smiley_height 30
|
||||
#define smiley_width 30
|
||||
extern const unsigned char smiley[] PROGMEM;
|
||||
#define Smiling_Eyes_height 30
|
||||
#define Smiling_Eyes_width 30
|
||||
extern const unsigned char Smiling_Eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_height 30
|
||||
#define Grinning_width 30
|
||||
extern const unsigned char Grinning[] PROGMEM;
|
||||
|
||||
#define Slightly_Smiling_height 30
|
||||
#define Slightly_Smiling_width 30
|
||||
extern const unsigned char Slightly_Smiling[] PROGMEM;
|
||||
|
||||
#define Winking_Face_height 30
|
||||
#define Winking_Face_width 30
|
||||
extern const unsigned char Winking_Face[] PROGMEM;
|
||||
|
||||
#define Grinning_Smiling_Eyes_height 30
|
||||
#define Grinning_Smiling_Eyes_width 30
|
||||
extern const unsigned char Grinning_Smiling_Eyes[] PROGMEM;
|
||||
|
||||
#define question_height 25
|
||||
#define question_width 25
|
||||
@@ -38,6 +54,18 @@ extern const unsigned char bang[] PROGMEM;
|
||||
#define haha_width 30
|
||||
extern const unsigned char haha[] PROGMEM;
|
||||
|
||||
#define ROFL_height 30
|
||||
#define ROFL_width 30
|
||||
extern const unsigned char ROFL[] PROGMEM;
|
||||
|
||||
#define Smiling_Closed_Eyes_height 30
|
||||
#define Smiling_Closed_Eyes_width 30
|
||||
extern const unsigned char Smiling_Closed_Eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_SmilingEyes2_height 30
|
||||
#define Grinning_SmilingEyes2_width 30
|
||||
extern const unsigned char Grinning_SmilingEyes2[] PROGMEM;
|
||||
|
||||
#define wave_icon_height 30
|
||||
#define wave_icon_width 30
|
||||
extern const unsigned char wave_icon[] PROGMEM;
|
||||
|
||||
@@ -12,7 +12,10 @@ const uint8_t imgSatellite[] PROGMEM = {
|
||||
0b00000000, 0b00000000, 0b00000000, 0b00011000, 0b11011011, 0b11111111, 0b11011011, 0b00011000,
|
||||
};
|
||||
|
||||
const uint8_t imgUSB[] PROGMEM = {0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C};
|
||||
const uint8_t imgUSB[] PROGMEM = {0x00, 0xfc, 0xf0, 0xfc, 0x88, 0xff, 0x86, 0xfe, 0x85, 0xfe, 0x89, 0xff, 0xf1, 0xfc, 0x00, 0xfc};
|
||||
const uint8_t imgUSB_HighResolution[] PROGMEM = {0x00, 0x3e, 0xf8, 0x80, 0x43, 0xf8, 0xc0, 0xc2, 0xff, 0x60, 0x42, 0xfc,
|
||||
0x3c, 0xc2, 0xff, 0x22, 0x42, 0xf8, 0x3d, 0x42, 0xf8, 0x22, 0xc2, 0xff,
|
||||
0x61, 0x42, 0xfc, 0xc0, 0xc2, 0xff, 0x80, 0x43, 0xf8, 0x00, 0x3e, 0xf8};
|
||||
const uint8_t imgPower[] PROGMEM = {0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08,
|
||||
0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22};
|
||||
const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C};
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "./E0213A367.h"
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
using namespace NicheGraphics::Drivers;
|
||||
|
||||
// Map the display controller IC's output to the connected panel
|
||||
void E0213A367::configScanning()
|
||||
{
|
||||
// "Driver output control"
|
||||
// Scan gates from 0 to 249 (vertical resolution 250px)
|
||||
sendCommand(0x01);
|
||||
sendData(0xF9);
|
||||
sendData(0x00);
|
||||
}
|
||||
|
||||
// Specify which information is used to control the sequence of voltages applied to move the pixels
|
||||
void E0213A367::configWaveform()
|
||||
{
|
||||
// This command (0x37) is poorly documented
|
||||
// As of July 2025, the datasheet for this display's controller IC is unavailable
|
||||
// The values are supplied by Heltec, who presumably have privileged access to information from the display manufacturer
|
||||
// Datasheet for the similar SSD1680 IC hints at the function of this command:
|
||||
|
||||
// "Spare VCOM OTP selection":
|
||||
// Unclear why 0x40 is set. Sane values for related SSD1680 seem to be 0x80 or 0x00.
|
||||
// Maybe value is redundant? No noticeable impact when set to 0x00.
|
||||
// We'll leave it set to 0x40, following Heltec's lead, just in case.
|
||||
|
||||
// "Display Mode"
|
||||
// Seems to specify whether a waveform stored in OTP should use display mode 1 or 2 (full refresh or differential refresh)
|
||||
|
||||
// Unusual that waveforms are programmed to OTP, but this meta information is not ..?
|
||||
|
||||
sendCommand(0x37); // "Write Register for Display Option" ?
|
||||
sendData(0x40); // "Spare VCOM OTP selection" ?
|
||||
sendData(0x80); // "Display Mode for WS[7:0]" ?
|
||||
sendData(0x03); // "Display Mode for WS[15:8]" ?
|
||||
sendData(0x0E); // "Display Mode [23:16]" ?
|
||||
|
||||
switch (updateType) {
|
||||
case FAST:
|
||||
sendCommand(0x3C); // Border waveform:
|
||||
sendData(0x81); // As specified by Heltec. Actually VCOM (0x80)?. Bit 0 seems redundant here.
|
||||
break;
|
||||
case FULL:
|
||||
default:
|
||||
sendCommand(0x3C); // Border waveform:
|
||||
sendData(0x01); // Follow LUT 1 (blink same as white pixels)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell controller IC which operations to run
|
||||
void E0213A367::configUpdateSequence()
|
||||
{
|
||||
switch (updateType) {
|
||||
case FAST:
|
||||
sendCommand(0x22); // Set "update sequence"
|
||||
sendData(0xFF); // Will load LUT from OTP memory, Display mode 2 "differential refresh"
|
||||
break;
|
||||
case FULL:
|
||||
default:
|
||||
sendCommand(0x22); // Set "update sequence"
|
||||
sendData(0xF7); // Will load LUT from OTP memory, Display mode 1 "full refresh"
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Once the refresh operation has been started,
|
||||
// begin periodically polling the display to check for completion, using the normal Meshtastic threading code
|
||||
// Only used when refresh is "async"
|
||||
void E0213A367::detachFromUpdate()
|
||||
{
|
||||
switch (updateType) {
|
||||
case FAST:
|
||||
return beginPolling(50, 500); // At least 500ms for fast refresh
|
||||
case FULL:
|
||||
default:
|
||||
return beginPolling(100, 1500); // At least 1.5 seconds for full refresh
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
|
||||
E-Ink display driver
|
||||
- SSD1682
|
||||
- Manufacturer: SEEKINK
|
||||
- Size: 2.13 inch
|
||||
- Resolution: 122px x 255px
|
||||
- Flex connector marking: HINK-E0213A162-A1 (hidden, printed on reverse)
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include "./SSD1682.h"
|
||||
|
||||
namespace NicheGraphics::Drivers
|
||||
{
|
||||
class E0213A367 : public SSD1682
|
||||
{
|
||||
// Display properties
|
||||
private:
|
||||
static constexpr uint32_t width = 122;
|
||||
static constexpr uint32_t height = 250;
|
||||
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
|
||||
|
||||
public:
|
||||
E0213A367() : SSD1682(width, height, supported, 0) {}
|
||||
|
||||
protected:
|
||||
void configScanning() override;
|
||||
void configWaveform() override;
|
||||
void configUpdateSequence() override;
|
||||
void detachFromUpdate() override;
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "./SSD1682.h"
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
using namespace NicheGraphics::Drivers;
|
||||
|
||||
SSD1682::SSD1682(uint16_t width, uint16_t height, EInk::UpdateTypes supported, uint8_t bufferOffsetX)
|
||||
: SSD16XX(width, height, supported, bufferOffsetX)
|
||||
{
|
||||
}
|
||||
|
||||
// SSD1682 only accepts single-byte x and y values
|
||||
// This causes an incompatibility with the default SSD16XX::configFullscreen
|
||||
void SSD1682::configFullscreen()
|
||||
{
|
||||
// Define the boundaries of the "fullscreen" region, for the controller IC
|
||||
static const uint8_t sx = bufferOffsetX; // Notice the offset
|
||||
static const uint8_t sy = 0;
|
||||
static const uint8_t ex = bufferRowSize + bufferOffsetX - 1; // End is "max index", not "count". Minus 1 handles this
|
||||
static const uint8_t ey = height;
|
||||
|
||||
// Data entry mode - Left to Right, Top to Bottom
|
||||
sendCommand(0x11);
|
||||
sendData(0x03);
|
||||
|
||||
// Select controller IC memory region to display a fullscreen image
|
||||
sendCommand(0x44); // Memory X start - end
|
||||
sendData(sx);
|
||||
sendData(ex);
|
||||
sendCommand(0x45); // Memory Y start - end
|
||||
sendData(sy);
|
||||
sendData(ey);
|
||||
|
||||
// Place the cursor at the start of this memory region, ready to send image data x=0 y=0
|
||||
sendCommand(0x4E); // Memory cursor X
|
||||
sendData(sx);
|
||||
sendCommand(0x4F); // Memory cursor y
|
||||
sendData(sy);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
|
||||
E-Ink base class for displays based on SSD1682
|
||||
|
||||
SSD1682 has a few quirks. We're implementing them here in a new base class,
|
||||
to avoid re-implementing them every time we need to add a new SSD1682-based display.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include "./SSD16XX.h"
|
||||
|
||||
namespace NicheGraphics::Drivers
|
||||
{
|
||||
|
||||
class SSD1682 : public SSD16XX
|
||||
{
|
||||
public:
|
||||
SSD1682(uint16_t width, uint16_t height, EInk::UpdateTypes supported, uint8_t bufferOffsetX = 0);
|
||||
virtual void configFullscreen(); // Select memory region on controller IC
|
||||
virtual void deepSleep() {} // Not usable (image memory not retained)
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -0,0 +1,527 @@
|
||||
// trunk-ignore-all(clang-format)
|
||||
#pragma once
|
||||
/* PROPERTIES
|
||||
|
||||
FONT_NAME FreeSans12pt_Win1250
|
||||
*/
|
||||
const uint8_t FreeSans12pt_Win1250Bitmaps[] PROGMEM = {
|
||||
/* 0x01 */ 0x00, 0x30, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x24, 0x00, 0x04, 0x80, 0x01, 0x90, 0x00, 0x62, 0x00, 0x30, 0xFE, 0x04, 0x10, 0x5F, 0x02, 0x0B, 0x00, 0x7F, 0xE0, 0x0C, 0x1C, 0x02, 0x83, 0x81, 0x9F, 0xF0, 0x02, 0x1E, 0x00, 0x41, 0xC0, 0x0E, 0x7F, 0x81, 0x78, 0x18, 0x62, 0x00, 0xFF, 0xC0,
|
||||
/* 0x02 */ 0x00, 0xFF, 0x80, 0x61, 0x13, 0xF0, 0x62, 0x60, 0x07, 0xFC, 0x00, 0x83, 0x80, 0x10, 0xF0, 0x33, 0xF6, 0x01, 0x41, 0xC0, 0x18, 0x38, 0x03, 0xFF, 0xE0, 0x47, 0x02, 0x08, 0x20, 0x61, 0xC4, 0x06, 0x17, 0x00, 0x22, 0x00, 0x02, 0x40, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x3C, 0x00,
|
||||
/* 0x03 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x04, 0x08, 0x48, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x08, 0x10, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA1, 0x81, 0x8D, 0x87, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x04 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x10, 0x02, 0x48, 0xE0, 0x61, 0xC1, 0xCC, 0x0E, 0x78, 0x1C, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xFC, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x05 */ 0x00, 0x18, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0xF4, 0x08, 0x12, 0x23, 0xC1, 0x91, 0x2C, 0x1C, 0x8A, 0xC3, 0x64, 0x64, 0x13, 0x22, 0x41, 0x98, 0x26, 0x2C, 0xC4, 0x22, 0x60, 0x42, 0x13, 0x04, 0x30, 0x80, 0x61, 0xA4, 0x02, 0x18, 0x20, 0x03, 0x41, 0x00, 0x20, 0x08, 0x02, 0x00, 0x60, 0x40, 0x03, 0xF8,
|
||||
/* 0x06 */ 0x00, 0x10, 0x00, 0x03, 0x00, 0x1C, 0x48, 0x00, 0xB4, 0x80, 0x09, 0xF9, 0xC0, 0xE0, 0xE4, 0x0C, 0x02, 0x8F, 0x80, 0x38, 0x88, 0x01, 0x0D, 0x00, 0x18, 0x30, 0x01, 0x60, 0x80, 0x13, 0x18, 0x03, 0xF2, 0xC0, 0x20, 0x26, 0x06, 0x07, 0xFF, 0xA0, 0x02, 0x39, 0x00, 0x14, 0x70, 0x01, 0xC3, 0x00, 0x18, 0x00,
|
||||
/* 0x07 */
|
||||
/* 0x08 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x10, 0x37, 0xE2, 0x61, 0x00, 0x0C, 0xC6, 0x10, 0x98, 0x0C, 0x63, 0x00, 0x00, 0xC6, 0x00,
|
||||
/* 0x09 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x00, 0x37, 0xE0,
|
||||
/* 0x0A */
|
||||
/* 0x0B */ 0x1F, 0x07, 0xC1, 0x86, 0x41, 0x10, 0x0C, 0x04, 0x80, 0x40, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x88, 0x00, 0x04, 0x40, 0x00, 0x41, 0x00, 0x02, 0x04, 0x00, 0x20, 0x20, 0x02, 0x00, 0x80, 0x20, 0x02, 0x02, 0x00, 0x08, 0x20, 0x00, 0x22, 0x00, 0x00, 0xE0, 0x00,
|
||||
/* 0x0C */ 0x01, 0x00, 0x00, 0x38, 0x00, 0x04, 0xC0, 0x01, 0x08, 0x00, 0x18, 0x80, 0x1C, 0x10, 0x02, 0x07, 0x80, 0x81, 0x10, 0x1F, 0xC2, 0x02, 0x00, 0x60, 0x80, 0x1A, 0x20, 0x1C, 0x42, 0x1C, 0x08, 0xFE, 0x03, 0xA0, 0x01, 0x8C, 0x01, 0xC1, 0x43, 0xD0, 0x27, 0x81, 0xF8,
|
||||
/* 0x0D */
|
||||
/* 0x0E */ 0x00, 0xE0, 0x00, 0x11, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x00, 0x03, 0xF8, 0x00, 0x60, 0x60, 0x09, 0x02, 0x00, 0xA0, 0x10, 0x16, 0x01, 0x01, 0x40, 0x10, 0x10, 0x01, 0x01, 0x00, 0x08, 0x10, 0x00, 0x82, 0x1F, 0x08, 0x3F, 0x90, 0x44, 0x00, 0x06, 0xBF, 0xFF, 0xAF, 0xF0, 0xFF, 0xFF, 0x0F, 0xE3, 0xFB, 0xFC,
|
||||
/* 0x0F */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x40, 0x12, 0x34, 0x00, 0x69, 0x40, 0x01, 0x49, 0xE0, 0xF1, 0xCD, 0x06, 0x8E, 0x28, 0x14, 0x71, 0x40, 0xA3, 0x8B, 0xFD, 0x14, 0x50, 0x68, 0xA2, 0x81, 0x4D, 0x97, 0xFA, 0x44, 0xBF, 0xD6, 0x31, 0x02, 0xE0, 0xC8, 0x16, 0x08, 0x61, 0x08, 0x21, 0xF0, 0x80, 0xF8, 0x78, 0x00,
|
||||
/* 0x10 */ 0x00, 0xF0, 0x00, 0x3A, 0x00, 0x07, 0xC0, 0x00, 0xA8, 0x00, 0x1F, 0x00, 0x02, 0xB0, 0x00, 0x52, 0x00, 0x0A, 0x40, 0x02, 0x48, 0x00, 0x49, 0x00, 0x09, 0x30, 0x01, 0x22, 0x01, 0xC4, 0x70, 0xF0, 0x85, 0xE1, 0x10, 0x88, 0x37, 0x20, 0x03, 0x9C, 0x00, 0x37, 0x00, 0x06, 0x40, 0x01, 0x86, 0x00,
|
||||
/* 0x11 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x60, 0x02, 0x36, 0x00, 0x09, 0x04, 0x0C, 0x48, 0x60, 0xC1, 0xC3, 0x0F, 0x0E, 0x00, 0x08, 0x70, 0x00, 0x23, 0x80, 0x63, 0x84, 0x01, 0x9F, 0x20, 0x0C, 0xFD, 0x80, 0x27, 0xE4, 0x03, 0x3F, 0x30, 0x33, 0xE0, 0xC0, 0x00, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x12 */ 0x00, 0xC2, 0x00, 0x1C, 0x24, 0x02, 0x18, 0x60, 0x64, 0x02, 0x02, 0x40, 0x20, 0x00, 0xF2, 0x03, 0x89, 0xE0, 0x7C, 0x80, 0x0E, 0x25, 0x80, 0xE1, 0x00, 0x1A, 0x08, 0x71, 0xB0, 0xC4, 0x39, 0x84, 0xC2, 0xCC, 0x40, 0x76, 0x7C, 0x05, 0xBB, 0x80, 0x4C, 0xE0, 0x0A, 0x78, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x00,
|
||||
/* 0x13 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x60, 0xC1, 0xC6, 0xC9, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xF8, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x14 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x20, 0x22, 0x33, 0x01, 0x89, 0x20, 0x02, 0x48, 0x60, 0xE1, 0xC8, 0x80, 0x8E, 0x46, 0x46, 0x72, 0x32, 0x33, 0x9F, 0x9F, 0x94, 0x78, 0x78, 0xA0, 0x00, 0x0D, 0x80, 0x00, 0x44, 0x0E, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x15 */ 0x03, 0xFC, 0x20, 0x38, 0x1C, 0x81, 0x80, 0x1D, 0x08, 0x00, 0x32, 0x60, 0x00, 0x89, 0x00, 0x02, 0x18, 0x00, 0x08, 0x61, 0xC3, 0x22, 0x8D, 0x93, 0x72, 0x00, 0x00, 0x48, 0x00, 0x01, 0x20, 0x00, 0x04, 0x9F, 0xFF, 0x92, 0x60, 0x0E, 0x44, 0xFF, 0xF2, 0x11, 0xC3, 0x88, 0x21, 0xF8, 0x40, 0x40, 0x02, 0x00, 0xC0, 0x30, 0x00, 0xFF, 0x00,
|
||||
/* 0x16 */ 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xF0, 0x03, 0xF0, 0x27, 0xF0, 0x6F, 0x70, 0x6E, 0x60, 0xFC, 0x60, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xF4, 0x1F, 0xF4, 0x1F, 0xF0, 0x0E, 0x70, 0x0E, 0x30, 0x1C, 0x38, 0x38, 0x0F, 0xF0,
|
||||
/* 0x17 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x00, 0x21, 0xC0, 0x02, 0x8E, 0x20, 0xF4, 0x70, 0x84, 0x11, 0x82, 0x40, 0x84, 0x01, 0x03, 0x20, 0x0F, 0x85, 0x80, 0x03, 0x04, 0x00, 0x04, 0x30, 0x78, 0x10, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x18 */ 0x00, 0xFC, 0x00, 0x02, 0x06, 0x00, 0x08, 0x24, 0x00, 0x21, 0xA4, 0x00, 0x4C, 0x48, 0x00, 0xA0, 0x50, 0x01, 0x92, 0x60, 0x03, 0x24, 0xC0, 0x06, 0x01, 0x81, 0x28, 0x03, 0x49, 0x6C, 0xC4, 0xAD, 0xD8, 0x16, 0xA4, 0xCC, 0xC4, 0x44, 0x86, 0x13, 0x05, 0x00, 0x28, 0x0A, 0x00, 0x50, 0x14, 0x00, 0x90, 0x48, 0x01, 0x20, 0x90, 0x02, 0x41, 0x20, 0x00, 0x00,
|
||||
/* 0x19 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x49, 0xC3, 0x81, 0xC0, 0x00, 0x0E, 0x78, 0xF0, 0x77, 0xEF, 0xC3, 0xA7, 0x4E, 0x15, 0x0A, 0x10, 0xA7, 0x8F, 0x0D, 0x80, 0x00, 0x44, 0x00, 0x06, 0x33, 0xF0, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x1A */ 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0C, 0x3E, 0x18, 0x82, 0x32, 0x02, 0x64, 0x04, 0xC8, 0x09, 0x80, 0x23, 0x00, 0x86, 0x02, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x81, 0x80, 0x03, 0x00, 0x07, 0xFF, 0xF8,
|
||||
/* 0x1B */ 0x00, 0xFE, 0x00, 0x03, 0x81, 0x80, 0x04, 0x00, 0x60, 0x08, 0x00, 0x30, 0x10, 0x00, 0x10, 0x30, 0x07, 0x88, 0x23, 0xC8, 0x08, 0x22, 0x00, 0x04, 0x60, 0x00, 0x44, 0x60, 0x00, 0x84, 0x63, 0x03, 0x04, 0x61, 0xFC, 0x04, 0x6B, 0x00, 0x9E, 0xA5, 0x01, 0x6A, 0xD5, 0x01, 0x43, 0xA8, 0x81, 0x05, 0xD0, 0x82, 0x0A, 0xA0, 0x82, 0x05, 0xC0, 0x82, 0x02, 0x61, 0xFF, 0x0C, 0x1E, 0x00, 0xF0,
|
||||
/* 0x1C */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x30, 0x02, 0x32, 0x00, 0x09, 0x00, 0x00, 0x48, 0x20, 0x61, 0xC3, 0x84, 0x0E, 0x1C, 0x78, 0x70, 0x40, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA0, 0x03, 0x0D, 0x83, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x1D */ 0x01, 0xFE, 0x00, 0x3A, 0x1C, 0x03, 0x00, 0x30, 0x23, 0x1E, 0xC3, 0x38, 0x03, 0x10, 0xC3, 0x09, 0x00, 0x18, 0x68, 0x00, 0xC1, 0x40, 0x00, 0x0A, 0x07, 0x80, 0x50, 0x46, 0x02, 0x80, 0x00, 0x1A, 0x1E, 0x00, 0xCB, 0x10, 0x0D, 0x03, 0x00, 0x48, 0x60, 0x06, 0x40, 0x00, 0x22, 0x0C, 0x02, 0x10, 0x60, 0x60, 0x43, 0xFC, 0x01, 0xE0, 0x00, 0x00,
|
||||
/* 0x1E */ 0x01, 0xF0, 0x00, 0xEA, 0xC0, 0x31, 0x5F, 0x04, 0x5F, 0x88, 0x80, 0xA0, 0x48, 0x0E, 0x02, 0x8F, 0x40, 0x3C, 0x10, 0x21, 0x66, 0x87, 0x15, 0x98, 0x71, 0x41, 0x02, 0x14, 0x00, 0x01, 0x40, 0x00, 0x14, 0x00, 0x01, 0x21, 0xFE, 0x12, 0x00, 0x02, 0x10, 0x00, 0x60, 0x80, 0x0C, 0x06, 0x01, 0x80, 0x3F, 0xE0,
|
||||
/* 0x1F */ 0x0E, 0x00, 0x13, 0x00, 0x23, 0x00, 0xF3, 0x01, 0x31, 0x01, 0x11, 0x03, 0xD3, 0x06, 0xF2, 0x30, 0x34, 0xC7, 0x25, 0x33, 0x2B, 0xC2, 0x57, 0x04, 0x3A, 0x08, 0x72, 0x30, 0xA3, 0xC3, 0x40, 0x04, 0x40, 0x18, 0x40, 0x60, 0x7F, 0x80,
|
||||
/* ' ' 0x20 */
|
||||
/* '!' 0x21 */ 0xFF, 0xFF, 0xFF, 0xF0, 0xF0,
|
||||
/* '"' 0x22 */ 0xCF, 0x3C, 0xF3, 0x8A, 0x20,
|
||||
/* '#' 0x23 */ 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30,
|
||||
/* '$' 0x24 */ 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x7C, 0x47, 0x88, 0xF1, 0x07, 0xA0, 0x7E, 0x03, 0xF0, 0x17, 0x02, 0x7C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, 0xE0, 0x10, 0x02, 0x00,
|
||||
/* '%' 0x25 */ 0x00, 0x06, 0x03, 0xC0, 0x40, 0x7E, 0x0C, 0x0E, 0x70, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xE7, 0x30, 0x07, 0xE6, 0x00, 0x3C, 0x40, 0x00, 0x0C, 0x7C, 0x00, 0x8F, 0xE0, 0x19, 0xC7, 0x01, 0x18, 0x30, 0x31, 0x83, 0x02, 0x1C, 0x70, 0x40, 0xFE, 0x04, 0x07, 0xC0,
|
||||
/* '&' 0x26 */ 0x0F, 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x39, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, 0x1F, 0x9F, 0xE6, 0x3E, 0x1C,
|
||||
/* ''' 0x27 */ 0xFF, 0xA0,
|
||||
/* '(' 0x28 */ 0x08, 0x8C, 0x46, 0x31, 0x98, 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20,
|
||||
/* ')' 0x29 */ 0x82, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, 0x00,
|
||||
/* '*' 0x2A */ 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00,
|
||||
/* '+' 0x2B */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0,
|
||||
/* ',' 0x2C */ 0xF5, 0x60,
|
||||
/* '-' 0x2D */ 0xFF, 0xF0,
|
||||
/* '.' 0x2E */ 0xF0,
|
||||
/* '/' 0x2F */ 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00,
|
||||
/* '0' 0x30 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* '1' 0x31 */ 0x08, 0xCF, 0xFF, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18,
|
||||
/* '2' 0x32 */ 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0,
|
||||
/* '3' 0x33 */ 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0C, 0x01, 0x80, 0x60, 0x78, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, 0x80, 0xD8, 0x73, 0xFC, 0x3F, 0x00,
|
||||
/* '4' 0x34 */ 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80,
|
||||
/* '5' 0x35 */ 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x81, 0xB8, 0x73, 0xFC, 0x1F, 0x00,
|
||||
/* '6' 0x36 */ 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* '7' 0x37 */ 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00,
|
||||
/* '8' 0x38 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xC1, 0x8C, 0x61, 0xF8, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00,
|
||||
/* '9' 0x39 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, 0xC1, 0x98, 0x73, 0xFC, 0x1E, 0x00,
|
||||
/* ':' 0x3A */ 0xF0, 0x00, 0x03, 0xC0,
|
||||
/* ';' 0x3B */ 0xF0, 0x00, 0x0F, 0x56,
|
||||
/* '<' 0x3C */ 0x00, 0x70, 0x1E, 0x0F, 0x83, 0xC0, 0xF0, 0x0E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10,
|
||||
/* '=' 0x3D */ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* '>' 0x3E */ 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x07, 0x01, 0xE0, 0xF0, 0x3C, 0x0F, 0x00, 0x80, 0x00,
|
||||
/* '?' 0x3F */ 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00,
|
||||
/* '@' 0x40 */ 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x38, 0xC1, 0xE0, 0x66, 0x0F, 0xD9, 0xD8, 0x61, 0xC3, 0xC3, 0x07, 0x0F, 0x1C, 0x1C, 0x3C, 0x60, 0x60, 0xF1, 0x81, 0x83, 0xC6, 0x06, 0x1B, 0x18, 0x38, 0xEE, 0x71, 0xE7, 0x18, 0xFD, 0xF8, 0x71, 0xE7, 0xC0, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x01, 0xFC, 0x00,
|
||||
/* 'A' 0x41 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 'B' 0x42 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00,
|
||||
/* 'C' 0x43 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0,
|
||||
/* 'D' 0x44 */ 0xFF, 0xC3, 0xFF, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1B, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3, 0xFE, 0x00,
|
||||
/* 'E' 0x45 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 'F' 0x46 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xDF, 0xFB, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00,
|
||||
/* 'G' 0x47 */ 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x07, 0x60, 0x03, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x03, 0x60, 0x07, 0x30, 0x0F, 0x3C, 0x1F, 0x1F, 0xFB, 0x07, 0xE1,
|
||||
/* 'H' 0x48 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0,
|
||||
/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 'J' 0x4A */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00,
|
||||
/* 'K' 0x4B */ 0xC0, 0x3E, 0x03, 0xB0, 0x39, 0x83, 0x8C, 0x38, 0x63, 0x83, 0x38, 0x19, 0xC0, 0xDE, 0x07, 0xB8, 0x38, 0xE1, 0x83, 0x0C, 0x1C, 0x60, 0x73, 0x01, 0x98, 0x0E, 0xC0, 0x3E, 0x00, 0xC0,
|
||||
/* 'L' 0x4C */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0,
|
||||
/* 'M' 0x4D */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83,
|
||||
/* 'N' 0x4E */ 0xE0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, 0x0F, 0x30, 0x79, 0xC3, 0xC6, 0x1E, 0x18, 0xF0, 0xE7, 0x83, 0x3C, 0x1D, 0xE0, 0x6F, 0x01, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, 0xC0,
|
||||
/* 'O' 0x4F */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00,
|
||||
/* 'P' 0x50 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00,
|
||||
/* 'Q' 0x51 */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xC0, 0xFC, 0x78, 0x3C, 0x1F, 0xFF, 0x03, 0xF9, 0x80, 0x00, 0x40,
|
||||
/* 'R' 0x52 */ 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70,
|
||||
/* 'S' 0x53 */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80,
|
||||
/* 'T' 0x54 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
|
||||
/* 'U' 0x55 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x80, 0xEE, 0x0E, 0x3F, 0xE0, 0xFC, 0x00,
|
||||
/* 'V' 0x56 */ 0xC0, 0x0F, 0x00, 0x7E, 0x01, 0x98, 0x06, 0x60, 0x39, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x38, 0x60, 0x61, 0x81, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x37, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00,
|
||||
/* 'W' 0x57 */ 0xE0, 0x30, 0x1D, 0x80, 0xE0, 0x76, 0x07, 0x81, 0xDC, 0x1E, 0x06, 0x70, 0x7C, 0x18, 0xC1, 0xB0, 0xE3, 0x0C, 0xC3, 0x8C, 0x33, 0x0C, 0x38, 0xC6, 0x30, 0x67, 0x18, 0xC1, 0x98, 0x67, 0x06, 0x61, 0xD8, 0x1D, 0x83, 0x60, 0x3C, 0x0D, 0x80, 0xF0, 0x3E, 0x03, 0xC0, 0x70, 0x0F, 0x01, 0xC0, 0x18, 0x07, 0x00,
|
||||
/* 'X' 0x58 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70,
|
||||
/* 'Y' 0x59 */ 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
|
||||
/* 'Z' 0x5A */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
/* '[' 0x5B */ 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0,
|
||||
/* '\' 0x5C */ 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04,
|
||||
/* ']' 0x5D */ 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0,
|
||||
/* '^' 0x5E */ 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80,
|
||||
/* '_' 0x5F */ 0xFF, 0xFE,
|
||||
/* '`' 0x60 */ 0xE3, 0x8C, 0x30,
|
||||
/* 'a' 0x61 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
|
||||
/* 'b' 0x62 */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0xF8, 0xDF, 0xCF, 0x0E, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xE0, 0x6F, 0x0E, 0xDF, 0xCC, 0xF8,
|
||||
/* 'c' 0x63 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00,
|
||||
/* 'd' 0x64 */ 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x8F, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8F, 0x3F, 0x63, 0xCC,
|
||||
/* 'e' 0x65 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0,
|
||||
/* 'f' 0x66 */ 0x3B, 0xD8, 0xC6, 0x7F, 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00,
|
||||
/* 'g' 0x67 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xB1, 0xE6, 0x00, 0xC0, 0x3E, 0x0E, 0x7F, 0xC7, 0xE0,
|
||||
/* 'h' 0x68 */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
|
||||
/* 'i' 0x69 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0,
|
||||
/* 'j' 0x6A */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0,
|
||||
/* 'k' 0x6B */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0xB8, 0xC6, 0x31, 0xCC, 0x3B, 0x06, 0xC1, 0xF0, 0x30,
|
||||
/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 'm' 0x6D */ 0xCF, 0x1F, 0x6F, 0xDF, 0xFC, 0x78, 0xFC, 0x18, 0x3C, 0x0C, 0x1E, 0x06, 0x0F, 0x03, 0x07, 0x81, 0x83, 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x3C, 0x0C, 0x18,
|
||||
/* 'n' 0x6E */ 0xCF, 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0,
|
||||
/* 'o' 0x6F */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0,
|
||||
/* 'p' 0x70 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 'q' 0x71 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60,
|
||||
/* 'r' 0x72 */ 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
|
||||
/* 's' 0x73 */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x01, 0xF0, 0x3E, 0x1D, 0xFE, 0x3F, 0x00,
|
||||
/* 't' 0x74 */ 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xE7,
|
||||
/* 'u' 0x75 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0,
|
||||
/* 'v' 0x76 */ 0xE0, 0x6C, 0x0D, 0x81, 0xB8, 0x63, 0x0C, 0x61, 0x8E, 0x60, 0xCC, 0x19, 0x83, 0xE0, 0x3C, 0x07, 0x00, 0xE0,
|
||||
/* 'w' 0x77 */ 0xC1, 0xC1, 0xB0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36, 0x31, 0x9B, 0x18, 0xCD, 0x98, 0x64, 0x6C, 0x16, 0x36, 0x0F, 0x1A, 0x07, 0x8F, 0x03, 0x83, 0x80, 0xC1, 0xC0,
|
||||
/* 'x' 0x78 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0,
|
||||
/* 'y' 0x79 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00,
|
||||
/* 'z' 0x7A */ 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0,
|
||||
/* '{' 0x7B */ 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60,
|
||||
/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
|
||||
/* '}' 0x7D */ 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00,
|
||||
/* '~' 0x7E */ 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, 0x80,
|
||||
/* 0x7F */
|
||||
/* 0x80 */ 0x01, 0xF0, 0x1F, 0xF0, 0xE0, 0xC7, 0x00, 0x18, 0x00, 0xC0, 0x07, 0xFF, 0x3F, 0xFC, 0x30, 0x01, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xE0, 0x81, 0xFE, 0x03, 0xF0,
|
||||
/* 0x81 */
|
||||
/* 0x82 */ 0xF5, 0x80,
|
||||
/* 0x83 */
|
||||
/* 0x84 */ 0xCF, 0x34, 0x51, 0x88,
|
||||
/* 0x85 */ 0xC6, 0x3C, 0x63,
|
||||
/* 0x86 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00,
|
||||
/* 0x87 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x0F, 0xFF, 0xFF, 0x0C, 0x03, 0x00, 0xC0, 0x30,
|
||||
/* 0x88 */
|
||||
/* 0x89 */ 0x38, 0x18, 0x00, 0xF8, 0x30, 0x03, 0x18, 0xC0, 0x04, 0x11, 0x80, 0x0C, 0x66, 0x00, 0x0F, 0x8C, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x31, 0xC0, 0xE0, 0x67, 0xC3, 0xC1, 0x98, 0xCC, 0xC3, 0x20, 0x90, 0x8C, 0x63, 0x33, 0x10, 0x7C, 0x3C, 0x60, 0x70, 0x38,
|
||||
/* 0x8A */ 0x0C, 0x40, 0x1F, 0x00, 0x38, 0x03, 0xF8, 0x1F, 0xF0, 0xE0, 0xE6, 0x01, 0xD8, 0x03, 0x60, 0x01, 0xC0, 0x07, 0x80, 0x0F, 0xE0, 0x0F, 0xF0, 0x03, 0xE0, 0x01, 0xF0, 0x03, 0xC0, 0x0F, 0x80, 0x37, 0x83, 0x8F, 0xFC, 0x0F, 0xE0,
|
||||
/* 0x8B */ 0x2F, 0x49, 0x99,
|
||||
/* 0x8C */ 0x01, 0x80, 0x0C, 0x00, 0x60, 0x00, 0x00, 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80,
|
||||
/* 0x8D */ 0x0C, 0xC0, 0xF8, 0x07, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
|
||||
/* 0x8E */ 0x0C, 0xC0, 0x3C, 0x00, 0xE1, 0xFF, 0xFF, 0xFF, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0x80,
|
||||
/* 0x8F */ 0x01, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x07, 0x00, 0x70, 0x03, 0x00, 0x38, 0x03, 0x80, 0x38, 0x01, 0x80, 0x1C, 0x01, 0xC0, 0x0F, 0xFF, 0xFF, 0xFC,
|
||||
/* 0x90 */
|
||||
/* 0x91 */ 0x6A, 0xF0,
|
||||
/* 0x92 */ 0xF5, 0x60,
|
||||
/* 0x93 */ 0x4E, 0x28, 0xA2, 0xCF, 0x30,
|
||||
/* 0x94 */ 0xCF, 0x34, 0x51, 0x4E, 0x20,
|
||||
/* 0x95 */ 0x7B, 0xFF, 0xFF, 0xFD, 0xE0,
|
||||
/* 0x96 */ 0xFF, 0xFF, 0xF0,
|
||||
/* 0x97 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 0x98 */
|
||||
/* 0x99 */ 0xFF, 0x70, 0x1F, 0xFD, 0xC0, 0x71, 0x87, 0x83, 0xC6, 0x1E, 0x0F, 0x18, 0x68, 0x3C, 0x61, 0xB1, 0xB1, 0x86, 0xC6, 0xC6, 0x19, 0x1B, 0x18, 0x66, 0xCC, 0x61, 0x9B, 0x31, 0x86, 0x3C, 0xC6, 0x18, 0xE3, 0x18, 0x63, 0x8C,
|
||||
/* 0x9A */ 0x63, 0x0D, 0x83, 0x60, 0x70, 0x00, 0x0F, 0x87, 0xFB, 0x86, 0xC0, 0x30, 0x0F, 0x01, 0xFC, 0x0F, 0xC0, 0x7C, 0x0F, 0x87, 0x7F, 0x8F, 0xC0,
|
||||
/* 0x9B */ 0x99, 0x92, 0xF4,
|
||||
/* 0x9C */ 0x07, 0x03, 0x80, 0xC0, 0x60, 0x00, 0x0F, 0x87, 0xFB, 0x86, 0xC0, 0x30, 0x0F, 0x01, 0xFC, 0x0F, 0xC0, 0x7C, 0x0F, 0x87, 0x7F, 0x8F, 0xC0,
|
||||
/* 0x9D */ 0x03, 0x06, 0x66, 0x64, 0x60, 0xF8, 0xF8, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x38,
|
||||
/* 0x9E */ 0x63, 0x0C, 0x83, 0x60, 0x70, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03, 0x01, 0xC0, 0xE0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFF, 0xFF, 0xF0,
|
||||
/* 0x9F */ 0x07, 0x01, 0x80, 0xC0, 0x20, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03, 0x01, 0xC0, 0xE0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xA0 */
|
||||
/* 0xA1 */ 0xC6, 0xD9, 0xB1, 0xC0,
|
||||
/* 0xA2 */ 0x83, 0x8D, 0xF1, 0xC0,
|
||||
/* 0xA3 */ 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x80, 0xCC, 0x06, 0xC0, 0x3C, 0x01, 0xC0, 0x3C, 0x01, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x3F, 0xF9, 0xFF, 0xC0,
|
||||
/* 0xA4 */ 0xDD, 0xFF, 0xD8, 0xD8, 0x3C, 0x1E, 0x0F, 0x8D, 0xFF, 0xDD, 0x80,
|
||||
/* 0xA5 */ 0x03, 0x80, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0xC0, 0x04, 0xE0, 0x0C, 0xE0, 0x0C, 0xE0, 0x08, 0x70, 0x18, 0x70, 0x18, 0x70, 0x10, 0x38, 0x3F, 0xF8, 0x3F, 0xF8, 0x30, 0x1C, 0x70, 0x0C, 0x60, 0x0C, 0x60, 0x0E, 0xE0, 0x06, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x0F,
|
||||
/* 0xA6 */ 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC,
|
||||
/* 0xA7 */ 0x0F, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x70, 0x07, 0x03, 0xF8, 0xC3, 0x98, 0x3B, 0x03, 0xF0, 0x37, 0x06, 0x78, 0xC7, 0xB0, 0x7C, 0x03, 0x80, 0x39, 0x83, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0,
|
||||
/* 0xA8 */ 0xCF, 0x30,
|
||||
/* 0xA9 */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE3, 0x1C, 0x73, 0xF3, 0x99, 0x86, 0x6C, 0xC1, 0x8F, 0x30, 0x03, 0xCC, 0x00, 0xF3, 0x00, 0x3C, 0xC1, 0x8D, 0x98, 0x66, 0x77, 0xF3, 0x8E, 0x79, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
|
||||
/* 0xAA */ 0x0F, 0xC0, 0xFF, 0xC3, 0x03, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDC, 0x0E, 0x3F, 0xF0, 0x3F, 0x00, 0x20, 0x01, 0xE0, 0x01, 0x80, 0x06, 0x00, 0xF0, 0x00,
|
||||
/* 0xAB */ 0x21, 0x63, 0xE7, 0x84, 0x84, 0xE7, 0x63, 0x21,
|
||||
/* 0xAC */ 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03,
|
||||
/* 0xAD */ 0xFF, 0xF0,
|
||||
/* 0xAE */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xFF, 0x1C, 0x7F, 0xF3, 0x9B, 0x04, 0x6C, 0xC1, 0x8F, 0x30, 0x43, 0xCF, 0xF0, 0xF3, 0xFC, 0x3C, 0xC1, 0x0D, 0xB0, 0x66, 0x7C, 0x1B, 0x8F, 0x07, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
|
||||
/* 0xAF */ 0x03, 0x00, 0x18, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0x80,
|
||||
/* 0xB0 */ 0x38, 0xFB, 0x1C, 0x18, 0x38, 0xDF, 0x1C,
|
||||
/* 0xB1 */ 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xE7, 0xFE, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xB2 */ 0x76, 0x31, 0x87, 0x80,
|
||||
/* 0xB3 */ 0x66, 0x66, 0x66, 0x67, 0x7E, 0xE6, 0x66, 0x66, 0x66,
|
||||
/* 0xB4 */ 0x3B, 0x99, 0x80,
|
||||
/* 0xB5 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x1C, 0xE3, 0xCF, 0xEF, 0xFC, 0x7C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 0xB6 */ 0x1F, 0xE7, 0xFD, 0xF3, 0x7E, 0x6F, 0xCD, 0xF9, 0xBF, 0x37, 0xE6, 0x7C, 0xCF, 0x98, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC,
|
||||
/* 0xB7 */ 0xF0,
|
||||
/* 0xB8 */ 0x10, 0xF0, 0xE3, 0x78,
|
||||
/* 0xB9 */ 0x1F, 0x01, 0xFC, 0x1C, 0x70, 0xC1, 0x80, 0x0C, 0x00, 0xE0, 0xFF, 0x1F, 0x18, 0xC0, 0xC6, 0x06, 0x38, 0x70, 0xFF, 0xE3, 0xC7, 0x00, 0x30, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x03, 0xC0,
|
||||
/* 0xBA */ 0x3F, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3E, 0x01, 0xF0, 0x3C, 0x0D, 0xDE, 0x7F, 0x02, 0x01, 0xE0, 0x18, 0x46, 0x0F, 0x00,
|
||||
/* 0xBB */ 0x88, 0xC6, 0xE7, 0x21, 0x21, 0xE7, 0xC6, 0x88,
|
||||
/* 0xBC */ 0xC3, 0x31, 0x8C, 0x63, 0x10, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xBD */ 0x77, 0x66, 0xCC, 0xC8,
|
||||
/* 0xBE */ 0xC7, 0x9B, 0x36, 0xCC, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x80,
|
||||
/* 0xBF */ 0x0C, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0,
|
||||
/* 0xC0 */ 0x03, 0x80, 0x18, 0x00, 0x40, 0x00, 0x00, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70,
|
||||
/* 0xC1 */ 0x01, 0xC0, 0x0C, 0x00, 0x20, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC2 */ 0x07, 0x00, 0x3E, 0x01, 0x8C, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC3 */ 0x10, 0x40, 0x63, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC4 */ 0x0C, 0xC0, 0x33, 0x00, 0x00, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0xFC, 0x03, 0x30, 0x0C, 0xC0, 0x73, 0x81, 0x86, 0x06, 0x18, 0x38, 0x70, 0xC0, 0xC3, 0xFF, 0x1F, 0xFE, 0x60, 0x19, 0x80, 0x6E, 0x01, 0xF0, 0x03, 0xC0, 0x0C,
|
||||
/* 0xC5 */ 0x18, 0x0C, 0x06, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xC6 */ 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xFF, 0x0E, 0x07, 0x38, 0x07, 0x60, 0x06, 0xC0, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xE0, 0x06, 0xC0, 0x0D, 0xC0, 0x31, 0xE0, 0xE1, 0xFF, 0x80, 0xFC, 0x00,
|
||||
/* 0xC7 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x66, 0x00, 0x7C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x01, 0xDC, 0x03, 0x1C, 0x1E, 0x1F, 0xF8, 0x0F, 0xC0, 0x08, 0x00, 0x1E, 0x00, 0x0C, 0x01, 0x18, 0x01, 0xE0, 0x00,
|
||||
/* 0xC8 */ 0x06, 0x30, 0x07, 0xC0, 0x07, 0x00, 0x3F, 0x01, 0xFF, 0x87, 0x03, 0x9C, 0x03, 0xB0, 0x03, 0x60, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x70, 0x03, 0x60, 0x06, 0xE0, 0x18, 0xF0, 0x70, 0xFF, 0xC0, 0x7E, 0x00,
|
||||
/* 0xC9 */ 0x07, 0x00, 0x60, 0x0C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 0xCA */ 0xFF, 0xE7, 0xFF, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xFF, 0xE7, 0xFF, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xFF, 0xF7, 0xFF, 0x80, 0x18, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x01, 0xE0,
|
||||
/* 0xCB */ 0x19, 0x81, 0x98, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xCC */ 0x08, 0xC0, 0xF8, 0x07, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xCD */ 0x36, 0xC0, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
/* 0xCE */ 0x39, 0xFC, 0x40, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
|
||||
/* 0xCF */ 0x18, 0xC0, 0x3E, 0x00, 0x70, 0x3F, 0xF0, 0xFF, 0xE3, 0x01, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1B, 0x00, 0xEC, 0x07, 0x3F, 0xF8, 0xFF, 0x80,
|
||||
/* 0xD0 */ 0x7F, 0xE0, 0xFF, 0xE1, 0x80, 0xE3, 0x00, 0xE6, 0x00, 0xCC, 0x01, 0xD8, 0x01, 0xB0, 0x03, 0xFE, 0x07, 0xFC, 0x0D, 0x80, 0x1B, 0x00, 0x36, 0x00, 0x6C, 0x01, 0x98, 0x07, 0x30, 0x1C, 0x7F, 0xF0, 0xFF, 0xC0,
|
||||
/* 0xD1 */ 0x01, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0E, 0x01, 0xF0, 0x0F, 0xC0, 0x7E, 0x03, 0xD8, 0x1E, 0xE0, 0xF3, 0x07, 0x9C, 0x3C, 0x61, 0xE1, 0x8F, 0x0E, 0x78, 0x33, 0xC1, 0xDE, 0x06, 0xF0, 0x1F, 0x80, 0xFC, 0x03, 0xE0, 0x1C,
|
||||
/* 0xD2 */ 0x0C, 0xC0, 0x3C, 0x00, 0xE1, 0xC0, 0x3E, 0x01, 0xF8, 0x0F, 0xC0, 0x7B, 0x03, 0xDC, 0x1E, 0x60, 0xF3, 0x87, 0x8C, 0x3C, 0x31, 0xE1, 0xCF, 0x06, 0x78, 0x3B, 0xC0, 0xDE, 0x03, 0xF0, 0x1F, 0x80, 0x7C, 0x03, 0x80,
|
||||
/* 0xD3 */ 0x00, 0xE0, 0x00, 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80,
|
||||
/* 0xD4 */ 0x03, 0xC0, 0x01, 0xE0, 0x01, 0x98, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80,
|
||||
/* 0xD5 */ 0x03, 0xB8, 0x01, 0x98, 0x00, 0x98, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80,
|
||||
/* 0xD6 */ 0x06, 0x30, 0x03, 0x18, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFF, 0xC1, 0xE0, 0xF0, 0xC0, 0x18, 0xC0, 0x06, 0x60, 0x03, 0x60, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x06, 0xC0, 0x06, 0x60, 0x03, 0x18, 0x03, 0x0F, 0x07, 0x83, 0xFF, 0x80, 0x7F, 0x00,
|
||||
/* 0xD7 */ 0x81, 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x81,
|
||||
/* 0xD8 */ 0x0C, 0xC0, 0x1E, 0x00, 0x78, 0x3F, 0xF8, 0xFF, 0xF3, 0x00, 0xEC, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x03, 0x3F, 0xF8, 0xFF, 0xF3, 0x00, 0xEC, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1C,
|
||||
/* 0xD9 */ 0x03, 0x00, 0x7C, 0x03, 0x70, 0x19, 0x80, 0xF8, 0x03, 0xC3, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3E, 0x03, 0xB8, 0x38, 0xFF, 0x83, 0xF0,
|
||||
/* 0xDA */ 0x03, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0,
|
||||
/* 0xDB */ 0x0E, 0xE0, 0x66, 0x03, 0x60, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0,
|
||||
/* 0xDC */ 0x0C, 0xC0, 0x66, 0x00, 0x01, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0x01, 0xDC, 0x1C, 0x7F, 0xC1, 0xF8, 0x00,
|
||||
/* 0xDD */ 0x01, 0x80, 0x0C, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
|
||||
/* 0xDE */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x04, 0x00, 0x78, 0x01, 0x81, 0x18, 0x0F, 0x00,
|
||||
/* 0xDF */ 0x1F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0D, 0x81, 0xB0, 0x66, 0x38, 0xC7, 0xD8, 0x1B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x3E, 0x0E, 0xCF, 0x99, 0xE0,
|
||||
/* 0xE0 */ 0x0C, 0x61, 0x8C, 0x03, 0x3D, 0xFC, 0xE3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00,
|
||||
/* 0xE1 */ 0x07, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7,
|
||||
/* 0xE2 */ 0x0C, 0x01, 0xE0, 0x1B, 0x03, 0x30, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7,
|
||||
/* 0xE3 */ 0x20, 0x82, 0x10, 0x3F, 0x01, 0xE0, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7,
|
||||
/* 0xE4 */ 0x19, 0x81, 0x98, 0x00, 0x00, 0x00, 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
|
||||
/* 0xE5 */ 0x3B, 0x30, 0x06, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x30,
|
||||
/* 0xE6 */ 0x07, 0x01, 0x80, 0xC0, 0x20, 0x00, 0x07, 0xC3, 0xF9, 0x87, 0xE0, 0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0E, 0x0D, 0xC7, 0x3F, 0x87, 0xC0,
|
||||
/* 0xE7 */ 0x1F, 0x0F, 0xE7, 0x1D, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x02, 0x00, 0xE0, 0x0C, 0x23, 0x07, 0x80,
|
||||
/* 0xE8 */ 0x21, 0x0C, 0xC1, 0xE0, 0x78, 0x00, 0x07, 0xC3, 0xF9, 0x87, 0xE0, 0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0E, 0x0D, 0xC7, 0x3F, 0x87, 0xC0,
|
||||
/* 0xE9 */ 0x03, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0,
|
||||
/* 0xEA */ 0x1F, 0x07, 0xF1, 0x87, 0x60, 0x6C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x1D, 0x87, 0x1F, 0xC1, 0xF8, 0x06, 0x01, 0x80, 0x30, 0x06, 0x00, 0x78,
|
||||
/* 0xEB */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x03, 0xC0, 0x7F, 0xFF, 0xFF, 0xE0, 0x0C, 0x01, 0xC0, 0xDC, 0x31, 0xFC, 0x1F, 0x00,
|
||||
/* 0xEC */ 0x31, 0x82, 0x60, 0x6C, 0x07, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0,
|
||||
/* 0xED */ 0x39, 0x99, 0x80, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x80,
|
||||
/* 0xEE */ 0x71, 0xED, 0xA3, 0x00, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
|
||||
/* 0xEF */ 0x00, 0x67, 0x00, 0x66, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x60, 0x1E, 0x60, 0x3F, 0xE0, 0x71, 0xE0, 0xE0, 0xE0, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xE0, 0xE0, 0x71, 0xE0, 0x3F, 0x60, 0x1E, 0x60,
|
||||
/* 0xF0 */ 0x00, 0x60, 0x06, 0x03, 0xF0, 0x06, 0x00, 0x61, 0xE6, 0x3F, 0xE7, 0x1E, 0xE0, 0xEC, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xE0, 0xE7, 0x1E, 0x3F, 0xE1, 0xE6,
|
||||
/* 0xF1 */ 0x03, 0x81, 0xC0, 0x60, 0x30, 0x00, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
|
||||
/* 0xF2 */ 0x31, 0x84, 0xC1, 0xA0, 0x38, 0x00, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
|
||||
/* 0xF3 */ 0x07, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF4 */ 0x0C, 0x03, 0xC0, 0xD8, 0x19, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF5 */ 0x0C, 0xC3, 0xB8, 0x66, 0x0D, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF6 */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* 0xF7 */ 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00,
|
||||
/* 0xF8 */ 0xC7, 0x37, 0x8E, 0x03, 0x3D, 0xFC, 0xE3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00,
|
||||
/* 0xF9 */ 0x0E, 0x07, 0xC1, 0xB8, 0x6C, 0x1F, 0x03, 0x8C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x07, 0xE3, 0xDF, 0xB3, 0xCC,
|
||||
/* 0xFA */ 0x03, 0x01, 0x80, 0x60, 0x30, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30,
|
||||
/* 0xFB */ 0x1D, 0xC6, 0x61, 0xB0, 0xCC, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30,
|
||||
/* 0xFC */ 0x31, 0x8C, 0x60, 0x00, 0x00, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0,
|
||||
/* 0xFD */ 0x03, 0x80, 0x60, 0x18, 0x06, 0x00, 0x01, 0xC0, 0xD8, 0x1B, 0x06, 0x70, 0xC6, 0x18, 0xC6, 0x18, 0xC1, 0x98, 0x36, 0x06, 0xC0, 0x78, 0x0E, 0x01, 0xC0, 0x30, 0x06, 0x01, 0xC0, 0xF0, 0x1C, 0x00,
|
||||
/* 0xFE */ 0x61, 0x86, 0x3E, 0xF9, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0x8E, 0x10, 0x83, 0xC3, 0x78,
|
||||
/* 0xFF */ 0xF0,
|
||||
};
|
||||
|
||||
const GFXglyph FreeSans12pt_Win1250Glyphs[] PROGMEM = {
|
||||
/* 0x01 */ { 0, 19, 20, 21, 1, -17 },
|
||||
/* 0x02 */ { 48, 19, 20, 21, 1, -17 },
|
||||
/* 0x03 */ { 96, 21, 20, 23, 1, -17 },
|
||||
/* 0x04 */ { 149, 21, 20, 23, 1, -17 },
|
||||
/* 0x05 */ { 202, 20, 20, 22, 1, -17 },
|
||||
/* 0x06 */ { 252, 20, 20, 22, 1, -17 },
|
||||
/* 0x07 */ { 302, 0, 0, 8, 0, 0 },
|
||||
/* 0x08 */ { 302, 23, 20, 25, 1, -17 },
|
||||
/* 0x09 */ { 360, 23, 16, 25, 1, -16 },
|
||||
/* 0x0A */ { 406, 0, 0, 8, 0, 0 },
|
||||
/* 0x0B */ { 406, 21, 20, 23, 1, -17 },
|
||||
/* 0x0C */ { 459, 19, 18, 21, 1, -15 },
|
||||
/* 0x0D */ { 502, 0, 0, 8, 0, 0 },
|
||||
/* 0x0E */ { 502, 20, 20, 22, 1, -17 },
|
||||
/* 0x0F */ { 552, 21, 21, 23, 1, -18 },
|
||||
/* 0x10 */ { 608, 19, 20, 21, 1, -17 },
|
||||
/* 0x11 */ { 656, 21, 20, 23, 1, -17 },
|
||||
/* 0x12 */ { 709, 20, 20, 22, 1, -17 },
|
||||
/* 0x13 */ { 759, 21, 20, 23, 1, -17 },
|
||||
/* 0x14 */ { 812, 21, 20, 23, 1, -17 },
|
||||
/* 0x15 */ { 865, 22, 20, 24, 1, -17 },
|
||||
/* 0x16 */ { 920, 16, 20, 18, 1, -17 },
|
||||
/* 0x17 */ { 960, 21, 20, 23, 1, -17 },
|
||||
/* 0x18 */ { 1013, 23, 20, 25, 1, -17 },
|
||||
/* 0x19 */ { 1071, 21, 20, 23, 1, -17 },
|
||||
/* 0x1A */ { 1124, 15, 19, 17, 1, -16 },
|
||||
/* 0x1B */ { 1160, 24, 21, 26, 1, -18 },
|
||||
/* 0x1C */ { 1223, 21, 20, 23, 1, -17 },
|
||||
/* 0x1D */ { 1276, 21, 21, 23, 1, -18 },
|
||||
/* 0x1E */ { 1332, 20, 20, 22, 1, -17 },
|
||||
/* 0x1F */ { 1382, 15, 20, 17, 1, -17 },
|
||||
/* ' ' 0x20 */ { 1420, 0, 0, 6, 0, 0 },
|
||||
/* '!' 0x21 */ { 1420, 2, 18, 8, 3, -16 },
|
||||
/* '"' 0x22 */ { 1425, 6, 6, 8, 1, -15 },
|
||||
/* '#' 0x23 */ { 1430, 13, 16, 13, 0, -14 },
|
||||
/* '$' 0x24 */ { 1456, 11, 20, 13, 1, -16 },
|
||||
/* '%' 0x25 */ { 1484, 20, 17, 21, 1, -15 },
|
||||
/* '&' 0x26 */ { 1527, 14, 17, 16, 1, -15 },
|
||||
/* ''' 0x27 */ { 1557, 2, 6, 5, 1, -15 },
|
||||
/* '(' 0x28 */ { 1559, 5, 23, 8, 2, -16 },
|
||||
/* ')' 0x29 */ { 1574, 5, 23, 8, 1, -16 },
|
||||
/* '*' 0x2A */ { 1589, 7, 7, 9, 1, -16 },
|
||||
/* '+' 0x2B */ { 1596, 10, 11, 14, 2, -9 },
|
||||
/* ',' 0x2C */ { 1610, 2, 6, 7, 2, 0 },
|
||||
/* '-' 0x2D */ { 1612, 6, 2, 8, 1, -6 },
|
||||
/* '.' 0x2E */ { 1614, 2, 2, 6, 2, 0 },
|
||||
/* '/' 0x2F */ { 1615, 7, 18, 7, 0, -16 },
|
||||
/* '0' 0x30 */ { 1631, 11, 17, 13, 1, -15 },
|
||||
/* '1' 0x31 */ { 1655, 5, 17, 13, 3, -15 },
|
||||
/* '2' 0x32 */ { 1666, 11, 17, 13, 1, -15 },
|
||||
/* '3' 0x33 */ { 1690, 11, 17, 13, 1, -15 },
|
||||
/* '4' 0x34 */ { 1714, 11, 17, 13, 1, -15 },
|
||||
/* '5' 0x35 */ { 1738, 11, 17, 13, 1, -15 },
|
||||
/* '6' 0x36 */ { 1762, 11, 17, 13, 1, -15 },
|
||||
/* '7' 0x37 */ { 1786, 11, 17, 13, 1, -15 },
|
||||
/* '8' 0x38 */ { 1810, 11, 17, 13, 1, -15 },
|
||||
/* '9' 0x39 */ { 1834, 11, 17, 13, 1, -15 },
|
||||
/* ':' 0x3A */ { 1858, 2, 13, 6, 2, -11 },
|
||||
/* ';' 0x3B */ { 1862, 2, 16, 6, 2, -10 },
|
||||
/* '<' 0x3C */ { 1866, 12, 11, 14, 1, -9 },
|
||||
/* '=' 0x3D */ { 1883, 12, 6, 14, 1, -7 },
|
||||
/* '>' 0x3E */ { 1892, 12, 11, 14, 1, -9 },
|
||||
/* '?' 0x3F */ { 1909, 10, 18, 13, 2, -16 },
|
||||
/* '@' 0x40 */ { 1932, 22, 21, 24, 1, -16 },
|
||||
/* 'A' 0x41 */ { 1990, 14, 18, 16, 1, -16 },
|
||||
/* 'B' 0x42 */ { 2022, 13, 18, 16, 2, -16 },
|
||||
/* 'C' 0x43 */ { 2052, 15, 18, 17, 1, -16 },
|
||||
/* 'D' 0x44 */ { 2086, 14, 18, 17, 2, -16 },
|
||||
/* 'E' 0x45 */ { 2118, 12, 18, 15, 2, -16 },
|
||||
/* 'F' 0x46 */ { 2145, 11, 18, 14, 2, -16 },
|
||||
/* 'G' 0x47 */ { 2170, 16, 18, 18, 1, -16 },
|
||||
/* 'H' 0x48 */ { 2206, 13, 18, 17, 2, -16 },
|
||||
/* 'I' 0x49 */ { 2236, 2, 18, 7, 2, -16 },
|
||||
/* 'J' 0x4A */ { 2241, 9, 18, 13, 1, -16 },
|
||||
/* 'K' 0x4B */ { 2262, 13, 18, 16, 2, -16 },
|
||||
/* 'L' 0x4C */ { 2292, 10, 18, 14, 2, -16 },
|
||||
/* 'M' 0x4D */ { 2315, 16, 18, 20, 2, -16 },
|
||||
/* 'N' 0x4E */ { 2351, 13, 18, 18, 2, -16 },
|
||||
/* 'O' 0x4F */ { 2381, 17, 18, 19, 1, -16 },
|
||||
/* 'P' 0x50 */ { 2420, 12, 18, 16, 2, -16 },
|
||||
/* 'Q' 0x51 */ { 2447, 17, 19, 19, 1, -16 },
|
||||
/* 'R' 0x52 */ { 2488, 14, 18, 17, 2, -16 },
|
||||
/* 'S' 0x53 */ { 2520, 14, 18, 16, 1, -16 },
|
||||
/* 'T' 0x54 */ { 2552, 12, 18, 15, 1, -16 },
|
||||
/* 'U' 0x55 */ { 2579, 13, 18, 17, 2, -16 },
|
||||
/* 'V' 0x56 */ { 2609, 14, 18, 15, 1, -16 },
|
||||
/* 'W' 0x57 */ { 2641, 22, 18, 22, 0, -16 },
|
||||
/* 'X' 0x58 */ { 2691, 14, 18, 16, 1, -16 },
|
||||
/* 'Y' 0x59 */ { 2723, 14, 18, 16, 1, -16 },
|
||||
/* 'Z' 0x5A */ { 2755, 13, 18, 15, 1, -16 },
|
||||
/* '[' 0x5B */ { 2785, 4, 23, 7, 2, -16 },
|
||||
/* '\' 0x5C */ { 2797, 7, 18, 7, 0, -16 },
|
||||
/* ']' 0x5D */ { 2813, 4, 23, 7, 1, -16 },
|
||||
/* '^' 0x5E */ { 2825, 9, 9, 11, 1, -15 },
|
||||
/* '_' 0x5F */ { 2836, 15, 1, 13, -1, 5 },
|
||||
/* '`' 0x60 */ { 2838, 5, 4, 6, 1, -16 },
|
||||
/* 'a' 0x61 */ { 2841, 12, 13, 13, 1, -11 },
|
||||
/* 'b' 0x62 */ { 2861, 12, 18, 13, 1, -16 },
|
||||
/* 'c' 0x63 */ { 2888, 10, 13, 12, 1, -11 },
|
||||
/* 'd' 0x64 */ { 2905, 11, 18, 13, 1, -16 },
|
||||
/* 'e' 0x65 */ { 2930, 11, 13, 13, 1, -11 },
|
||||
/* 'f' 0x66 */ { 2948, 5, 18, 7, 1, -16 },
|
||||
/* 'g' 0x67 */ { 2960, 11, 18, 13, 1, -11 },
|
||||
/* 'h' 0x68 */ { 2985, 10, 18, 13, 1, -16 },
|
||||
/* 'i' 0x69 */ { 3008, 2, 18, 5, 2, -16 },
|
||||
/* 'j' 0x6A */ { 3013, 4, 23, 6, 0, -16 },
|
||||
/* 'k' 0x6B */ { 3025, 10, 18, 12, 1, -16 },
|
||||
/* 'l' 0x6C */ { 3048, 2, 18, 5, 1, -16 },
|
||||
/* 'm' 0x6D */ { 3053, 17, 13, 19, 1, -11 },
|
||||
/* 'n' 0x6E */ { 3081, 10, 13, 13, 1, -11 },
|
||||
/* 'o' 0x6F */ { 3098, 11, 13, 13, 1, -11 },
|
||||
/* 'p' 0x70 */ { 3116, 12, 17, 13, 1, -11 },
|
||||
/* 'q' 0x71 */ { 3142, 11, 17, 13, 1, -11 },
|
||||
/* 'r' 0x72 */ { 3166, 6, 13, 8, 1, -11 },
|
||||
/* 's' 0x73 */ { 3176, 10, 13, 12, 1, -11 },
|
||||
/* 't' 0x74 */ { 3193, 5, 16, 7, 1, -14 },
|
||||
/* 'u' 0x75 */ { 3203, 10, 13, 13, 1, -11 },
|
||||
/* 'v' 0x76 */ { 3220, 11, 13, 12, 0, -11 },
|
||||
/* 'w' 0x77 */ { 3238, 17, 13, 17, 0, -11 },
|
||||
/* 'x' 0x78 */ { 3266, 10, 13, 11, 1, -11 },
|
||||
/* 'y' 0x79 */ { 3283, 11, 18, 11, 0, -11 },
|
||||
/* 'z' 0x7A */ { 3308, 10, 13, 12, 1, -11 },
|
||||
/* '{' 0x7B */ { 3325, 5, 23, 8, 1, -16 },
|
||||
/* '|' 0x7C */ { 3340, 2, 23, 6, 2, -16 },
|
||||
/* '}' 0x7D */ { 3346, 5, 23, 8, 2, -16 },
|
||||
/* '~' 0x7E */ { 3361, 10, 5, 12, 1, -9 },
|
||||
/* 0x7F */ { 3368, 0, 0, 0, 0, 0 },
|
||||
/* 0x80 */ { 3368, 14, 17, 16, 1, -17 },
|
||||
/* 0x81 */ { 3398, 0, 0, 8, 0, 0 },
|
||||
/* 0x82 */ { 3398, 2, 5, 6, 2, -2 },
|
||||
/* 0x83 */ { 3400, 0, 0, 8, 0, 0 },
|
||||
/* 0x84 */ { 3400, 6, 5, 10, 2, -2 },
|
||||
/* 0x85 */ { 3404, 12, 2, 16, 2, -2 },
|
||||
/* 0x86 */ { 3407, 10, 21, 13, 2, -17 },
|
||||
/* 0x87 */ { 3434, 10, 20, 13, 2, -17 },
|
||||
/* 0x88 */ { 3459, 0, 0, 8, 0, 0 },
|
||||
/* 0x89 */ { 3459, 23, 18, 24, 0, -18 },
|
||||
/* 0x8A */ { 3511, 14, 21, 16, 1, -21 },
|
||||
/* 0x8B */ { 3548, 3, 8, 6, 1, -11 },
|
||||
/* 0x8C */ { 3551, 14, 22, 16, 1, -22 },
|
||||
/* 0x8D */ { 3590, 12, 21, 15, 1, -21 },
|
||||
/* 0x8E */ { 3622, 13, 21, 15, 1, -21 },
|
||||
/* 0x8F */ { 3657, 13, 22, 15, 1, -22 },
|
||||
/* 0x90 */ { 3693, 0, 0, 8, 0, 0 },
|
||||
/* 0x91 */ { 3693, 2, 6, 6, 2, -18 },
|
||||
/* 0x92 */ { 3695, 2, 6, 6, 2, -18 },
|
||||
/* 0x93 */ { 3697, 6, 6, 10, 2, -18 },
|
||||
/* 0x94 */ { 3702, 6, 6, 10, 2, -18 },
|
||||
/* 0x95 */ { 3707, 6, 6, 10, 2, -11 },
|
||||
/* 0x96 */ { 3712, 10, 2, 12, 1, -8 },
|
||||
/* 0x97 */ { 3715, 22, 2, 24, 1, -8 },
|
||||
/* 0x98 */ { 3721, 0, 0, 8, 0, 0 },
|
||||
/* 0x99 */ { 3721, 22, 13, 24, 2, -18 },
|
||||
/* 0x9A */ { 3757, 10, 18, 12, 1, -18 },
|
||||
/* 0x9B */ { 3780, 3, 8, 6, 2, -10 },
|
||||
/* 0x9C */ { 3783, 10, 18, 12, 1, -18 },
|
||||
/* 0x9D */ { 3806, 8, 18, 11, 1, -18 },
|
||||
/* 0x9E */ { 3824, 10, 18, 12, 1, -18 },
|
||||
/* 0x9F */ { 3847, 10, 18, 12, 1, -18 },
|
||||
/* 0xA0 */ { 3870, 0, 0, 7, 0, 0 },
|
||||
/* 0xA1 */ { 3870, 7, 4, 8, 0, -18 },
|
||||
/* 0xA2 */ { 3874, 7, 4, 8, 0, -18 },
|
||||
/* 0xA3 */ { 3878, 13, 18, 15, 1, -18 },
|
||||
/* 0xA4 */ { 3908, 9, 9, 13, 2, -13 },
|
||||
/* 0xA5 */ { 3919, 16, 23, 16, 1, -18 },
|
||||
/* 0xA6 */ { 3965, 2, 23, 6, 2, -18 },
|
||||
/* 0xA7 */ { 3971, 11, 23, 13, 1, -18 },
|
||||
/* 0xA8 */ { 4003, 6, 2, 8, 1, -17 },
|
||||
/* 0xA9 */ { 4005, 18, 17, 19, 1, -17 },
|
||||
/* 0xAA */ { 4044, 14, 23, 16, 1, -18 },
|
||||
/* 0xAB */ { 4085, 8, 8, 12, 2, -11 },
|
||||
/* 0xAC */ { 4093, 12, 6, 14, 1, -9 },
|
||||
/* 0xAD */ { 4102, 6, 2, 8, 1, -8 },
|
||||
/* 0xAE */ { 4104, 18, 17, 19, 1, -17 },
|
||||
/* 0xAF */ { 4143, 13, 21, 15, 1, -21 },
|
||||
/* 0xB0 */ { 4178, 7, 8, 15, 4, -17 },
|
||||
/* 0xB1 */ { 4185, 12, 15, 14, 1, -15 },
|
||||
/* 0xB2 */ { 4208, 5, 5, 8, 1, 0 },
|
||||
/* 0xB3 */ { 4212, 4, 18, 6, 1, -18 },
|
||||
/* 0xB4 */ { 4221, 5, 4, 8, 2, -18 },
|
||||
/* 0xB5 */ { 4224, 12, 17, 13, 2, -13 },
|
||||
/* 0xB6 */ { 4250, 11, 21, 13, 2, -18 },
|
||||
/* 0xB7 */ { 4279, 2, 2, 6, 2, -8 },
|
||||
/* 0xB8 */ { 4280, 6, 5, 8, 1, 0 },
|
||||
/* 0xB9 */ { 4284, 13, 18, 13, 1, -13 },
|
||||
/* 0xBA */ { 4314, 10, 18, 12, 1, -13 },
|
||||
/* 0xBB */ { 4337, 8, 8, 12, 2, -10 },
|
||||
/* 0xBC */ { 4345, 10, 18, 14, 2, -18 },
|
||||
/* 0xBD */ { 4368, 8, 4, 8, 0, -18 },
|
||||
/* 0xBE */ { 4372, 7, 18, 9, 1, -18 },
|
||||
/* 0xBF */ { 4388, 10, 17, 12, 1, -17 },
|
||||
/* 0xC0 */ { 4410, 14, 22, 17, 2, -22 },
|
||||
/* 0xC1 */ { 4449, 14, 22, 16, 1, -22 },
|
||||
/* 0xC2 */ { 4488, 14, 22, 16, 1, -22 },
|
||||
/* 0xC3 */ { 4527, 14, 22, 16, 1, -22 },
|
||||
/* 0xC4 */ { 4566, 14, 21, 16, 1, -21 },
|
||||
/* 0xC5 */ { 4603, 10, 22, 14, 2, -22 },
|
||||
/* 0xC6 */ { 4631, 15, 22, 17, 1, -22 },
|
||||
/* 0xC7 */ { 4673, 15, 23, 17, 1, -18 },
|
||||
/* 0xC8 */ { 4717, 15, 21, 17, 1, -21 },
|
||||
/* 0xC9 */ { 4757, 12, 22, 15, 2, -22 },
|
||||
/* 0xCA */ { 4790, 13, 23, 15, 2, -18 },
|
||||
/* 0xCB */ { 4828, 12, 21, 15, 2, -21 },
|
||||
/* 0xCC */ { 4860, 12, 21, 15, 2, -21 },
|
||||
/* 0xCD */ { 4892, 4, 22, 7, 1, -22 },
|
||||
/* 0xCE */ { 4903, 6, 22, 7, 0, -22 },
|
||||
/* 0xCF */ { 4920, 14, 21, 17, 2, -21 },
|
||||
/* 0xD0 */ { 4957, 15, 18, 17, 1, -18 },
|
||||
/* 0xD1 */ { 4991, 13, 22, 18, 2, -22 },
|
||||
/* 0xD2 */ { 5027, 13, 21, 18, 2, -21 },
|
||||
/* 0xD3 */ { 5062, 17, 22, 19, 1, -22 },
|
||||
/* 0xD4 */ { 5109, 17, 22, 19, 1, -22 },
|
||||
/* 0xD5 */ { 5156, 17, 22, 19, 1, -22 },
|
||||
/* 0xD6 */ { 5203, 17, 21, 19, 1, -21 },
|
||||
/* 0xD7 */ { 5248, 8, 9, 14, 3, -10 },
|
||||
/* 0xD8 */ { 5257, 14, 21, 17, 2, -21 },
|
||||
/* 0xD9 */ { 5294, 13, 24, 17, 2, -24 },
|
||||
/* 0xDA */ { 5333, 13, 22, 17, 2, -22 },
|
||||
/* 0xDB */ { 5369, 13, 22, 17, 2, -22 },
|
||||
/* 0xDC */ { 5405, 13, 21, 17, 2, -21 },
|
||||
/* 0xDD */ { 5440, 14, 22, 16, 1, -22 },
|
||||
/* 0xDE */ { 5479, 12, 23, 15, 1, -18 },
|
||||
/* 0xDF */ { 5514, 11, 18, 14, 2, -18 },
|
||||
/* 0xE0 */ { 5539, 6, 18, 8, 1, -18 },
|
||||
/* 0xE1 */ { 5553, 12, 18, 13, 1, -18 },
|
||||
/* 0xE2 */ { 5580, 12, 18, 13, 1, -18 },
|
||||
/* 0xE3 */ { 5607, 12, 18, 13, 1, -18 },
|
||||
/* 0xE4 */ { 5634, 12, 17, 13, 1, -17 },
|
||||
/* 0xE5 */ { 5660, 5, 22, 6, 0, -22 },
|
||||
/* 0xE6 */ { 5674, 10, 18, 12, 1, -18 },
|
||||
/* 0xE7 */ { 5697, 10, 18, 12, 1, -13 },
|
||||
/* 0xE8 */ { 5720, 10, 18, 12, 1, -18 },
|
||||
/* 0xE9 */ { 5743, 11, 18, 13, 1, -18 },
|
||||
/* 0xEA */ { 5768, 11, 18, 13, 1, -13 },
|
||||
/* 0xEB */ { 5793, 11, 17, 13, 1, -17 },
|
||||
/* 0xEC */ { 5817, 11, 18, 13, 1, -18 },
|
||||
/* 0xED */ { 5842, 5, 18, 5, 0, -18 },
|
||||
/* 0xEE */ { 5854, 6, 18, 6, 0, -18 },
|
||||
/* 0xEF */ { 5868, 16, 18, 18, 1, -18 },
|
||||
/* 0xF0 */ { 5904, 12, 18, 14, 1, -18 },
|
||||
/* 0xF1 */ { 5931, 10, 18, 13, 1, -18 },
|
||||
/* 0xF2 */ { 5954, 10, 18, 13, 1, -18 },
|
||||
/* 0xF3 */ { 5977, 11, 18, 13, 1, -18 },
|
||||
/* 0xF4 */ { 6002, 11, 18, 13, 1, -18 },
|
||||
/* 0xF5 */ { 6027, 11, 18, 13, 1, -18 },
|
||||
/* 0xF6 */ { 6052, 11, 17, 13, 1, -17 },
|
||||
/* 0xF7 */ { 6076, 12, 11, 14, 1, -11 },
|
||||
/* 0xF8 */ { 6093, 6, 18, 8, 1, -18 },
|
||||
/* 0xF9 */ { 6107, 10, 19, 13, 1, -19 },
|
||||
/* 0xFA */ { 6131, 10, 18, 13, 1, -18 },
|
||||
/* 0xFB */ { 6154, 10, 18, 13, 1, -18 },
|
||||
/* 0xFC */ { 6177, 10, 17, 13, 1, -17 },
|
||||
/* 0xFD */ { 6199, 11, 23, 11, 0, -18 },
|
||||
/* 0xFE */ { 6231, 6, 21, 7, 1, -16 },
|
||||
/* 0xFF */ { 6247, 2, 2, 8, 3, -17 },
|
||||
};
|
||||
|
||||
const GFXfont FreeSans12pt_Win1250 PROGMEM = {
|
||||
(uint8_t*)FreeSans12pt_Win1250Bitmaps,
|
||||
(GFXglyph*)FreeSans12pt_Win1250Glyphs,
|
||||
0x01, 0xFF, 19
|
||||
};
|
||||
@@ -0,0 +1,527 @@
|
||||
// trunk-ignore-all(clang-format)
|
||||
#pragma once
|
||||
/* PROPERTIES
|
||||
|
||||
FONT_NAME FreeSans12pt_Win1251
|
||||
*/
|
||||
const uint8_t FreeSans12pt_Win1251Bitmaps[] PROGMEM = {
|
||||
/* 0x01 */ 0x00, 0x30, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x24, 0x00, 0x04, 0x80, 0x01, 0x90, 0x00, 0x62, 0x00, 0x30, 0xFE, 0x04, 0x10, 0x5F, 0x02, 0x0B, 0x00, 0x7F, 0xE0, 0x0C, 0x1C, 0x02, 0x83, 0x81, 0x9F, 0xF0, 0x02, 0x1E, 0x00, 0x41, 0xC0, 0x0E, 0x7F, 0x81, 0x78, 0x18, 0x62, 0x00, 0xFF, 0xC0,
|
||||
/* 0x02 */ 0x00, 0xFF, 0x80, 0x61, 0x13, 0xF0, 0x62, 0x60, 0x07, 0xFC, 0x00, 0x83, 0x80, 0x10, 0xF0, 0x33, 0xF6, 0x01, 0x41, 0xC0, 0x18, 0x38, 0x03, 0xFF, 0xE0, 0x47, 0x02, 0x08, 0x20, 0x61, 0xC4, 0x06, 0x17, 0x00, 0x22, 0x00, 0x02, 0x40, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x3C, 0x00,
|
||||
/* 0x03 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x04, 0x08, 0x48, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x08, 0x10, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA1, 0x81, 0x8D, 0x87, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x04 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x10, 0x02, 0x48, 0xE0, 0x61, 0xC1, 0xCC, 0x0E, 0x78, 0x1C, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xFC, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x05 */ 0x00, 0x18, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0xF4, 0x08, 0x12, 0x23, 0xC1, 0x91, 0x2C, 0x1C, 0x8A, 0xC3, 0x64, 0x64, 0x13, 0x22, 0x41, 0x98, 0x26, 0x2C, 0xC4, 0x22, 0x60, 0x42, 0x13, 0x04, 0x30, 0x80, 0x61, 0xA4, 0x02, 0x18, 0x20, 0x03, 0x41, 0x00, 0x20, 0x08, 0x02, 0x00, 0x60, 0x40, 0x03, 0xF8,
|
||||
/* 0x06 */ 0x00, 0x10, 0x00, 0x03, 0x00, 0x1C, 0x48, 0x00, 0xB4, 0x80, 0x09, 0xF9, 0xC0, 0xE0, 0xE4, 0x0C, 0x02, 0x8F, 0x80, 0x38, 0x88, 0x01, 0x0D, 0x00, 0x18, 0x30, 0x01, 0x60, 0x80, 0x13, 0x18, 0x03, 0xF2, 0xC0, 0x20, 0x26, 0x06, 0x07, 0xFF, 0xA0, 0x02, 0x39, 0x00, 0x14, 0x70, 0x01, 0xC3, 0x00, 0x18, 0x00,
|
||||
/* 0x07 */
|
||||
/* 0x08 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x10, 0x37, 0xE2, 0x61, 0x00, 0x0C, 0xC6, 0x10, 0x98, 0x0C, 0x63, 0x00, 0x00, 0xC6, 0x00,
|
||||
/* 0x09 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x00, 0x37, 0xE0,
|
||||
/* 0x0A */
|
||||
/* 0x0B */ 0x1F, 0x07, 0xC1, 0x86, 0x41, 0x10, 0x0C, 0x04, 0x80, 0x40, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x88, 0x00, 0x04, 0x40, 0x00, 0x41, 0x00, 0x02, 0x04, 0x00, 0x20, 0x20, 0x02, 0x00, 0x80, 0x20, 0x02, 0x02, 0x00, 0x08, 0x20, 0x00, 0x22, 0x00, 0x00, 0xE0, 0x00,
|
||||
/* 0x0C */ 0x01, 0x00, 0x00, 0x38, 0x00, 0x04, 0xC0, 0x01, 0x08, 0x00, 0x18, 0x80, 0x1C, 0x10, 0x02, 0x07, 0x80, 0x81, 0x10, 0x1F, 0xC2, 0x02, 0x00, 0x60, 0x80, 0x1A, 0x20, 0x1C, 0x42, 0x1C, 0x08, 0xFE, 0x03, 0xA0, 0x01, 0x8C, 0x01, 0xC1, 0x43, 0xD0, 0x27, 0x81, 0xF8,
|
||||
/* 0x0D */
|
||||
/* 0x0E */ 0x00, 0xE0, 0x00, 0x11, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x00, 0x03, 0xF8, 0x00, 0x60, 0x60, 0x09, 0x02, 0x00, 0xA0, 0x10, 0x16, 0x01, 0x01, 0x40, 0x10, 0x10, 0x01, 0x01, 0x00, 0x08, 0x10, 0x00, 0x82, 0x1F, 0x08, 0x3F, 0x90, 0x44, 0x00, 0x06, 0xBF, 0xFF, 0xAF, 0xF0, 0xFF, 0xFF, 0x0F, 0xE3, 0xFB, 0xFC,
|
||||
/* 0x0F */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x40, 0x12, 0x34, 0x00, 0x69, 0x40, 0x01, 0x49, 0xE0, 0xF1, 0xCD, 0x06, 0x8E, 0x28, 0x14, 0x71, 0x40, 0xA3, 0x8B, 0xFD, 0x14, 0x50, 0x68, 0xA2, 0x81, 0x4D, 0x97, 0xFA, 0x44, 0xBF, 0xD6, 0x31, 0x02, 0xE0, 0xC8, 0x16, 0x08, 0x61, 0x08, 0x21, 0xF0, 0x80, 0xF8, 0x78, 0x00,
|
||||
/* 0x10 */ 0x00, 0xF0, 0x00, 0x3A, 0x00, 0x07, 0xC0, 0x00, 0xA8, 0x00, 0x1F, 0x00, 0x02, 0xB0, 0x00, 0x52, 0x00, 0x0A, 0x40, 0x02, 0x48, 0x00, 0x49, 0x00, 0x09, 0x30, 0x01, 0x22, 0x01, 0xC4, 0x70, 0xF0, 0x85, 0xE1, 0x10, 0x88, 0x37, 0x20, 0x03, 0x9C, 0x00, 0x37, 0x00, 0x06, 0x40, 0x01, 0x86, 0x00,
|
||||
/* 0x11 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x60, 0x02, 0x36, 0x00, 0x09, 0x04, 0x0C, 0x48, 0x60, 0xC1, 0xC3, 0x0F, 0x0E, 0x00, 0x08, 0x70, 0x00, 0x23, 0x80, 0x63, 0x84, 0x01, 0x9F, 0x20, 0x0C, 0xFD, 0x80, 0x27, 0xE4, 0x03, 0x3F, 0x30, 0x33, 0xE0, 0xC0, 0x00, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x12 */ 0x00, 0xC2, 0x00, 0x1C, 0x24, 0x02, 0x18, 0x60, 0x64, 0x02, 0x02, 0x40, 0x20, 0x00, 0xF2, 0x03, 0x89, 0xE0, 0x7C, 0x80, 0x0E, 0x25, 0x80, 0xE1, 0x00, 0x1A, 0x08, 0x71, 0xB0, 0xC4, 0x39, 0x84, 0xC2, 0xCC, 0x40, 0x76, 0x7C, 0x05, 0xBB, 0x80, 0x4C, 0xE0, 0x0A, 0x78, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x00,
|
||||
/* 0x13 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x60, 0xC1, 0xC6, 0xC9, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xF8, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x14 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x20, 0x22, 0x33, 0x01, 0x89, 0x20, 0x02, 0x48, 0x60, 0xE1, 0xC8, 0x80, 0x8E, 0x46, 0x46, 0x72, 0x32, 0x33, 0x9F, 0x9F, 0x94, 0x78, 0x78, 0xA0, 0x00, 0x0D, 0x80, 0x00, 0x44, 0x0E, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x15 */ 0x03, 0xFC, 0x20, 0x38, 0x1C, 0x81, 0x80, 0x1D, 0x08, 0x00, 0x32, 0x60, 0x00, 0x89, 0x00, 0x02, 0x18, 0x00, 0x08, 0x61, 0xC3, 0x22, 0x8D, 0x93, 0x72, 0x00, 0x00, 0x48, 0x00, 0x01, 0x20, 0x00, 0x04, 0x9F, 0xFF, 0x92, 0x60, 0x0E, 0x44, 0xFF, 0xF2, 0x11, 0xC3, 0x88, 0x21, 0xF8, 0x40, 0x40, 0x02, 0x00, 0xC0, 0x30, 0x00, 0xFF, 0x00,
|
||||
/* 0x16 */ 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xF0, 0x03, 0xF0, 0x27, 0xF0, 0x6F, 0x70, 0x6E, 0x60, 0xFC, 0x60, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xF4, 0x1F, 0xF4, 0x1F, 0xF0, 0x0E, 0x70, 0x0E, 0x30, 0x1C, 0x38, 0x38, 0x0F, 0xF0,
|
||||
/* 0x17 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x00, 0x21, 0xC0, 0x02, 0x8E, 0x20, 0xF4, 0x70, 0x84, 0x11, 0x82, 0x40, 0x84, 0x01, 0x03, 0x20, 0x0F, 0x85, 0x80, 0x03, 0x04, 0x00, 0x04, 0x30, 0x78, 0x10, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x18 */ 0x00, 0xFC, 0x00, 0x02, 0x06, 0x00, 0x08, 0x24, 0x00, 0x21, 0xA4, 0x00, 0x4C, 0x48, 0x00, 0xA0, 0x50, 0x01, 0x92, 0x60, 0x03, 0x24, 0xC0, 0x06, 0x01, 0x81, 0x28, 0x03, 0x49, 0x6C, 0xC4, 0xAD, 0xD8, 0x16, 0xA4, 0xCC, 0xC4, 0x44, 0x86, 0x13, 0x05, 0x00, 0x28, 0x0A, 0x00, 0x50, 0x14, 0x00, 0x90, 0x48, 0x01, 0x20, 0x90, 0x02, 0x41, 0x20, 0x00, 0x00,
|
||||
/* 0x19 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x49, 0xC3, 0x81, 0xC0, 0x00, 0x0E, 0x78, 0xF0, 0x77, 0xEF, 0xC3, 0xA7, 0x4E, 0x15, 0x0A, 0x10, 0xA7, 0x8F, 0x0D, 0x80, 0x00, 0x44, 0x00, 0x06, 0x33, 0xF0, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x1A */ 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0C, 0x3E, 0x18, 0x82, 0x32, 0x02, 0x64, 0x04, 0xC8, 0x09, 0x80, 0x23, 0x00, 0x86, 0x02, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x81, 0x80, 0x03, 0x00, 0x07, 0xFF, 0xF8,
|
||||
/* 0x1B */ 0x00, 0xFE, 0x00, 0x03, 0x81, 0x80, 0x04, 0x00, 0x60, 0x08, 0x00, 0x30, 0x10, 0x00, 0x10, 0x30, 0x07, 0x88, 0x23, 0xC8, 0x08, 0x22, 0x00, 0x04, 0x60, 0x00, 0x44, 0x60, 0x00, 0x84, 0x63, 0x03, 0x04, 0x61, 0xFC, 0x04, 0x6B, 0x00, 0x9E, 0xA5, 0x01, 0x6A, 0xD5, 0x01, 0x43, 0xA8, 0x81, 0x05, 0xD0, 0x82, 0x0A, 0xA0, 0x82, 0x05, 0xC0, 0x82, 0x02, 0x61, 0xFF, 0x0C, 0x1E, 0x00, 0xF0,
|
||||
/* 0x1C */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x30, 0x02, 0x32, 0x00, 0x09, 0x00, 0x00, 0x48, 0x20, 0x61, 0xC3, 0x84, 0x0E, 0x1C, 0x78, 0x70, 0x40, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA0, 0x03, 0x0D, 0x83, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x1D */ 0x01, 0xFE, 0x00, 0x3A, 0x1C, 0x03, 0x00, 0x30, 0x23, 0x1E, 0xC3, 0x38, 0x03, 0x10, 0xC3, 0x09, 0x00, 0x18, 0x68, 0x00, 0xC1, 0x40, 0x00, 0x0A, 0x07, 0x80, 0x50, 0x46, 0x02, 0x80, 0x00, 0x1A, 0x1E, 0x00, 0xCB, 0x10, 0x0D, 0x03, 0x00, 0x48, 0x60, 0x06, 0x40, 0x00, 0x22, 0x0C, 0x02, 0x10, 0x60, 0x60, 0x43, 0xFC, 0x01, 0xE0, 0x00, 0x00,
|
||||
/* 0x1E */ 0x01, 0xF0, 0x00, 0xEA, 0xC0, 0x31, 0x5F, 0x04, 0x5F, 0x88, 0x80, 0xA0, 0x48, 0x0E, 0x02, 0x8F, 0x40, 0x3C, 0x10, 0x21, 0x66, 0x87, 0x15, 0x98, 0x71, 0x41, 0x02, 0x14, 0x00, 0x01, 0x40, 0x00, 0x14, 0x00, 0x01, 0x21, 0xFE, 0x12, 0x00, 0x02, 0x10, 0x00, 0x60, 0x80, 0x0C, 0x06, 0x01, 0x80, 0x3F, 0xE0,
|
||||
/* 0x1F */ 0x0E, 0x00, 0x13, 0x00, 0x23, 0x00, 0xF3, 0x01, 0x31, 0x01, 0x11, 0x03, 0xD3, 0x06, 0xF2, 0x30, 0x34, 0xC7, 0x25, 0x33, 0x2B, 0xC2, 0x57, 0x04, 0x3A, 0x08, 0x72, 0x30, 0xA3, 0xC3, 0x40, 0x04, 0x40, 0x18, 0x40, 0x60, 0x7F, 0x80,
|
||||
/* ' ' 0x20 */
|
||||
/* '!' 0x21 */ 0xFF, 0xFF, 0xFF, 0xF0, 0xF0,
|
||||
/* '"' 0x22 */ 0xCF, 0x3C, 0xF3, 0x8A, 0x20,
|
||||
/* '#' 0x23 */ 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30,
|
||||
/* '$' 0x24 */ 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x7C, 0x47, 0x88, 0xF1, 0x07, 0xA0, 0x7E, 0x03, 0xF0, 0x17, 0x02, 0x7C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, 0xE0, 0x10, 0x02, 0x00,
|
||||
/* '%' 0x25 */ 0x00, 0x06, 0x03, 0xC0, 0x40, 0x7E, 0x0C, 0x0E, 0x70, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xE7, 0x30, 0x07, 0xE6, 0x00, 0x3C, 0x40, 0x00, 0x0C, 0x7C, 0x00, 0x8F, 0xE0, 0x19, 0xC7, 0x01, 0x18, 0x30, 0x31, 0x83, 0x02, 0x1C, 0x70, 0x40, 0xFE, 0x04, 0x07, 0xC0,
|
||||
/* '&' 0x26 */ 0x0F, 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x39, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, 0x1F, 0x9F, 0xE6, 0x3E, 0x1C,
|
||||
/* ''' 0x27 */ 0xFF, 0xA0,
|
||||
/* '(' 0x28 */ 0x08, 0x8C, 0x46, 0x31, 0x98, 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20,
|
||||
/* ')' 0x29 */ 0x82, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, 0x00,
|
||||
/* '*' 0x2A */ 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00,
|
||||
/* '+' 0x2B */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0,
|
||||
/* ',' 0x2C */ 0xF5, 0x60,
|
||||
/* '-' 0x2D */ 0xFF, 0xF0,
|
||||
/* '.' 0x2E */ 0xF0,
|
||||
/* '/' 0x2F */ 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00,
|
||||
/* '0' 0x30 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* '1' 0x31 */ 0x08, 0xCF, 0xFF, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18,
|
||||
/* '2' 0x32 */ 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0,
|
||||
/* '3' 0x33 */ 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0C, 0x01, 0x80, 0x60, 0x78, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, 0x80, 0xD8, 0x73, 0xFC, 0x3F, 0x00,
|
||||
/* '4' 0x34 */ 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80,
|
||||
/* '5' 0x35 */ 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x81, 0xB8, 0x73, 0xFC, 0x1F, 0x00,
|
||||
/* '6' 0x36 */ 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* '7' 0x37 */ 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00,
|
||||
/* '8' 0x38 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xC1, 0x8C, 0x61, 0xF8, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00,
|
||||
/* '9' 0x39 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, 0xC1, 0x98, 0x73, 0xFC, 0x1E, 0x00,
|
||||
/* ':' 0x3A */ 0xF0, 0x00, 0x03, 0xC0,
|
||||
/* ';' 0x3B */ 0xF0, 0x00, 0x0F, 0x56,
|
||||
/* '<' 0x3C */ 0x00, 0x70, 0x1E, 0x0F, 0x83, 0xC0, 0xF0, 0x0E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10,
|
||||
/* '=' 0x3D */ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* '>' 0x3E */ 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x07, 0x01, 0xE0, 0xF0, 0x3C, 0x0F, 0x00, 0x80, 0x00,
|
||||
/* '?' 0x3F */ 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00,
|
||||
/* '@' 0x40 */ 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x38, 0xC1, 0xE0, 0x66, 0x0F, 0xD9, 0xD8, 0x61, 0xC3, 0xC3, 0x07, 0x0F, 0x1C, 0x1C, 0x3C, 0x60, 0x60, 0xF1, 0x81, 0x83, 0xC6, 0x06, 0x1B, 0x18, 0x38, 0xEE, 0x71, 0xE7, 0x18, 0xFD, 0xF8, 0x71, 0xE7, 0xC0, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x01, 0xFC, 0x00,
|
||||
/* 'A' 0x41 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 'B' 0x42 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00,
|
||||
/* 'C' 0x43 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0,
|
||||
/* 'D' 0x44 */ 0xFF, 0xC3, 0xFF, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1B, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3, 0xFE, 0x00,
|
||||
/* 'E' 0x45 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 'F' 0x46 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xDF, 0xFB, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00,
|
||||
/* 'G' 0x47 */ 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x07, 0x60, 0x03, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x03, 0x60, 0x07, 0x30, 0x0F, 0x3C, 0x1F, 0x1F, 0xFB, 0x07, 0xE1,
|
||||
/* 'H' 0x48 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0,
|
||||
/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 'J' 0x4A */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00,
|
||||
/* 'K' 0x4B */ 0xC0, 0x3E, 0x03, 0xB0, 0x39, 0x83, 0x8C, 0x38, 0x63, 0x83, 0x38, 0x19, 0xC0, 0xDE, 0x07, 0xB8, 0x38, 0xE1, 0x83, 0x0C, 0x1C, 0x60, 0x73, 0x01, 0x98, 0x0E, 0xC0, 0x3E, 0x00, 0xC0,
|
||||
/* 'L' 0x4C */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0,
|
||||
/* 'M' 0x4D */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83,
|
||||
/* 'N' 0x4E */ 0xE0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, 0x0F, 0x30, 0x79, 0xC3, 0xC6, 0x1E, 0x18, 0xF0, 0xE7, 0x83, 0x3C, 0x1D, 0xE0, 0x6F, 0x01, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, 0xC0,
|
||||
/* 'O' 0x4F */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00,
|
||||
/* 'P' 0x50 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00,
|
||||
/* 'Q' 0x51 */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xC0, 0xFC, 0x78, 0x3C, 0x1F, 0xFF, 0x03, 0xF9, 0x80, 0x00, 0x40,
|
||||
/* 'R' 0x52 */ 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70,
|
||||
/* 'S' 0x53 */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80,
|
||||
/* 'T' 0x54 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
|
||||
/* 'U' 0x55 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x80, 0xEE, 0x0E, 0x3F, 0xE0, 0xFC, 0x00,
|
||||
/* 'V' 0x56 */ 0xC0, 0x0F, 0x00, 0x7E, 0x01, 0x98, 0x06, 0x60, 0x39, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x38, 0x60, 0x61, 0x81, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x37, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00,
|
||||
/* 'W' 0x57 */ 0xE0, 0x30, 0x1D, 0x80, 0xE0, 0x76, 0x07, 0x81, 0xDC, 0x1E, 0x06, 0x70, 0x7C, 0x18, 0xC1, 0xB0, 0xE3, 0x0C, 0xC3, 0x8C, 0x33, 0x0C, 0x38, 0xC6, 0x30, 0x67, 0x18, 0xC1, 0x98, 0x67, 0x06, 0x61, 0xD8, 0x1D, 0x83, 0x60, 0x3C, 0x0D, 0x80, 0xF0, 0x3E, 0x03, 0xC0, 0x70, 0x0F, 0x01, 0xC0, 0x18, 0x07, 0x00,
|
||||
/* 'X' 0x58 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70,
|
||||
/* 'Y' 0x59 */ 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
|
||||
/* 'Z' 0x5A */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
/* '[' 0x5B */ 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0,
|
||||
/* '\' 0x5C */ 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04,
|
||||
/* ']' 0x5D */ 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0,
|
||||
/* '^' 0x5E */ 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80,
|
||||
/* '_' 0x5F */ 0xFF, 0xFE,
|
||||
/* '`' 0x60 */ 0xE3, 0x8C, 0x30,
|
||||
/* 'a' 0x61 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
|
||||
/* 'b' 0x62 */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0xF8, 0xDF, 0xCF, 0x0E, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xE0, 0x6F, 0x0E, 0xDF, 0xCC, 0xF8,
|
||||
/* 'c' 0x63 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00,
|
||||
/* 'd' 0x64 */ 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x8F, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8F, 0x3F, 0x63, 0xCC,
|
||||
/* 'e' 0x65 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0,
|
||||
/* 'f' 0x66 */ 0x3B, 0xD8, 0xC6, 0x7F, 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00,
|
||||
/* 'g' 0x67 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xB1, 0xE6, 0x00, 0xC0, 0x3E, 0x0E, 0x7F, 0xC7, 0xE0,
|
||||
/* 'h' 0x68 */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
|
||||
/* 'i' 0x69 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0,
|
||||
/* 'j' 0x6A */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0,
|
||||
/* 'k' 0x6B */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0xB8, 0xC6, 0x31, 0xCC, 0x3B, 0x06, 0xC1, 0xF0, 0x30,
|
||||
/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 'm' 0x6D */ 0xCF, 0x1F, 0x6F, 0xDF, 0xFC, 0x78, 0xFC, 0x18, 0x3C, 0x0C, 0x1E, 0x06, 0x0F, 0x03, 0x07, 0x81, 0x83, 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x3C, 0x0C, 0x18,
|
||||
/* 'n' 0x6E */ 0xCF, 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0,
|
||||
/* 'o' 0x6F */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0,
|
||||
/* 'p' 0x70 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 'q' 0x71 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60,
|
||||
/* 'r' 0x72 */ 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
|
||||
/* 's' 0x73 */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x01, 0xF0, 0x3E, 0x1D, 0xFE, 0x3F, 0x00,
|
||||
/* 't' 0x74 */ 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xE7,
|
||||
/* 'u' 0x75 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0,
|
||||
/* 'v' 0x76 */ 0xE0, 0x6C, 0x0D, 0x81, 0xB8, 0x63, 0x0C, 0x61, 0x8E, 0x60, 0xCC, 0x19, 0x83, 0xE0, 0x3C, 0x07, 0x00, 0xE0,
|
||||
/* 'w' 0x77 */ 0xC1, 0xC1, 0xB0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36, 0x31, 0x9B, 0x18, 0xCD, 0x98, 0x64, 0x6C, 0x16, 0x36, 0x0F, 0x1A, 0x07, 0x8F, 0x03, 0x83, 0x80, 0xC1, 0xC0,
|
||||
/* 'x' 0x78 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0,
|
||||
/* 'y' 0x79 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00,
|
||||
/* 'z' 0x7A */ 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0,
|
||||
/* '{' 0x7B */ 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60,
|
||||
/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
|
||||
/* '}' 0x7D */ 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00,
|
||||
/* '~' 0x7E */ 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, 0x80,
|
||||
/* 0x7F */
|
||||
/* 0x80 */ 0xFF, 0xE0, 0xFF, 0xE0, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0xFC, 0x07, 0xFE, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x1E, 0x00, 0x1C,
|
||||
/* 0x81 */ 0x07, 0x01, 0xC0, 0x20, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x00,
|
||||
/* 0x82 */ 0xF5, 0x80,
|
||||
/* 0x83 */ 0x0C, 0x38, 0x61, 0x80, 0x1F, 0xFF, 0xE0, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x80,
|
||||
/* 0x84 */ 0xCF, 0x34, 0x51, 0x88,
|
||||
/* 0x85 */ 0xC6, 0x3C, 0x63,
|
||||
/* 0x86 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00,
|
||||
/* 0x87 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x0F, 0xFF, 0xFF, 0x0C, 0x03, 0x00, 0xC0, 0x30,
|
||||
/* 0x88 */ 0x01, 0xF0, 0x1F, 0xF0, 0xE0, 0xC7, 0x00, 0x18, 0x00, 0xC0, 0x07, 0xFF, 0x3F, 0xFC, 0x30, 0x01, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xE0, 0x81, 0xFE, 0x03, 0xF0,
|
||||
/* 0x89 */ 0x38, 0x18, 0x00, 0xF8, 0x30, 0x03, 0x18, 0xC0, 0x04, 0x11, 0x80, 0x0C, 0x66, 0x00, 0x0F, 0x8C, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x31, 0xC0, 0xE0, 0x67, 0xC3, 0xC1, 0x98, 0xCC, 0xC3, 0x20, 0x90, 0x8C, 0x63, 0x33, 0x10, 0x7C, 0x3C, 0x60, 0x70, 0x38,
|
||||
/* 0x8A */ 0x1F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x1F, 0xF0, 0x30, 0x3F, 0xF0, 0x60, 0x60, 0x30, 0xC0, 0xC0, 0x31, 0x81, 0x80, 0x66, 0x03, 0x00, 0xCC, 0x06, 0x01, 0xB8, 0x0C, 0x06, 0xE0, 0x1F, 0xFD, 0x80, 0x3F, 0xE0,
|
||||
/* 0x8B */ 0x2F, 0x49, 0x99,
|
||||
/* 0x8C */ 0xC0, 0x60, 0x06, 0x03, 0x00, 0x30, 0x18, 0x01, 0x80, 0xC0, 0x0C, 0x06, 0x00, 0x60, 0x30, 0x03, 0x01, 0x80, 0x18, 0x0C, 0x00, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x30, 0x18, 0x1D, 0x80, 0xC0, 0x3C, 0x06, 0x01, 0xE0, 0x30, 0x0F, 0x01, 0x80, 0x78, 0x0C, 0x06, 0xC0, 0x7F, 0xF6, 0x03, 0xFE, 0x00,
|
||||
/* 0x8D */ 0x03, 0x00, 0x60, 0x0C, 0x00, 0x00, 0xC0, 0x7C, 0x0E, 0xC1, 0xCC, 0x38, 0xC7, 0x0C, 0xE0, 0xDC, 0x0F, 0x80, 0xF0, 0x0F, 0x80, 0xDC, 0x0C, 0xE0, 0xC7, 0x0C, 0x30, 0xC3, 0x8C, 0x1C, 0xC0, 0xEC, 0x07,
|
||||
/* 0x8E */ 0xFF, 0xE0, 0xFF, 0xE0, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0xFC, 0x07, 0xFE, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03,
|
||||
/* 0x8F */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0x06, 0x00, 0x30, 0x00,
|
||||
/* 0x90 */ 0x30, 0x0F, 0xF0, 0xFF, 0x03, 0x00, 0x30, 0x03, 0x3C, 0x37, 0xE3, 0xC7, 0x38, 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, 0x33, 0x03, 0x00, 0x60, 0x06, 0x01, 0x80, 0x30,
|
||||
/* 0x91 */ 0x6A, 0xF0,
|
||||
/* 0x92 */ 0xF5, 0x60,
|
||||
/* 0x93 */ 0x4E, 0x28, 0xA2, 0xCF, 0x30,
|
||||
/* 0x94 */ 0xCF, 0x34, 0x51, 0x4E, 0x20,
|
||||
/* 0x95 */ 0x7B, 0xFF, 0xFF, 0xFD, 0xE0,
|
||||
/* 0x96 */ 0xFF, 0xFF, 0xF0,
|
||||
/* 0x97 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 0x98 */
|
||||
/* 0x99 */ 0xFF, 0x70, 0x1F, 0xFD, 0xC0, 0x71, 0x87, 0x83, 0xC6, 0x1E, 0x0F, 0x18, 0x68, 0x3C, 0x61, 0xB1, 0xB1, 0x86, 0xC6, 0xC6, 0x19, 0x1B, 0x18, 0x66, 0xCC, 0x61, 0x9B, 0x31, 0x86, 0x3C, 0xC6, 0x18, 0xE3, 0x18, 0x63, 0x8C,
|
||||
/* 0x9A */ 0x7F, 0x80, 0x3F, 0xC0, 0x18, 0x60, 0x0C, 0x30, 0x06, 0x18, 0x03, 0x0F, 0xF1, 0x87, 0xFC, 0xC3, 0x07, 0x61, 0x81, 0xB0, 0xC0, 0xD0, 0x60, 0xF8, 0x3F, 0xEC, 0x1F, 0xE0,
|
||||
/* 0x9B */ 0x99, 0x92, 0xF4,
|
||||
/* 0x9C */ 0xC0, 0xC0, 0x30, 0x30, 0x0C, 0x0C, 0x03, 0x03, 0x00, 0xC0, 0xC0, 0x3F, 0xFF, 0xCF, 0xFF, 0xFB, 0x03, 0x07, 0xC0, 0xC0, 0xF0, 0x30, 0x3C, 0x0C, 0x1F, 0x03, 0xFE, 0xC0, 0xFF, 0x00,
|
||||
/* 0x9D */ 0x07, 0x07, 0x03, 0x03, 0x00, 0x06, 0x0F, 0x0D, 0x8C, 0xCC, 0x6C, 0x3C, 0x1E, 0x0F, 0x86, 0xE3, 0x39, 0x8E, 0xC3, 0xE0, 0xC0,
|
||||
/* 0x9E */ 0x30, 0x1F, 0xE3, 0xFC, 0x18, 0x03, 0x00, 0x67, 0x0D, 0xF9, 0xC7, 0x38, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C,
|
||||
/* 0x9F */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xC1, 0x80, 0x60,
|
||||
/* 0xA0 */
|
||||
/* 0xA1 */ 0x10, 0x40, 0xC4, 0x07, 0xE0, 0x1E, 0x0C, 0x01, 0xF0, 0x1D, 0x80, 0xCE, 0x0E, 0x30, 0x61, 0xC7, 0x06, 0x30, 0x3B, 0x81, 0xD8, 0x07, 0xC0, 0x3C, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x03, 0x80, 0x38, 0x01, 0xC0, 0x1C, 0x00,
|
||||
/* 0xA2 */ 0x21, 0x86, 0x20, 0xFC, 0x07, 0x0E, 0x06, 0xC0, 0xD8, 0x33, 0x86, 0x30, 0xC6, 0x30, 0xC6, 0x0C, 0xC1, 0xB0, 0x36, 0x03, 0xC0, 0x70, 0x0E, 0x01, 0x80, 0x30, 0x0E, 0x07, 0x80, 0xE0, 0x00,
|
||||
/* 0xA3 */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00,
|
||||
/* 0xA4 */ 0xDD, 0xFF, 0xD8, 0xD8, 0x3C, 0x1E, 0x0F, 0x8D, 0xFF, 0xDD, 0x80,
|
||||
/* 0xA5 */ 0x00, 0x60, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x00,
|
||||
/* 0xA6 */ 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC,
|
||||
/* 0xA7 */ 0x0F, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x70, 0x07, 0x03, 0xF8, 0xC3, 0x98, 0x3B, 0x03, 0xF0, 0x37, 0x06, 0x78, 0xC7, 0xB0, 0x7C, 0x03, 0x80, 0x39, 0x83, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0,
|
||||
/* 0xA8 */ 0x19, 0x81, 0x98, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xA9 */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE3, 0x1C, 0x73, 0xF3, 0x99, 0x86, 0x6C, 0xC1, 0x8F, 0x30, 0x03, 0xCC, 0x00, 0xF3, 0x00, 0x3C, 0xC1, 0x8D, 0x98, 0x66, 0x77, 0xF3, 0x8E, 0x79, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
|
||||
/* 0xAA */ 0x07, 0xE0, 0x3F, 0xF0, 0xF0, 0x71, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xFF, 0xE1, 0xFF, 0xC3, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1C, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0,
|
||||
/* 0xAB */ 0x21, 0x63, 0xE7, 0x84, 0x84, 0xE7, 0x63, 0x21,
|
||||
/* 0xAC */ 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03,
|
||||
/* 0xAD */ 0xFF, 0xF0,
|
||||
/* 0xAE */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xFF, 0x1C, 0x7F, 0xF3, 0x9B, 0x04, 0x6C, 0xC1, 0x8F, 0x30, 0x43, 0xCF, 0xF0, 0xF3, 0xFC, 0x3C, 0xC1, 0x0D, 0xB0, 0x66, 0x7C, 0x1B, 0x8F, 0x07, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
|
||||
/* 0xAF */ 0xC7, 0x8C, 0x01, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x00,
|
||||
/* 0xB0 */ 0x38, 0xFB, 0x1C, 0x18, 0x38, 0xDF, 0x1C,
|
||||
/* 0xB1 */ 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xE7, 0xFE, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xB2 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xB3 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xB4 */ 0x03, 0x03, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
|
||||
/* 0xB5 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x1C, 0xE3, 0xCF, 0xEF, 0xFC, 0x7C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 0xB6 */ 0x1F, 0xE7, 0xFD, 0xF3, 0x7E, 0x6F, 0xCD, 0xF9, 0xBF, 0x37, 0xE6, 0x7C, 0xCF, 0x98, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC,
|
||||
/* 0xB7 */ 0xF0,
|
||||
/* 0xB8 */ 0x19, 0x83, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x03, 0xC0, 0x7F, 0xFF, 0xFF, 0xE0, 0x0C, 0x01, 0xC0, 0xDC, 0x31, 0xFC, 0x1F, 0x00,
|
||||
/* 0xB9 */ 0xC0, 0xC0, 0x18, 0x18, 0x03, 0x83, 0x00, 0x70, 0x60, 0x0B, 0x0C, 0x01, 0x61, 0x8F, 0xA6, 0x33, 0x1C, 0xC6, 0x41, 0x88, 0xC8, 0x31, 0x99, 0x06, 0x13, 0x20, 0xC3, 0x66, 0x38, 0x6C, 0xEF, 0x07, 0x8F, 0xA0, 0xF0, 0x04, 0x0E, 0x00, 0x81, 0xC7, 0xF0, 0x18, 0xFC,
|
||||
/* 0xBA */ 0x1F, 0x87, 0xF9, 0xC3, 0x30, 0x3E, 0x01, 0xFE, 0x3F, 0xC6, 0x00, 0xE0, 0x0C, 0x0D, 0xC3, 0x9F, 0xE1, 0xF8,
|
||||
/* 0xBB */ 0x88, 0xC6, 0xE7, 0x21, 0x21, 0xE7, 0xC6, 0x88,
|
||||
/* 0xBC */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0,
|
||||
/* 0xBD */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80,
|
||||
/* 0xBE */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x00, 0xF0, 0x3E, 0x1D, 0xFE, 0x3E, 0x00,
|
||||
/* 0xBF */ 0xCF, 0x30, 0x00, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30,
|
||||
/* 0xC0 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC1 */ 0xFF, 0xE7, 0xFF, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x1F, 0xF8, 0xFF, 0xF6, 0x01, 0xB0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00,
|
||||
/* 0xC2 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00,
|
||||
/* 0xC3 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00,
|
||||
/* 0xC4 */ 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x60, 0x60, 0x18, 0x18, 0x06, 0x06, 0x01, 0x81, 0x80, 0x60, 0x60, 0x18, 0x18, 0x06, 0x06, 0x01, 0x81, 0x80, 0x60, 0x60, 0x18, 0x18, 0x0E, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x70, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xC0,
|
||||
/* 0xC5 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 0xC6 */ 0x70, 0x60, 0xE3, 0x06, 0x0C, 0x38, 0x61, 0xC1, 0xC6, 0x38, 0x0E, 0x67, 0x00, 0x66, 0x60, 0x03, 0x6C, 0x00, 0x3F, 0xC0, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x03, 0xFC, 0x00, 0x76, 0xE0, 0x0E, 0x67, 0x01, 0xC6, 0x38, 0x38, 0x61, 0xC3, 0x06, 0x0C, 0x60, 0x60, 0xEE, 0x06, 0x07,
|
||||
/* 0xC7 */ 0x0F, 0x81, 0xFF, 0x0C, 0x18, 0xC0, 0x66, 0x03, 0x00, 0x18, 0x01, 0xC0, 0x1C, 0x07, 0xC0, 0x3F, 0x00, 0x1C, 0x00, 0x7C, 0x01, 0xE0, 0x0F, 0x80, 0x6E, 0x0E, 0x3F, 0xE0, 0x7E, 0x00,
|
||||
/* 0xC8 */ 0xC0, 0x3E, 0x01, 0xF0, 0x1F, 0x80, 0xFC, 0x0D, 0xE0, 0xEF, 0x06, 0x78, 0x73, 0xC3, 0x1E, 0x30, 0xF1, 0x87, 0x98, 0x3D, 0xC1, 0xEC, 0x0F, 0xC0, 0x7E, 0x03, 0xE0, 0x1F, 0x00, 0xC0,
|
||||
/* 0xC9 */ 0x10, 0x40, 0xC4, 0x07, 0xE0, 0x1E, 0x0C, 0x03, 0xE0, 0x1F, 0x01, 0xF8, 0x0F, 0xC0, 0xDE, 0x0E, 0xF0, 0x67, 0x87, 0x3C, 0x31, 0xE3, 0x0F, 0x18, 0x79, 0x83, 0xDC, 0x1E, 0xC0, 0xFC, 0x07, 0xE0, 0x3E, 0x01, 0xF0, 0x0C,
|
||||
/* 0xCA */ 0xC0, 0x7C, 0x0E, 0xC1, 0xCC, 0x38, 0xC7, 0x0C, 0xE0, 0xDC, 0x0F, 0x80, 0xF0, 0x0F, 0x80, 0xDC, 0x0C, 0xE0, 0xC7, 0x0C, 0x30, 0xC3, 0x8C, 0x1C, 0xC0, 0xEC, 0x07,
|
||||
/* 0xCB */ 0x1F, 0xFC, 0x7F, 0xF1, 0x80, 0xC6, 0x03, 0x18, 0x0C, 0x60, 0x31, 0x80, 0xC6, 0x03, 0x18, 0x0C, 0x60, 0x31, 0x80, 0xC6, 0x03, 0x18, 0x0C, 0xC0, 0x33, 0x00, 0xDC, 0x03, 0xE0, 0x0F, 0x00, 0x30,
|
||||
/* 0xCC */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83,
|
||||
/* 0xCD */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0,
|
||||
/* 0xCE */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00,
|
||||
/* 0xCF */ 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0,
|
||||
/* 0xD0 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00,
|
||||
/* 0xD1 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0,
|
||||
/* 0xD2 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
|
||||
/* 0xD3 */ 0xC0, 0x1F, 0x01, 0xD8, 0x0C, 0xE0, 0xE3, 0x06, 0x1C, 0x70, 0x63, 0x03, 0xB8, 0x1D, 0x80, 0x7C, 0x03, 0xC0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x38, 0x03, 0x80, 0x1C, 0x01, 0xC0, 0x00,
|
||||
/* 0xD4 */ 0x00, 0xC0, 0x00, 0x30, 0x00, 0xFF, 0xC0, 0xFF, 0xFC, 0x78, 0xC7, 0x98, 0x30, 0x6E, 0x0C, 0x1F, 0x03, 0x03, 0xC0, 0xC0, 0xF0, 0x30, 0x3C, 0x0C, 0x0F, 0x83, 0x07, 0x60, 0xC1, 0x9E, 0x31, 0xE3, 0xFF, 0xF0, 0x3F, 0xF0, 0x00, 0xC0, 0x00, 0x30, 0x00,
|
||||
/* 0xD5 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70,
|
||||
/* 0xD6 */ 0xC0, 0x19, 0x80, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x01, 0x98, 0x03, 0x30, 0x06, 0x60, 0x0C, 0xC0, 0x19, 0x80, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x01, 0x98, 0x03, 0x30, 0x06, 0x60, 0x0C, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60,
|
||||
/* 0xD7 */ 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x37, 0xFF, 0x3F, 0xF0, 0x03, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03,
|
||||
/* 0xD8 */ 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/* 0xD9 */ 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0,
|
||||
/* 0xDA */ 0xFE, 0x00, 0x3F, 0x80, 0x00, 0x60, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x1F, 0xF8, 0x07, 0xFF, 0x01, 0x80, 0xE0, 0x60, 0x1C, 0x18, 0x03, 0x06, 0x00, 0xC1, 0x80, 0x30, 0x60, 0x1C, 0x18, 0x0E, 0x07, 0xFF, 0x01, 0xFF, 0x80,
|
||||
/* 0xDB */ 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0xFF, 0x83, 0xFF, 0xE1, 0xE0, 0x38, 0xF0, 0x0E, 0x78, 0x03, 0x3C, 0x01, 0x9E, 0x00, 0xCF, 0x00, 0xE7, 0x80, 0xE3, 0xFF, 0xE1, 0xFF, 0xE0, 0xC0,
|
||||
/* 0xDC */ 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x1F, 0xF8, 0xFF, 0xE6, 0x03, 0xB0, 0x0F, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0xF8, 0x0E, 0xFF, 0xE7, 0xFE, 0x00,
|
||||
/* 0xDD */ 0x0F, 0xC0, 0x7F, 0xE1, 0xC1, 0xE7, 0x01, 0xCC, 0x01, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x1F, 0xFE, 0x3F, 0xFC, 0x00, 0x38, 0x00, 0x7C, 0x00, 0xD8, 0x03, 0x98, 0x0E, 0x38, 0x3C, 0x3F, 0xF0, 0x1F, 0x80,
|
||||
/* 0xDE */ 0xC0, 0x3F, 0x06, 0x07, 0xFE, 0x30, 0x70, 0x39, 0x87, 0x00, 0xEC, 0x30, 0x03, 0x61, 0x80, 0x1B, 0x18, 0x00, 0x78, 0xC0, 0x03, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0xF1, 0x80, 0x07, 0x8C, 0x00, 0x3C, 0x70, 0x03, 0xE1, 0x80, 0x1B, 0x0E, 0x01, 0xD8, 0x38, 0x1C, 0xC0, 0xFF, 0xC6, 0x01, 0xF8, 0x00,
|
||||
/* 0xDF */ 0x0F, 0xFC, 0xFF, 0xF3, 0x00, 0xD8, 0x03, 0x60, 0x0D, 0x80, 0x36, 0x00, 0xCC, 0x03, 0x3F, 0xFC, 0x3F, 0xF0, 0x38, 0xC1, 0xC3, 0x0E, 0x0C, 0x70, 0x31, 0x80, 0xCE, 0x03, 0x70, 0x0F, 0x80, 0x30,
|
||||
/* 0xE0 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
|
||||
/* 0xE1 */ 0x00, 0xC0, 0x38, 0x3F, 0x1F, 0x87, 0x00, 0xC0, 0x17, 0xC7, 0xFC, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1F, 0x07, 0x71, 0xC7, 0xF0, 0x7C, 0x00,
|
||||
/* 0xE2 */ 0xFE, 0x3F, 0xEC, 0x3B, 0x06, 0xC1, 0xB0, 0xEF, 0xF3, 0x0E, 0xC0, 0xF0, 0x3C, 0x1F, 0xFE, 0xFF, 0x00,
|
||||
/* 0xE3 */ 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x00,
|
||||
/* 0xE4 */ 0x0F, 0xF0, 0x3F, 0xC0, 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x30, 0x60, 0xC1, 0x83, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x3C, 0x00, 0xC0,
|
||||
/* 0xE5 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0,
|
||||
/* 0xE6 */ 0xE1, 0x87, 0x71, 0x8E, 0x39, 0x9C, 0x1D, 0xB8, 0x0F, 0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0xF0, 0x1D, 0xB8, 0x39, 0x9C, 0x71, 0x8E, 0xE1, 0x87, 0xC1, 0x83,
|
||||
/* 0xE7 */ 0x3E, 0x7F, 0xB0, 0xE0, 0x30, 0x18, 0x78, 0x3C, 0x07, 0x01, 0xE0, 0xF8, 0xEF, 0xE3, 0xE0,
|
||||
/* 0xE8 */ 0xC0, 0xF8, 0x3F, 0x07, 0xE1, 0xFC, 0x37, 0x8C, 0xF3, 0x9E, 0x63, 0xD8, 0x7F, 0x0F, 0xC1, 0xF8, 0x3E, 0x06,
|
||||
/* 0xE9 */ 0x21, 0x86, 0x20, 0xFC, 0x0F, 0x0C, 0x0F, 0x83, 0xF0, 0x7E, 0x1F, 0xC3, 0x78, 0xCF, 0x39, 0xE6, 0x3D, 0x87, 0xF0, 0xFC, 0x1F, 0x83, 0xE0, 0x60,
|
||||
/* 0xEA */ 0xC1, 0xE1, 0xB1, 0x99, 0x8D, 0x87, 0x83, 0xC1, 0xF0, 0xDC, 0x67, 0x31, 0xD8, 0x7C, 0x18,
|
||||
/* 0xEB */ 0x3F, 0xCF, 0xF3, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xDC, 0x36, 0x0F, 0x83, 0xC0, 0xC0,
|
||||
/* 0xEC */ 0xE0, 0x7E, 0x07, 0xF0, 0xFF, 0x0F, 0xF0, 0xFD, 0x9B, 0xD9, 0xBD, 0xFB, 0xCF, 0x3C, 0xF3, 0xC6, 0x3C, 0x63, 0xC0, 0x30,
|
||||
/* 0xED */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0,
|
||||
/* 0xEE */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0,
|
||||
/* 0xEF */ 0xFF, 0xFF, 0xFC, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0,
|
||||
/* 0xF0 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 0xF1 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00,
|
||||
/* 0xF2 */ 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
/* 0xF3 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00,
|
||||
/* 0xF4 */ 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x0F, 0x67, 0x87, 0xFD, 0xF8, 0xC3, 0xE3, 0xB8, 0x78, 0x3E, 0x06, 0x03, 0xC0, 0xC0, 0x78, 0x18, 0x0F, 0x03, 0x01, 0xE0, 0x60, 0x3E, 0x1E, 0x0E, 0xC3, 0xE3, 0x9F, 0xFF, 0xE1, 0xF6, 0x78, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00,
|
||||
/* 0xF5 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0,
|
||||
/* 0xF6 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCF, 0xFF, 0xFF, 0xF0, 0x03, 0x00, 0x30,
|
||||
/* 0xF7 */ 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0xFE, 0xFF, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18,
|
||||
/* 0xF8 */ 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xFF, 0xFF, 0xFF, 0xFC,
|
||||
/* 0xF9 */ 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0x00, 0x03,
|
||||
/* 0xFA */ 0xFC, 0x03, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x0F, 0xF0, 0x3F, 0xE0, 0xC1, 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC1, 0xC3, 0xFE, 0x0F, 0xF0,
|
||||
/* 0xFB */ 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xFF, 0x0F, 0xFE, 0x3C, 0x1C, 0xF0, 0x33, 0xC0, 0xCF, 0x03, 0x3C, 0x1C, 0xFF, 0xE3, 0xFF, 0x0C,
|
||||
/* 0xFC */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0x3F, 0xEC, 0x1F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0xFE, 0xFF, 0x00,
|
||||
/* 0xFD */ 0x3F, 0x0F, 0xF1, 0x87, 0x60, 0x60, 0x0E, 0x3F, 0xC7, 0xF8, 0x03, 0x00, 0xD8, 0x1B, 0x87, 0x3F, 0xC3, 0xF0,
|
||||
/* 0xFE */ 0xC0, 0xF8, 0xC1, 0xFC, 0xC3, 0x8E, 0xC7, 0x07, 0xC6, 0x03, 0xFE, 0x03, 0xFE, 0x03, 0xC6, 0x03, 0xC6, 0x03, 0xC7, 0x06, 0xC3, 0x8E, 0xC1, 0xFC, 0xC0, 0xF8,
|
||||
/* 0xFF */ 0x1F, 0xCF, 0xF7, 0x0D, 0x83, 0x60, 0xD8, 0x33, 0xFC, 0x7F, 0x0C, 0xC6, 0x33, 0x0D, 0x83, 0xC0, 0xC0,
|
||||
};
|
||||
|
||||
const GFXglyph FreeSans12pt_Win1251Glyphs[] PROGMEM = {
|
||||
/* 0x01 */ { 0, 19, 20, 21, 1, -17 },
|
||||
/* 0x02 */ { 48, 19, 20, 21, 1, -17 },
|
||||
/* 0x03 */ { 96, 21, 20, 23, 1, -17 },
|
||||
/* 0x04 */ { 149, 21, 20, 23, 1, -17 },
|
||||
/* 0x05 */ { 202, 20, 20, 22, 1, -17 },
|
||||
/* 0x06 */ { 252, 20, 20, 22, 1, -17 },
|
||||
/* 0x07 */ { 302, 0, 0, 8, 0, 0 },
|
||||
/* 0x08 */ { 302, 23, 20, 25, 1, -17 },
|
||||
/* 0x09 */ { 360, 23, 16, 25, 1, -16 },
|
||||
/* 0x0A */ { 406, 0, 0, 8, 0, 0 },
|
||||
/* 0x0B */ { 406, 21, 20, 23, 1, -17 },
|
||||
/* 0x0C */ { 459, 19, 18, 21, 1, -15 },
|
||||
/* 0x0D */ { 502, 0, 0, 8, 0, 0 },
|
||||
/* 0x0E */ { 502, 20, 20, 22, 1, -17 },
|
||||
/* 0x0F */ { 552, 21, 21, 23, 1, -18 },
|
||||
/* 0x10 */ { 608, 19, 20, 21, 1, -17 },
|
||||
/* 0x11 */ { 656, 21, 20, 23, 1, -17 },
|
||||
/* 0x12 */ { 709, 20, 20, 22, 1, -17 },
|
||||
/* 0x13 */ { 759, 21, 20, 23, 1, -17 },
|
||||
/* 0x14 */ { 812, 21, 20, 23, 1, -17 },
|
||||
/* 0x15 */ { 865, 22, 20, 24, 1, -17 },
|
||||
/* 0x16 */ { 920, 16, 20, 18, 1, -17 },
|
||||
/* 0x17 */ { 960, 21, 20, 23, 1, -17 },
|
||||
/* 0x18 */ { 1013, 23, 20, 25, 1, -17 },
|
||||
/* 0x19 */ { 1071, 21, 20, 23, 1, -17 },
|
||||
/* 0x1A */ { 1124, 15, 19, 17, 1, -16 },
|
||||
/* 0x1B */ { 1160, 24, 21, 26, 1, -18 },
|
||||
/* 0x1C */ { 1223, 21, 20, 23, 1, -17 },
|
||||
/* 0x1D */ { 1276, 21, 21, 23, 1, -18 },
|
||||
/* 0x1E */ { 1332, 20, 20, 22, 1, -17 },
|
||||
/* 0x1F */ { 1382, 15, 20, 17, 1, -17 },
|
||||
/* ' ' 0x20 */ { 1420, 0, 0, 6, 0, 0 },
|
||||
/* '!' 0x21 */ { 1420, 2, 18, 8, 3, -16 },
|
||||
/* '"' 0x22 */ { 1425, 6, 6, 8, 1, -15 },
|
||||
/* '#' 0x23 */ { 1430, 13, 16, 13, 0, -14 },
|
||||
/* '$' 0x24 */ { 1456, 11, 20, 13, 1, -16 },
|
||||
/* '%' 0x25 */ { 1484, 20, 17, 21, 1, -15 },
|
||||
/* '&' 0x26 */ { 1527, 14, 17, 16, 1, -15 },
|
||||
/* ''' 0x27 */ { 1557, 2, 6, 5, 1, -15 },
|
||||
/* '(' 0x28 */ { 1559, 5, 23, 8, 2, -16 },
|
||||
/* ')' 0x29 */ { 1574, 5, 23, 8, 1, -16 },
|
||||
/* '*' 0x2A */ { 1589, 7, 7, 9, 1, -16 },
|
||||
/* '+' 0x2B */ { 1596, 10, 11, 14, 2, -9 },
|
||||
/* ',' 0x2C */ { 1610, 2, 6, 7, 2, 0 },
|
||||
/* '-' 0x2D */ { 1612, 6, 2, 8, 1, -6 },
|
||||
/* '.' 0x2E */ { 1614, 2, 2, 6, 2, 0 },
|
||||
/* '/' 0x2F */ { 1615, 7, 18, 7, 0, -16 },
|
||||
/* '0' 0x30 */ { 1631, 11, 17, 13, 1, -15 },
|
||||
/* '1' 0x31 */ { 1655, 5, 17, 13, 3, -15 },
|
||||
/* '2' 0x32 */ { 1666, 11, 17, 13, 1, -15 },
|
||||
/* '3' 0x33 */ { 1690, 11, 17, 13, 1, -15 },
|
||||
/* '4' 0x34 */ { 1714, 11, 17, 13, 1, -15 },
|
||||
/* '5' 0x35 */ { 1738, 11, 17, 13, 1, -15 },
|
||||
/* '6' 0x36 */ { 1762, 11, 17, 13, 1, -15 },
|
||||
/* '7' 0x37 */ { 1786, 11, 17, 13, 1, -15 },
|
||||
/* '8' 0x38 */ { 1810, 11, 17, 13, 1, -15 },
|
||||
/* '9' 0x39 */ { 1834, 11, 17, 13, 1, -15 },
|
||||
/* ':' 0x3A */ { 1858, 2, 13, 6, 2, -11 },
|
||||
/* ';' 0x3B */ { 1862, 2, 16, 6, 2, -10 },
|
||||
/* '<' 0x3C */ { 1866, 12, 11, 14, 1, -9 },
|
||||
/* '=' 0x3D */ { 1883, 12, 6, 14, 1, -7 },
|
||||
/* '>' 0x3E */ { 1892, 12, 11, 14, 1, -9 },
|
||||
/* '?' 0x3F */ { 1909, 10, 18, 13, 2, -16 },
|
||||
/* '@' 0x40 */ { 1932, 22, 21, 24, 1, -16 },
|
||||
/* 'A' 0x41 */ { 1990, 14, 18, 16, 1, -16 },
|
||||
/* 'B' 0x42 */ { 2022, 13, 18, 16, 2, -16 },
|
||||
/* 'C' 0x43 */ { 2052, 15, 18, 17, 1, -16 },
|
||||
/* 'D' 0x44 */ { 2086, 14, 18, 17, 2, -16 },
|
||||
/* 'E' 0x45 */ { 2118, 12, 18, 15, 2, -16 },
|
||||
/* 'F' 0x46 */ { 2145, 11, 18, 14, 2, -16 },
|
||||
/* 'G' 0x47 */ { 2170, 16, 18, 18, 1, -16 },
|
||||
/* 'H' 0x48 */ { 2206, 13, 18, 17, 2, -16 },
|
||||
/* 'I' 0x49 */ { 2236, 2, 18, 7, 2, -16 },
|
||||
/* 'J' 0x4A */ { 2241, 9, 18, 13, 1, -16 },
|
||||
/* 'K' 0x4B */ { 2262, 13, 18, 16, 2, -16 },
|
||||
/* 'L' 0x4C */ { 2292, 10, 18, 14, 2, -16 },
|
||||
/* 'M' 0x4D */ { 2315, 16, 18, 20, 2, -16 },
|
||||
/* 'N' 0x4E */ { 2351, 13, 18, 18, 2, -16 },
|
||||
/* 'O' 0x4F */ { 2381, 17, 18, 19, 1, -16 },
|
||||
/* 'P' 0x50 */ { 2420, 12, 18, 16, 2, -16 },
|
||||
/* 'Q' 0x51 */ { 2447, 17, 19, 19, 1, -16 },
|
||||
/* 'R' 0x52 */ { 2488, 14, 18, 17, 2, -16 },
|
||||
/* 'S' 0x53 */ { 2520, 14, 18, 16, 1, -16 },
|
||||
/* 'T' 0x54 */ { 2552, 12, 18, 15, 1, -16 },
|
||||
/* 'U' 0x55 */ { 2579, 13, 18, 17, 2, -16 },
|
||||
/* 'V' 0x56 */ { 2609, 14, 18, 15, 1, -16 },
|
||||
/* 'W' 0x57 */ { 2641, 22, 18, 22, 0, -16 },
|
||||
/* 'X' 0x58 */ { 2691, 14, 18, 16, 1, -16 },
|
||||
/* 'Y' 0x59 */ { 2723, 14, 18, 16, 1, -16 },
|
||||
/* 'Z' 0x5A */ { 2755, 13, 18, 15, 1, -16 },
|
||||
/* '[' 0x5B */ { 2785, 4, 23, 7, 2, -16 },
|
||||
/* '\' 0x5C */ { 2797, 7, 18, 7, 0, -16 },
|
||||
/* ']' 0x5D */ { 2813, 4, 23, 7, 1, -16 },
|
||||
/* '^' 0x5E */ { 2825, 9, 9, 11, 1, -15 },
|
||||
/* '_' 0x5F */ { 2836, 15, 1, 13, -1, 5 },
|
||||
/* '`' 0x60 */ { 2838, 5, 4, 6, 1, -16 },
|
||||
/* 'a' 0x61 */ { 2841, 12, 13, 13, 1, -11 },
|
||||
/* 'b' 0x62 */ { 2861, 12, 18, 13, 1, -16 },
|
||||
/* 'c' 0x63 */ { 2888, 10, 13, 12, 1, -11 },
|
||||
/* 'd' 0x64 */ { 2905, 11, 18, 13, 1, -16 },
|
||||
/* 'e' 0x65 */ { 2930, 11, 13, 13, 1, -11 },
|
||||
/* 'f' 0x66 */ { 2948, 5, 18, 7, 1, -16 },
|
||||
/* 'g' 0x67 */ { 2960, 11, 18, 13, 1, -11 },
|
||||
/* 'h' 0x68 */ { 2985, 10, 18, 13, 1, -16 },
|
||||
/* 'i' 0x69 */ { 3008, 2, 18, 5, 2, -16 },
|
||||
/* 'j' 0x6A */ { 3013, 4, 23, 6, 0, -16 },
|
||||
/* 'k' 0x6B */ { 3025, 10, 18, 12, 1, -16 },
|
||||
/* 'l' 0x6C */ { 3048, 2, 18, 5, 1, -16 },
|
||||
/* 'm' 0x6D */ { 3053, 17, 13, 19, 1, -11 },
|
||||
/* 'n' 0x6E */ { 3081, 10, 13, 13, 1, -11 },
|
||||
/* 'o' 0x6F */ { 3098, 11, 13, 13, 1, -11 },
|
||||
/* 'p' 0x70 */ { 3116, 12, 17, 13, 1, -11 },
|
||||
/* 'q' 0x71 */ { 3142, 11, 17, 13, 1, -11 },
|
||||
/* 'r' 0x72 */ { 3166, 6, 13, 8, 1, -11 },
|
||||
/* 's' 0x73 */ { 3176, 10, 13, 12, 1, -11 },
|
||||
/* 't' 0x74 */ { 3193, 5, 16, 7, 1, -14 },
|
||||
/* 'u' 0x75 */ { 3203, 10, 13, 13, 1, -11 },
|
||||
/* 'v' 0x76 */ { 3220, 11, 13, 12, 0, -11 },
|
||||
/* 'w' 0x77 */ { 3238, 17, 13, 17, 0, -11 },
|
||||
/* 'x' 0x78 */ { 3266, 10, 13, 11, 1, -11 },
|
||||
/* 'y' 0x79 */ { 3283, 11, 18, 11, 0, -11 },
|
||||
/* 'z' 0x7A */ { 3308, 10, 13, 12, 1, -11 },
|
||||
/* '{' 0x7B */ { 3325, 5, 23, 8, 1, -16 },
|
||||
/* '|' 0x7C */ { 3340, 2, 23, 6, 2, -16 },
|
||||
/* '}' 0x7D */ { 3346, 5, 23, 8, 2, -16 },
|
||||
/* '~' 0x7E */ { 3361, 10, 5, 12, 1, -9 },
|
||||
/* 0x7F */ { 3368, 0, 0, 0, 0, 0 },
|
||||
/* 0x80 */ { 3368, 16, 22, 18, 1, -18 },
|
||||
/* 0x81 */ { 3412, 11, 22, 14, 2, -22 },
|
||||
/* 0x82 */ { 3443, 2, 5, 6, 2, -2 },
|
||||
/* 0x83 */ { 3445, 7, 18, 9, 1, -18 },
|
||||
/* 0x84 */ { 3461, 6, 5, 10, 2, -2 },
|
||||
/* 0x85 */ { 3465, 12, 2, 16, 2, -2 },
|
||||
/* 0x86 */ { 3468, 10, 21, 13, 2, -17 },
|
||||
/* 0x87 */ { 3495, 10, 20, 13, 2, -17 },
|
||||
/* 0x88 */ { 3520, 14, 17, 16, 1, -17 },
|
||||
/* 0x89 */ { 3550, 23, 18, 24, 0, -18 },
|
||||
/* 0x8A */ { 3602, 23, 18, 24, 0, -18 },
|
||||
/* 0x8B */ { 3654, 3, 8, 6, 1, -11 },
|
||||
/* 0x8C */ { 3657, 21, 18, 24, 2, -18 },
|
||||
/* 0x8D */ { 3705, 12, 22, 15, 2, -22 },
|
||||
/* 0x8E */ { 3738, 16, 18, 18, 1, -18 },
|
||||
/* 0x8F */ { 3774, 13, 21, 17, 2, -18 },
|
||||
/* 0x90 */ { 3809, 12, 22, 14, 0, -18 },
|
||||
/* 0x91 */ { 3842, 2, 6, 6, 2, -18 },
|
||||
/* 0x92 */ { 3844, 2, 6, 6, 2, -18 },
|
||||
/* 0x93 */ { 3846, 6, 6, 10, 2, -18 },
|
||||
/* 0x94 */ { 3851, 6, 6, 10, 2, -18 },
|
||||
/* 0x95 */ { 3856, 6, 6, 10, 2, -11 },
|
||||
/* 0x96 */ { 3861, 10, 2, 12, 1, -8 },
|
||||
/* 0x97 */ { 3864, 22, 2, 24, 1, -8 },
|
||||
/* 0x98 */ { 3870, 0, 0, 8, 0, 0 },
|
||||
/* 0x99 */ { 3870, 22, 13, 24, 2, -18 },
|
||||
/* 0x9A */ { 3906, 17, 13, 19, 1, -13 },
|
||||
/* 0x9B */ { 3934, 3, 8, 6, 2, -10 },
|
||||
/* 0x9C */ { 3937, 18, 13, 20, 1, -13 },
|
||||
/* 0x9D */ { 3967, 9, 18, 12, 1, -18 },
|
||||
/* 0x9E */ { 3988, 11, 18, 14, 1, -18 },
|
||||
/* 0x9F */ { 4013, 10, 15, 13, 1, -13 },
|
||||
/* 0xA0 */ { 4032, 0, 0, 7, 0, 0 },
|
||||
/* 0xA1 */ { 4032, 13, 22, 15, 1, -22 },
|
||||
/* 0xA2 */ { 4068, 11, 22, 11, 0, -17 },
|
||||
/* 0xA3 */ { 4099, 9, 18, 13, 1, -18 },
|
||||
/* 0xA4 */ { 4120, 9, 9, 13, 2, -13 },
|
||||
/* 0xA5 */ { 4131, 11, 20, 14, 2, -20 },
|
||||
/* 0xA6 */ { 4159, 2, 23, 6, 2, -18 },
|
||||
/* 0xA7 */ { 4165, 11, 23, 13, 1, -18 },
|
||||
/* 0xA8 */ { 4197, 12, 21, 15, 2, -21 },
|
||||
/* 0xA9 */ { 4229, 18, 17, 19, 1, -17 },
|
||||
/* 0xAA */ { 4268, 15, 18, 17, 1, -18 },
|
||||
/* 0xAB */ { 4302, 8, 8, 12, 2, -11 },
|
||||
/* 0xAC */ { 4310, 12, 6, 14, 1, -9 },
|
||||
/* 0xAD */ { 4319, 6, 2, 8, 1, -8 },
|
||||
/* 0xAE */ { 4321, 18, 17, 19, 1, -17 },
|
||||
/* 0xAF */ { 4360, 7, 21, 7, 0, -21 },
|
||||
/* 0xB0 */ { 4379, 7, 8, 15, 4, -17 },
|
||||
/* 0xB1 */ { 4386, 12, 15, 14, 1, -15 },
|
||||
/* 0xB2 */ { 4409, 2, 18, 7, 2, -18 },
|
||||
/* 0xB3 */ { 4414, 2, 18, 5, 2, -18 },
|
||||
/* 0xB4 */ { 4419, 8, 15, 9, 1, -15 },
|
||||
/* 0xB5 */ { 4434, 12, 17, 13, 2, -13 },
|
||||
/* 0xB6 */ { 4460, 11, 21, 13, 2, -18 },
|
||||
/* 0xB7 */ { 4489, 2, 2, 6, 2, -8 },
|
||||
/* 0xB8 */ { 4490, 11, 17, 13, 1, -17 },
|
||||
/* 0xB9 */ { 4514, 19, 18, 22, 2, -18 },
|
||||
/* 0xBA */ { 4557, 11, 13, 12, 0, -13 },
|
||||
/* 0xBB */ { 4575, 8, 8, 12, 2, -10 },
|
||||
/* 0xBC */ { 4583, 4, 23, 6, 0, -18 },
|
||||
/* 0xBD */ { 4595, 14, 18, 16, 1, -18 },
|
||||
/* 0xBE */ { 4627, 10, 13, 12, 1, -13 },
|
||||
/* 0xBF */ { 4644, 6, 17, 6, 0, -17 },
|
||||
/* 0xC0 */ { 4657, 14, 18, 16, 1, -18 },
|
||||
/* 0xC1 */ { 4689, 13, 18, 16, 2, -18 },
|
||||
/* 0xC2 */ { 4719, 13, 18, 16, 2, -18 },
|
||||
/* 0xC3 */ { 4749, 11, 18, 14, 2, -18 },
|
||||
/* 0xC4 */ { 4774, 18, 21, 19, 1, -18 },
|
||||
/* 0xC5 */ { 4822, 12, 18, 15, 2, -18 },
|
||||
/* 0xC6 */ { 4849, 20, 18, 22, 1, -18 },
|
||||
/* 0xC7 */ { 4894, 13, 18, 16, 1, -18 },
|
||||
/* 0xC8 */ { 4924, 13, 18, 18, 2, -18 },
|
||||
/* 0xC9 */ { 4954, 13, 22, 18, 2, -22 },
|
||||
/* 0xCA */ { 4990, 12, 18, 15, 2, -18 },
|
||||
/* 0xCB */ { 5017, 14, 18, 16, 0, -18 },
|
||||
/* 0xCC */ { 5049, 16, 18, 20, 2, -18 },
|
||||
/* 0xCD */ { 5085, 13, 18, 17, 2, -18 },
|
||||
/* 0xCE */ { 5115, 17, 18, 19, 1, -18 },
|
||||
/* 0xCF */ { 5154, 13, 18, 17, 2, -18 },
|
||||
/* 0xD0 */ { 5184, 12, 18, 16, 2, -18 },
|
||||
/* 0xD1 */ { 5211, 15, 18, 17, 1, -18 },
|
||||
/* 0xD2 */ { 5245, 12, 18, 15, 1, -18 },
|
||||
/* 0xD3 */ { 5272, 13, 18, 15, 1, -18 },
|
||||
/* 0xD4 */ { 5302, 18, 18, 20, 1, -18 },
|
||||
/* 0xD5 */ { 5343, 14, 18, 16, 1, -18 },
|
||||
/* 0xD6 */ { 5375, 15, 21, 18, 2, -18 },
|
||||
/* 0xD7 */ { 5415, 12, 18, 15, 1, -18 },
|
||||
/* 0xD8 */ { 5442, 16, 18, 20, 2, -18 },
|
||||
/* 0xD9 */ { 5478, 18, 21, 20, 2, -18 },
|
||||
/* 0xDA */ { 5526, 18, 18, 20, 1, -18 },
|
||||
/* 0xDB */ { 5567, 17, 18, 21, 2, -18 },
|
||||
/* 0xDC */ { 5606, 13, 18, 16, 2, -18 },
|
||||
/* 0xDD */ { 5636, 15, 18, 17, 1, -18 },
|
||||
/* 0xDE */ { 5670, 21, 18, 24, 2, -18 },
|
||||
/* 0xDF */ { 5718, 14, 18, 16, 0, -18 },
|
||||
/* 0xE0 */ { 5750, 12, 13, 13, 1, -13 },
|
||||
/* 0xE1 */ { 5770, 11, 19, 13, 1, -19 },
|
||||
/* 0xE2 */ { 5797, 10, 13, 12, 1, -13 },
|
||||
/* 0xE3 */ { 5814, 7, 13, 9, 1, -13 },
|
||||
/* 0xE4 */ { 5826, 14, 15, 14, 0, -13 },
|
||||
/* 0xE5 */ { 5853, 11, 13, 13, 1, -13 },
|
||||
/* 0xE6 */ { 5871, 16, 13, 18, 1, -13 },
|
||||
/* 0xE7 */ { 5897, 9, 13, 12, 1, -13 },
|
||||
/* 0xE8 */ { 5912, 11, 13, 13, 1, -13 },
|
||||
/* 0xE9 */ { 5930, 11, 17, 13, 1, -17 },
|
||||
/* 0xEA */ { 5954, 9, 13, 12, 1, -13 },
|
||||
/* 0xEB */ { 5969, 10, 13, 12, 0, -13 },
|
||||
/* 0xEC */ { 5986, 12, 13, 14, 1, -13 },
|
||||
/* 0xED */ { 6006, 10, 13, 13, 1, -13 },
|
||||
/* 0xEE */ { 6023, 11, 13, 13, 1, -13 },
|
||||
/* 0xEF */ { 6041, 10, 13, 13, 1, -13 },
|
||||
/* 0xF0 */ { 6058, 12, 17, 13, 1, -13 },
|
||||
/* 0xF1 */ { 6084, 10, 13, 12, 1, -13 },
|
||||
/* 0xF2 */ { 6101, 8, 13, 10, 1, -13 },
|
||||
/* 0xF3 */ { 6114, 11, 18, 11, 0, -13 },
|
||||
/* 0xF4 */ { 6139, 19, 20, 20, 1, -16 },
|
||||
/* 0xF5 */ { 6187, 10, 13, 11, 1, -13 },
|
||||
/* 0xF6 */ { 6204, 12, 15, 13, 1, -13 },
|
||||
/* 0xF7 */ { 6227, 9, 13, 12, 1, -13 },
|
||||
/* 0xF8 */ { 6242, 14, 13, 16, 1, -13 },
|
||||
/* 0xF9 */ { 6265, 16, 15, 17, 1, -13 },
|
||||
/* 0xFA */ { 6295, 14, 13, 15, 1, -13 },
|
||||
/* 0xFB */ { 6318, 14, 13, 16, 1, -13 },
|
||||
/* 0xFC */ { 6341, 10, 13, 12, 1, -13 },
|
||||
/* 0xFD */ { 6358, 11, 13, 12, 1, -13 },
|
||||
/* 0xFE */ { 6376, 16, 13, 18, 1, -13 },
|
||||
/* 0xFF */ { 6402, 10, 13, 13, 1, -13 },
|
||||
};
|
||||
|
||||
const GFXfont FreeSans12pt_Win1251 PROGMEM = {
|
||||
(uint8_t*)FreeSans12pt_Win1251Bitmaps,
|
||||
(GFXglyph*)FreeSans12pt_Win1251Glyphs,
|
||||
0x01, 0xFF, 19
|
||||
};
|
||||
@@ -0,0 +1,527 @@
|
||||
// trunk-ignore-all(clang-format)
|
||||
#pragma once
|
||||
/* PROPERTIES
|
||||
|
||||
FONT_NAME FreeSans12pt_Win1252
|
||||
*/
|
||||
const uint8_t FreeSans12pt_Win1252Bitmaps[] PROGMEM = {
|
||||
/* 0x01 */ 0x00, 0x30, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x24, 0x00, 0x04, 0x80, 0x01, 0x90, 0x00, 0x62, 0x00, 0x30, 0xFE, 0x04, 0x10, 0x5F, 0x02, 0x0B, 0x00, 0x7F, 0xE0, 0x0C, 0x1C, 0x02, 0x83, 0x81, 0x9F, 0xF0, 0x02, 0x1E, 0x00, 0x41, 0xC0, 0x0E, 0x7F, 0x81, 0x78, 0x18, 0x62, 0x00, 0xFF, 0xC0,
|
||||
/* 0x02 */ 0x00, 0xFF, 0x80, 0x61, 0x13, 0xF0, 0x62, 0x60, 0x07, 0xFC, 0x00, 0x83, 0x80, 0x10, 0xF0, 0x33, 0xF6, 0x01, 0x41, 0xC0, 0x18, 0x38, 0x03, 0xFF, 0xE0, 0x47, 0x02, 0x08, 0x20, 0x61, 0xC4, 0x06, 0x17, 0x00, 0x22, 0x00, 0x02, 0x40, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x3C, 0x00,
|
||||
/* 0x03 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x04, 0x08, 0x48, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x08, 0x10, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA1, 0x81, 0x8D, 0x87, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x04 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x10, 0x02, 0x48, 0xE0, 0x61, 0xC1, 0xCC, 0x0E, 0x78, 0x1C, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xFC, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x05 */ 0x00, 0x18, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0xF4, 0x08, 0x12, 0x23, 0xC1, 0x91, 0x2C, 0x1C, 0x8A, 0xC3, 0x64, 0x64, 0x13, 0x22, 0x41, 0x98, 0x26, 0x2C, 0xC4, 0x22, 0x60, 0x42, 0x13, 0x04, 0x30, 0x80, 0x61, 0xA4, 0x02, 0x18, 0x20, 0x03, 0x41, 0x00, 0x20, 0x08, 0x02, 0x00, 0x60, 0x40, 0x03, 0xF8,
|
||||
/* 0x06 */ 0x00, 0x10, 0x00, 0x03, 0x00, 0x1C, 0x48, 0x00, 0xB4, 0x80, 0x09, 0xF9, 0xC0, 0xE0, 0xE4, 0x0C, 0x02, 0x8F, 0x80, 0x38, 0x88, 0x01, 0x0D, 0x00, 0x18, 0x30, 0x01, 0x60, 0x80, 0x13, 0x18, 0x03, 0xF2, 0xC0, 0x20, 0x26, 0x06, 0x07, 0xFF, 0xA0, 0x02, 0x39, 0x00, 0x14, 0x70, 0x01, 0xC3, 0x00, 0x18, 0x00,
|
||||
/* 0x07 */
|
||||
/* 0x08 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x10, 0x37, 0xE2, 0x61, 0x00, 0x0C, 0xC6, 0x10, 0x98, 0x0C, 0x63, 0x00, 0x00, 0xC6, 0x00,
|
||||
/* 0x09 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x00, 0x37, 0xE0,
|
||||
/* 0x0A */
|
||||
/* 0x0B */ 0x1F, 0x07, 0xC1, 0x86, 0x41, 0x10, 0x0C, 0x04, 0x80, 0x40, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x88, 0x00, 0x04, 0x40, 0x00, 0x41, 0x00, 0x02, 0x04, 0x00, 0x20, 0x20, 0x02, 0x00, 0x80, 0x20, 0x02, 0x02, 0x00, 0x08, 0x20, 0x00, 0x22, 0x00, 0x00, 0xE0, 0x00,
|
||||
/* 0x0C */ 0x01, 0x00, 0x00, 0x38, 0x00, 0x04, 0xC0, 0x01, 0x08, 0x00, 0x18, 0x80, 0x1C, 0x10, 0x02, 0x07, 0x80, 0x81, 0x10, 0x1F, 0xC2, 0x02, 0x00, 0x60, 0x80, 0x1A, 0x20, 0x1C, 0x42, 0x1C, 0x08, 0xFE, 0x03, 0xA0, 0x01, 0x8C, 0x01, 0xC1, 0x43, 0xD0, 0x27, 0x81, 0xF8,
|
||||
/* 0x0D */
|
||||
/* 0x0E */ 0x00, 0xE0, 0x00, 0x11, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x00, 0x03, 0xF8, 0x00, 0x60, 0x60, 0x09, 0x02, 0x00, 0xA0, 0x10, 0x16, 0x01, 0x01, 0x40, 0x10, 0x10, 0x01, 0x01, 0x00, 0x08, 0x10, 0x00, 0x82, 0x1F, 0x08, 0x3F, 0x90, 0x44, 0x00, 0x06, 0xBF, 0xFF, 0xAF, 0xF0, 0xFF, 0xFF, 0x0F, 0xE3, 0xFB, 0xFC,
|
||||
/* 0x0F */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x40, 0x12, 0x34, 0x00, 0x69, 0x40, 0x01, 0x49, 0xE0, 0xF1, 0xCD, 0x06, 0x8E, 0x28, 0x14, 0x71, 0x40, 0xA3, 0x8B, 0xFD, 0x14, 0x50, 0x68, 0xA2, 0x81, 0x4D, 0x97, 0xFA, 0x44, 0xBF, 0xD6, 0x31, 0x02, 0xE0, 0xC8, 0x16, 0x08, 0x61, 0x08, 0x21, 0xF0, 0x80, 0xF8, 0x78, 0x00,
|
||||
/* 0x10 */ 0x00, 0xF0, 0x00, 0x3A, 0x00, 0x07, 0xC0, 0x00, 0xA8, 0x00, 0x1F, 0x00, 0x02, 0xB0, 0x00, 0x52, 0x00, 0x0A, 0x40, 0x02, 0x48, 0x00, 0x49, 0x00, 0x09, 0x30, 0x01, 0x22, 0x01, 0xC4, 0x70, 0xF0, 0x85, 0xE1, 0x10, 0x88, 0x37, 0x20, 0x03, 0x9C, 0x00, 0x37, 0x00, 0x06, 0x40, 0x01, 0x86, 0x00,
|
||||
/* 0x11 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x60, 0x02, 0x36, 0x00, 0x09, 0x04, 0x0C, 0x48, 0x60, 0xC1, 0xC3, 0x0F, 0x0E, 0x00, 0x08, 0x70, 0x00, 0x23, 0x80, 0x63, 0x84, 0x01, 0x9F, 0x20, 0x0C, 0xFD, 0x80, 0x27, 0xE4, 0x03, 0x3F, 0x30, 0x33, 0xE0, 0xC0, 0x00, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x12 */ 0x00, 0xC2, 0x00, 0x1C, 0x24, 0x02, 0x18, 0x60, 0x64, 0x02, 0x02, 0x40, 0x20, 0x00, 0xF2, 0x03, 0x89, 0xE0, 0x7C, 0x80, 0x0E, 0x25, 0x80, 0xE1, 0x00, 0x1A, 0x08, 0x71, 0xB0, 0xC4, 0x39, 0x84, 0xC2, 0xCC, 0x40, 0x76, 0x7C, 0x05, 0xBB, 0x80, 0x4C, 0xE0, 0x0A, 0x78, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x00,
|
||||
/* 0x13 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x60, 0xC1, 0xC6, 0xC9, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xF8, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x14 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x20, 0x22, 0x33, 0x01, 0x89, 0x20, 0x02, 0x48, 0x60, 0xE1, 0xC8, 0x80, 0x8E, 0x46, 0x46, 0x72, 0x32, 0x33, 0x9F, 0x9F, 0x94, 0x78, 0x78, 0xA0, 0x00, 0x0D, 0x80, 0x00, 0x44, 0x0E, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x15 */ 0x03, 0xFC, 0x20, 0x38, 0x1C, 0x81, 0x80, 0x1D, 0x08, 0x00, 0x32, 0x60, 0x00, 0x89, 0x00, 0x02, 0x18, 0x00, 0x08, 0x61, 0xC3, 0x22, 0x8D, 0x93, 0x72, 0x00, 0x00, 0x48, 0x00, 0x01, 0x20, 0x00, 0x04, 0x9F, 0xFF, 0x92, 0x60, 0x0E, 0x44, 0xFF, 0xF2, 0x11, 0xC3, 0x88, 0x21, 0xF8, 0x40, 0x40, 0x02, 0x00, 0xC0, 0x30, 0x00, 0xFF, 0x00,
|
||||
/* 0x16 */ 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xF0, 0x03, 0xF0, 0x27, 0xF0, 0x6F, 0x70, 0x6E, 0x60, 0xFC, 0x60, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xF4, 0x1F, 0xF4, 0x1F, 0xF0, 0x0E, 0x70, 0x0E, 0x30, 0x1C, 0x38, 0x38, 0x0F, 0xF0,
|
||||
/* 0x17 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x00, 0x21, 0xC0, 0x02, 0x8E, 0x20, 0xF4, 0x70, 0x84, 0x11, 0x82, 0x40, 0x84, 0x01, 0x03, 0x20, 0x0F, 0x85, 0x80, 0x03, 0x04, 0x00, 0x04, 0x30, 0x78, 0x10, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x18 */ 0x00, 0xFC, 0x00, 0x02, 0x06, 0x00, 0x08, 0x24, 0x00, 0x21, 0xA4, 0x00, 0x4C, 0x48, 0x00, 0xA0, 0x50, 0x01, 0x92, 0x60, 0x03, 0x24, 0xC0, 0x06, 0x01, 0x81, 0x28, 0x03, 0x49, 0x6C, 0xC4, 0xAD, 0xD8, 0x16, 0xA4, 0xCC, 0xC4, 0x44, 0x86, 0x13, 0x05, 0x00, 0x28, 0x0A, 0x00, 0x50, 0x14, 0x00, 0x90, 0x48, 0x01, 0x20, 0x90, 0x02, 0x41, 0x20, 0x00, 0x00,
|
||||
/* 0x19 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x49, 0xC3, 0x81, 0xC0, 0x00, 0x0E, 0x78, 0xF0, 0x77, 0xEF, 0xC3, 0xA7, 0x4E, 0x15, 0x0A, 0x10, 0xA7, 0x8F, 0x0D, 0x80, 0x00, 0x44, 0x00, 0x06, 0x33, 0xF0, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x1A */ 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0C, 0x3E, 0x18, 0x82, 0x32, 0x02, 0x64, 0x04, 0xC8, 0x09, 0x80, 0x23, 0x00, 0x86, 0x02, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x81, 0x80, 0x03, 0x00, 0x07, 0xFF, 0xF8,
|
||||
/* 0x1B */ 0x00, 0xFE, 0x00, 0x03, 0x81, 0x80, 0x04, 0x00, 0x60, 0x08, 0x00, 0x30, 0x10, 0x00, 0x10, 0x30, 0x07, 0x88, 0x23, 0xC8, 0x08, 0x22, 0x00, 0x04, 0x60, 0x00, 0x44, 0x60, 0x00, 0x84, 0x63, 0x03, 0x04, 0x61, 0xFC, 0x04, 0x6B, 0x00, 0x9E, 0xA5, 0x01, 0x6A, 0xD5, 0x01, 0x43, 0xA8, 0x81, 0x05, 0xD0, 0x82, 0x0A, 0xA0, 0x82, 0x05, 0xC0, 0x82, 0x02, 0x61, 0xFF, 0x0C, 0x1E, 0x00, 0xF0,
|
||||
/* 0x1C */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x30, 0x02, 0x32, 0x00, 0x09, 0x00, 0x00, 0x48, 0x20, 0x61, 0xC3, 0x84, 0x0E, 0x1C, 0x78, 0x70, 0x40, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA0, 0x03, 0x0D, 0x83, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
|
||||
/* 0x1D */ 0x01, 0xFE, 0x00, 0x3A, 0x1C, 0x03, 0x00, 0x30, 0x23, 0x1E, 0xC3, 0x38, 0x03, 0x10, 0xC3, 0x09, 0x00, 0x18, 0x68, 0x00, 0xC1, 0x40, 0x00, 0x0A, 0x07, 0x80, 0x50, 0x46, 0x02, 0x80, 0x00, 0x1A, 0x1E, 0x00, 0xCB, 0x10, 0x0D, 0x03, 0x00, 0x48, 0x60, 0x06, 0x40, 0x00, 0x22, 0x0C, 0x02, 0x10, 0x60, 0x60, 0x43, 0xFC, 0x01, 0xE0, 0x00, 0x00,
|
||||
/* 0x1E */ 0x01, 0xF0, 0x00, 0xEA, 0xC0, 0x31, 0x5F, 0x04, 0x5F, 0x88, 0x80, 0xA0, 0x48, 0x0E, 0x02, 0x8F, 0x40, 0x3C, 0x10, 0x21, 0x66, 0x87, 0x15, 0x98, 0x71, 0x41, 0x02, 0x14, 0x00, 0x01, 0x40, 0x00, 0x14, 0x00, 0x01, 0x21, 0xFE, 0x12, 0x00, 0x02, 0x10, 0x00, 0x60, 0x80, 0x0C, 0x06, 0x01, 0x80, 0x3F, 0xE0,
|
||||
/* 0x1F */ 0x0E, 0x00, 0x13, 0x00, 0x23, 0x00, 0xF3, 0x01, 0x31, 0x01, 0x11, 0x03, 0xD3, 0x06, 0xF2, 0x30, 0x34, 0xC7, 0x25, 0x33, 0x2B, 0xC2, 0x57, 0x04, 0x3A, 0x08, 0x72, 0x30, 0xA3, 0xC3, 0x40, 0x04, 0x40, 0x18, 0x40, 0x60, 0x7F, 0x80,
|
||||
/* ' ' 0x20 */
|
||||
/* '!' 0x21 */ 0xFF, 0xFF, 0xFF, 0xF0, 0xF0,
|
||||
/* '"' 0x22 */ 0xCF, 0x3C, 0xF3, 0x8A, 0x20,
|
||||
/* '#' 0x23 */ 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30,
|
||||
/* '$' 0x24 */ 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x7C, 0x47, 0x88, 0xF1, 0x07, 0xA0, 0x7E, 0x03, 0xF0, 0x17, 0x02, 0x7C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, 0xE0, 0x10, 0x02, 0x00,
|
||||
/* '%' 0x25 */ 0x00, 0x06, 0x03, 0xC0, 0x40, 0x7E, 0x0C, 0x0E, 0x70, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xE7, 0x30, 0x07, 0xE6, 0x00, 0x3C, 0x40, 0x00, 0x0C, 0x7C, 0x00, 0x8F, 0xE0, 0x19, 0xC7, 0x01, 0x18, 0x30, 0x31, 0x83, 0x02, 0x1C, 0x70, 0x40, 0xFE, 0x04, 0x07, 0xC0,
|
||||
/* '&' 0x26 */ 0x0F, 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x39, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, 0x1F, 0x9F, 0xE6, 0x3E, 0x1C,
|
||||
/* ''' 0x27 */ 0xFF, 0xA0,
|
||||
/* '(' 0x28 */ 0x08, 0x8C, 0x46, 0x31, 0x98, 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20,
|
||||
/* ')' 0x29 */ 0x82, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, 0x00,
|
||||
/* '*' 0x2A */ 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00,
|
||||
/* '+' 0x2B */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0,
|
||||
/* ',' 0x2C */ 0xF5, 0x60,
|
||||
/* '-' 0x2D */ 0xFF, 0xF0,
|
||||
/* '.' 0x2E */ 0xF0,
|
||||
/* '/' 0x2F */ 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00,
|
||||
/* '0' 0x30 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* '1' 0x31 */ 0x08, 0xCF, 0xFF, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18,
|
||||
/* '2' 0x32 */ 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0,
|
||||
/* '3' 0x33 */ 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0C, 0x01, 0x80, 0x60, 0x78, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, 0x80, 0xD8, 0x73, 0xFC, 0x3F, 0x00,
|
||||
/* '4' 0x34 */ 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80,
|
||||
/* '5' 0x35 */ 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x81, 0xB8, 0x73, 0xFC, 0x1F, 0x00,
|
||||
/* '6' 0x36 */ 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* '7' 0x37 */ 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00,
|
||||
/* '8' 0x38 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xC1, 0x8C, 0x61, 0xF8, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00,
|
||||
/* '9' 0x39 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, 0xC1, 0x98, 0x73, 0xFC, 0x1E, 0x00,
|
||||
/* ':' 0x3A */ 0xF0, 0x00, 0x03, 0xC0,
|
||||
/* ';' 0x3B */ 0xF0, 0x00, 0x0F, 0x56,
|
||||
/* '<' 0x3C */ 0x00, 0x70, 0x1E, 0x0F, 0x83, 0xC0, 0xF0, 0x0E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10,
|
||||
/* '=' 0x3D */ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* '>' 0x3E */ 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x07, 0x01, 0xE0, 0xF0, 0x3C, 0x0F, 0x00, 0x80, 0x00,
|
||||
/* '?' 0x3F */ 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00,
|
||||
/* '@' 0x40 */ 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x38, 0xC1, 0xE0, 0x66, 0x0F, 0xD9, 0xD8, 0x61, 0xC3, 0xC3, 0x07, 0x0F, 0x1C, 0x1C, 0x3C, 0x60, 0x60, 0xF1, 0x81, 0x83, 0xC6, 0x06, 0x1B, 0x18, 0x38, 0xEE, 0x71, 0xE7, 0x18, 0xFD, 0xF8, 0x71, 0xE7, 0xC0, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x01, 0xFC, 0x00,
|
||||
/* 'A' 0x41 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 'B' 0x42 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00,
|
||||
/* 'C' 0x43 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0,
|
||||
/* 'D' 0x44 */ 0xFF, 0xC3, 0xFF, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1B, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3, 0xFE, 0x00,
|
||||
/* 'E' 0x45 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 'F' 0x46 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xDF, 0xFB, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00,
|
||||
/* 'G' 0x47 */ 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x07, 0x60, 0x03, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x03, 0x60, 0x07, 0x30, 0x0F, 0x3C, 0x1F, 0x1F, 0xFB, 0x07, 0xE1,
|
||||
/* 'H' 0x48 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0,
|
||||
/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 'J' 0x4A */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00,
|
||||
/* 'K' 0x4B */ 0xC0, 0x3E, 0x03, 0xB0, 0x39, 0x83, 0x8C, 0x38, 0x63, 0x83, 0x38, 0x19, 0xC0, 0xDE, 0x07, 0xB8, 0x38, 0xE1, 0x83, 0x0C, 0x1C, 0x60, 0x73, 0x01, 0x98, 0x0E, 0xC0, 0x3E, 0x00, 0xC0,
|
||||
/* 'L' 0x4C */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0,
|
||||
/* 'M' 0x4D */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83,
|
||||
/* 'N' 0x4E */ 0xE0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, 0x0F, 0x30, 0x79, 0xC3, 0xC6, 0x1E, 0x18, 0xF0, 0xE7, 0x83, 0x3C, 0x1D, 0xE0, 0x6F, 0x01, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, 0xC0,
|
||||
/* 'O' 0x4F */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00,
|
||||
/* 'P' 0x50 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00,
|
||||
/* 'Q' 0x51 */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xC0, 0xFC, 0x78, 0x3C, 0x1F, 0xFF, 0x03, 0xF9, 0x80, 0x00, 0x40,
|
||||
/* 'R' 0x52 */ 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70,
|
||||
/* 'S' 0x53 */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80,
|
||||
/* 'T' 0x54 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
|
||||
/* 'U' 0x55 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x80, 0xEE, 0x0E, 0x3F, 0xE0, 0xFC, 0x00,
|
||||
/* 'V' 0x56 */ 0xC0, 0x0F, 0x00, 0x7E, 0x01, 0x98, 0x06, 0x60, 0x39, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x38, 0x60, 0x61, 0x81, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x37, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00,
|
||||
/* 'W' 0x57 */ 0xE0, 0x30, 0x1D, 0x80, 0xE0, 0x76, 0x07, 0x81, 0xDC, 0x1E, 0x06, 0x70, 0x7C, 0x18, 0xC1, 0xB0, 0xE3, 0x0C, 0xC3, 0x8C, 0x33, 0x0C, 0x38, 0xC6, 0x30, 0x67, 0x18, 0xC1, 0x98, 0x67, 0x06, 0x61, 0xD8, 0x1D, 0x83, 0x60, 0x3C, 0x0D, 0x80, 0xF0, 0x3E, 0x03, 0xC0, 0x70, 0x0F, 0x01, 0xC0, 0x18, 0x07, 0x00,
|
||||
/* 'X' 0x58 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70,
|
||||
/* 'Y' 0x59 */ 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
|
||||
/* 'Z' 0x5A */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
/* '[' 0x5B */ 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0,
|
||||
/* '\' 0x5C */ 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04,
|
||||
/* ']' 0x5D */ 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0,
|
||||
/* '^' 0x5E */ 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80,
|
||||
/* '_' 0x5F */ 0xFF, 0xFE,
|
||||
/* '`' 0x60 */ 0xE3, 0x8C, 0x30,
|
||||
/* 'a' 0x61 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
|
||||
/* 'b' 0x62 */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0xF8, 0xDF, 0xCF, 0x0E, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xE0, 0x6F, 0x0E, 0xDF, 0xCC, 0xF8,
|
||||
/* 'c' 0x63 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00,
|
||||
/* 'd' 0x64 */ 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x8F, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8F, 0x3F, 0x63, 0xCC,
|
||||
/* 'e' 0x65 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0,
|
||||
/* 'f' 0x66 */ 0x3B, 0xD8, 0xC6, 0x7F, 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00,
|
||||
/* 'g' 0x67 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xB1, 0xE6, 0x00, 0xC0, 0x3E, 0x0E, 0x7F, 0xC7, 0xE0,
|
||||
/* 'h' 0x68 */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
|
||||
/* 'i' 0x69 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0,
|
||||
/* 'j' 0x6A */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0,
|
||||
/* 'k' 0x6B */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0xB8, 0xC6, 0x31, 0xCC, 0x3B, 0x06, 0xC1, 0xF0, 0x30,
|
||||
/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 'm' 0x6D */ 0xCF, 0x1F, 0x6F, 0xDF, 0xFC, 0x78, 0xFC, 0x18, 0x3C, 0x0C, 0x1E, 0x06, 0x0F, 0x03, 0x07, 0x81, 0x83, 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x3C, 0x0C, 0x18,
|
||||
/* 'n' 0x6E */ 0xCF, 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0,
|
||||
/* 'o' 0x6F */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0,
|
||||
/* 'p' 0x70 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 'q' 0x71 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60,
|
||||
/* 'r' 0x72 */ 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
|
||||
/* 's' 0x73 */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x01, 0xF0, 0x3E, 0x1D, 0xFE, 0x3F, 0x00,
|
||||
/* 't' 0x74 */ 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xE7,
|
||||
/* 'u' 0x75 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0,
|
||||
/* 'v' 0x76 */ 0xE0, 0x6C, 0x0D, 0x81, 0xB8, 0x63, 0x0C, 0x61, 0x8E, 0x60, 0xCC, 0x19, 0x83, 0xE0, 0x3C, 0x07, 0x00, 0xE0,
|
||||
/* 'w' 0x77 */ 0xC1, 0xC1, 0xB0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36, 0x31, 0x9B, 0x18, 0xCD, 0x98, 0x64, 0x6C, 0x16, 0x36, 0x0F, 0x1A, 0x07, 0x8F, 0x03, 0x83, 0x80, 0xC1, 0xC0,
|
||||
/* 'x' 0x78 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0,
|
||||
/* 'y' 0x79 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00,
|
||||
/* 'z' 0x7A */ 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0,
|
||||
/* '{' 0x7B */ 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60,
|
||||
/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
|
||||
/* '}' 0x7D */ 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00,
|
||||
/* '~' 0x7E */ 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, 0x80,
|
||||
/* 0x7F */
|
||||
/* 0x80 */ 0x01, 0xF0, 0x1F, 0xF0, 0xE0, 0xC7, 0x00, 0x18, 0x00, 0xC0, 0x07, 0xFF, 0x3F, 0xFC, 0x30, 0x01, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xE0, 0x81, 0xFE, 0x03, 0xF0,
|
||||
/* 0x81 */
|
||||
/* 0x82 */ 0xF5, 0x80,
|
||||
/* 0x83 */ 0x1C, 0xF3, 0x0C, 0x31, 0xF7, 0xCC, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x33, 0xCE, 0x00,
|
||||
/* 0x84 */ 0xCF, 0x34, 0x51, 0x88,
|
||||
/* 0x85 */ 0xC6, 0x3C, 0x63,
|
||||
/* 0x86 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00,
|
||||
/* 0x87 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x0F, 0xFF, 0xFF, 0x0C, 0x03, 0x00, 0xC0, 0x30,
|
||||
/* 0x88 */ 0x38, 0xD9, 0xB6, 0x30,
|
||||
/* 0x89 */ 0x38, 0x18, 0x00, 0xF8, 0x30, 0x03, 0x18, 0xC0, 0x04, 0x11, 0x80, 0x0C, 0x66, 0x00, 0x0F, 0x8C, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x31, 0xC0, 0xE0, 0x67, 0xC3, 0xC1, 0x98, 0xCC, 0xC3, 0x20, 0x90, 0x8C, 0x63, 0x33, 0x10, 0x7C, 0x3C, 0x60, 0x70, 0x38,
|
||||
/* 0x8A */ 0x0C, 0x40, 0x1F, 0x00, 0x38, 0x03, 0xF8, 0x1F, 0xF0, 0xE0, 0xE6, 0x01, 0xD8, 0x03, 0x60, 0x01, 0xC0, 0x07, 0x80, 0x0F, 0xE0, 0x0F, 0xF0, 0x03, 0xE0, 0x01, 0xF0, 0x03, 0xC0, 0x0F, 0x80, 0x37, 0x83, 0x8F, 0xFC, 0x0F, 0xE0,
|
||||
/* 0x8B */ 0x2F, 0x49, 0x99,
|
||||
/* 0x8C */ 0x07, 0xCF, 0xFC, 0x7F, 0xFF, 0xF3, 0x83, 0xC0, 0x18, 0x07, 0x00, 0x60, 0x0C, 0x03, 0x00, 0x30, 0x0C, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xC0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x01, 0xC0, 0x0E, 0x0F, 0x00, 0x1F, 0xEF, 0xFC, 0x1F, 0x3F, 0xF0,
|
||||
/* 0x8D */
|
||||
/* 0x8E */ 0x0C, 0xC0, 0x3C, 0x00, 0xE1, 0xFF, 0xFF, 0xFF, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0x80,
|
||||
/* 0x8F */
|
||||
/* 0x90 */
|
||||
/* 0x91 */ 0x6A, 0xF0,
|
||||
/* 0x92 */ 0xF5, 0x60,
|
||||
/* 0x93 */ 0x4E, 0x28, 0xA2, 0xCF, 0x30,
|
||||
/* 0x94 */ 0xCF, 0x34, 0x51, 0x4E, 0x20,
|
||||
/* 0x95 */ 0x7B, 0xFF, 0xFF, 0xFD, 0xE0,
|
||||
/* 0x96 */ 0xFF, 0xFF, 0xF0,
|
||||
/* 0x97 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
/* 0x98 */ 0x63, 0xFE, 0x70,
|
||||
/* 0x99 */ 0xFF, 0x70, 0x1F, 0xFD, 0xC0, 0x71, 0x87, 0x83, 0xC6, 0x1E, 0x0F, 0x18, 0x68, 0x3C, 0x61, 0xB1, 0xB1, 0x86, 0xC6, 0xC6, 0x19, 0x1B, 0x18, 0x66, 0xCC, 0x61, 0x9B, 0x31, 0x86, 0x3C, 0xC6, 0x18, 0xE3, 0x18, 0x63, 0x8C,
|
||||
/* 0x9A */ 0x63, 0x0D, 0x83, 0x60, 0x70, 0x00, 0x0F, 0x87, 0xFB, 0x86, 0xC0, 0x30, 0x0F, 0x01, 0xFC, 0x0F, 0xC0, 0x7C, 0x0F, 0x87, 0x7F, 0x8F, 0xC0,
|
||||
/* 0x9B */ 0x99, 0x92, 0xF4,
|
||||
/* 0x9C */ 0x1F, 0x0F, 0x83, 0xF9, 0xFC, 0x71, 0xF8, 0x6E, 0x0F, 0x03, 0xC0, 0x60, 0x3C, 0x07, 0xFF, 0xC0, 0x7F, 0xFC, 0x06, 0x00, 0xC0, 0x60, 0x0E, 0x0F, 0x03, 0x71, 0xF8, 0x63, 0xF9, 0xFC, 0x1F, 0x0F, 0x80,
|
||||
/* 0x9D */
|
||||
/* 0x9E */ 0x63, 0x0C, 0x83, 0x60, 0x70, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03, 0x01, 0xC0, 0xE0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFF, 0xFF, 0xF0,
|
||||
/* 0x9F */ 0x0C, 0xC0, 0x33, 0x00, 0x00, 0x30, 0x03, 0xE0, 0x1D, 0x80, 0x67, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x80, 0xCC, 0x03, 0xE0, 0x07, 0x80, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00,
|
||||
/* 0xA0 */
|
||||
/* 0xA1 */ 0xF0, 0xBF, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xA2 */ 0x04, 0x00, 0x80, 0x7C, 0x1F, 0xE7, 0x4C, 0xC8, 0xF1, 0x1E, 0x20, 0xC4, 0x18, 0x83, 0x10, 0x72, 0x37, 0x4E, 0x7F, 0x87, 0xC0, 0x20, 0x04, 0x00,
|
||||
/* 0xA3 */ 0x0F, 0xC1, 0xFE, 0x38, 0x76, 0x03, 0x60, 0x36, 0x00, 0x70, 0x03, 0x80, 0xFF, 0x0F, 0xF0, 0x1C, 0x00, 0xC0, 0x0C, 0x01, 0x80, 0x10, 0x02, 0xF1, 0x7F, 0xF6, 0x1F,
|
||||
/* 0xA4 */ 0xDD, 0xFF, 0xD8, 0xD8, 0x3C, 0x1E, 0x0F, 0x8D, 0xFF, 0xDD, 0x80,
|
||||
/* 0xA5 */ 0xC0, 0x3E, 0x06, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x19, 0x80, 0xF0, 0x0F, 0x07, 0xFE, 0x06, 0x00, 0x60, 0x7F, 0xE0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
|
||||
/* 0xA6 */ 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC,
|
||||
/* 0xA7 */ 0x0F, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x70, 0x07, 0x03, 0xF8, 0xC3, 0x98, 0x3B, 0x03, 0xF0, 0x37, 0x06, 0x78, 0xC7, 0xB0, 0x7C, 0x03, 0x80, 0x39, 0x83, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0,
|
||||
/* 0xA8 */ 0xCF, 0x30,
|
||||
/* 0xA9 */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE3, 0x1C, 0x73, 0xF3, 0x99, 0x86, 0x6C, 0xC1, 0x8F, 0x30, 0x03, 0xCC, 0x00, 0xF3, 0x00, 0x3C, 0xC1, 0x8D, 0x98, 0x66, 0x77, 0xF3, 0x8E, 0x79, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
|
||||
/* 0xAA */ 0x79, 0x08, 0x11, 0xEE, 0x50, 0xA3, 0x3B, 0x00, 0x03, 0xF8,
|
||||
/* 0xAB */ 0x21, 0x63, 0xE7, 0x84, 0x84, 0xE7, 0x63, 0x21,
|
||||
/* 0xAC */ 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03,
|
||||
/* 0xAD */ 0xFF, 0xF0,
|
||||
/* 0xAE */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xFF, 0x1C, 0x7F, 0xF3, 0x9B, 0x04, 0x6C, 0xC1, 0x8F, 0x30, 0x43, 0xCF, 0xF0, 0xF3, 0xFC, 0x3C, 0xC1, 0x0D, 0xB0, 0x66, 0x7C, 0x1B, 0x8F, 0x07, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
|
||||
/* 0xAF */ 0xFF, 0xF0,
|
||||
/* 0xB0 */ 0x38, 0xFB, 0x1C, 0x18, 0x38, 0xDF, 0x1C,
|
||||
/* 0xB1 */ 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xE7, 0xFE, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xB2 */ 0x7D, 0x8F, 0x18, 0x30, 0xC6, 0x18, 0x60, 0xFF, 0xFC,
|
||||
/* 0xB3 */ 0x7D, 0x8F, 0x18, 0x31, 0x80, 0xC1, 0xE3, 0xC6, 0xF8,
|
||||
/* 0xB4 */ 0x3B, 0x99, 0x80,
|
||||
/* 0xB5 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x1C, 0xE3, 0xCF, 0xEF, 0xFC, 0x7C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 0xB6 */ 0x1F, 0xE7, 0xFD, 0xF3, 0x7E, 0x6F, 0xCD, 0xF9, 0xBF, 0x37, 0xE6, 0x7C, 0xCF, 0x98, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC,
|
||||
/* 0xB7 */ 0xF0,
|
||||
/* 0xB8 */ 0x10, 0xF0, 0xE3, 0x78,
|
||||
/* 0xB9 */ 0x2F, 0xB6, 0xDB, 0x6C,
|
||||
/* 0xBA */ 0x79, 0x38, 0x61, 0x86, 0x1C, 0xDE, 0x00, 0x0F, 0xC0,
|
||||
/* 0xBB */ 0x88, 0xC6, 0xE7, 0x21, 0x21, 0xE7, 0xC6, 0x88,
|
||||
/* 0xBC */ 0x20, 0x08, 0x30, 0x0C, 0x38, 0x04, 0x0C, 0x06, 0x06, 0x02, 0x03, 0x02, 0x01, 0x81, 0x00, 0xC1, 0x06, 0x61, 0x87, 0x30, 0x83, 0x80, 0xC2, 0xC0, 0x42, 0x60, 0x43, 0x30, 0x21, 0xFC, 0x20, 0x0C, 0x30, 0x06, 0x10, 0x03, 0x00,
|
||||
/* 0xBD */ 0x20, 0x00, 0x08, 0x02, 0x06, 0x01, 0x83, 0x80, 0x40, 0x60, 0x20, 0x18, 0x18, 0x06, 0x04, 0x01, 0x83, 0x00, 0x61, 0x9F, 0x98, 0x4E, 0x76, 0x33, 0x0C, 0x08, 0x03, 0x04, 0x03, 0x83, 0x01, 0x80, 0x81, 0x80, 0x60, 0xC0, 0x30, 0x3F, 0xC8, 0x0F, 0xF0,
|
||||
/* 0xBE */ 0x7C, 0x00, 0x18, 0xC0, 0x43, 0x18, 0x18, 0x03, 0x02, 0x00, 0x60, 0xC0, 0x30, 0x10, 0x01, 0x84, 0x00, 0x31, 0x80, 0xC6, 0x20, 0xD8, 0xC8, 0x39, 0xF1, 0x07, 0x00, 0x41, 0x60, 0x18, 0x4C, 0x02, 0x11, 0x80, 0x83, 0xF8, 0x10, 0x06, 0x04, 0x00, 0xC1, 0x00, 0x18,
|
||||
/* 0xBF */ 0x0C, 0x06, 0x00, 0x00, 0x00, 0xC0, 0x60, 0x60, 0x30, 0x30, 0x38, 0x38, 0x18, 0x0C, 0x06, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00,
|
||||
/* 0xC0 */ 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC1 */ 0x01, 0xC0, 0x0C, 0x00, 0x20, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC2 */ 0x07, 0x00, 0x3E, 0x01, 0x8C, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC3 */ 0x0E, 0x40, 0x7F, 0x01, 0x98, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
|
||||
/* 0xC4 */ 0x0C, 0xC0, 0x33, 0x00, 0x00, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0xFC, 0x03, 0x30, 0x0C, 0xC0, 0x73, 0x81, 0x86, 0x06, 0x18, 0x38, 0x70, 0xC0, 0xC3, 0xFF, 0x1F, 0xFE, 0x60, 0x19, 0x80, 0x6E, 0x01, 0xF0, 0x03, 0xC0, 0x0C,
|
||||
/* 0xC5 */ 0x03, 0x00, 0x1E, 0x00, 0xEC, 0x03, 0x30, 0x0F, 0xC0, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x3F, 0x00, 0xCC, 0x03, 0x30, 0x1C, 0xE0, 0x61, 0x81, 0x86, 0x0E, 0x1C, 0x30, 0x30, 0xFF, 0xC7, 0xFF, 0x98, 0x06, 0x60, 0x1B, 0x80, 0x7C, 0x00, 0xF0, 0x03,
|
||||
/* 0xC6 */ 0x01, 0xFF, 0xFC, 0x07, 0xFF, 0xF0, 0x31, 0x80, 0x00, 0xC6, 0x00, 0x07, 0x18, 0x00, 0x18, 0x60, 0x00, 0x61, 0x80, 0x03, 0x86, 0x00, 0x0C, 0x1F, 0xF8, 0x70, 0x7F, 0xE1, 0x81, 0x80, 0x07, 0xFE, 0x00, 0x3F, 0xF8, 0x00, 0xC0, 0x60, 0x07, 0x01, 0x80, 0x1C, 0x06, 0x00, 0x60, 0x1F, 0xFF, 0x80, 0x7F, 0xF0,
|
||||
/* 0xC7 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x66, 0x00, 0x7C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x01, 0xDC, 0x03, 0x1C, 0x1E, 0x1F, 0xF8, 0x0F, 0xC0, 0x08, 0x00, 0x1E, 0x00, 0x0C, 0x01, 0x18, 0x01, 0xE0, 0x00,
|
||||
/* 0xC8 */ 0x1C, 0x00, 0xC0, 0x02, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 0xC9 */ 0x07, 0x00, 0x60, 0x0C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 0xCA */ 0x0E, 0x01, 0xF0, 0x31, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
/* 0xCB */ 0x19, 0x81, 0x98, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0,
|
||||
/* 0xCC */ 0xE7, 0x10, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
|
||||
/* 0xCD */ 0x36, 0xC0, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
/* 0xCE */ 0x39, 0xFC, 0x40, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
|
||||
/* 0xCF */ 0xC7, 0x8C, 0x01, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x00,
|
||||
/* 0xD0 */ 0x7F, 0xE0, 0xFF, 0xE1, 0x80, 0xE3, 0x00, 0xE6, 0x00, 0xCC, 0x01, 0xD8, 0x01, 0xB0, 0x03, 0xFE, 0x07, 0xFC, 0x0D, 0x80, 0x1B, 0x00, 0x36, 0x00, 0x6C, 0x01, 0x98, 0x07, 0x30, 0x1C, 0x7F, 0xF0, 0xFF, 0xC0,
|
||||
/* 0xD1 */ 0x08, 0xC0, 0xFE, 0x05, 0xE0, 0x00, 0x0E, 0x01, 0xF0, 0x0F, 0xC0, 0x7E, 0x03, 0xD8, 0x1E, 0xE0, 0xF3, 0x07, 0x9C, 0x3C, 0x61, 0xE1, 0x8F, 0x0E, 0x78, 0x33, 0xC1, 0xDE, 0x06, 0xF0, 0x1F, 0x80, 0xFC, 0x03, 0xE0, 0x1C,
|
||||
/* 0xD2 */ 0x07, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80,
|
||||
/* 0xD3 */ 0x00, 0xE0, 0x00, 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80,
|
||||
/* 0xD4 */ 0x03, 0xC0, 0x01, 0xE0, 0x01, 0x98, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80,
|
||||
/* 0xD5 */ 0x07, 0x20, 0x03, 0xF0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80,
|
||||
/* 0xD6 */ 0x06, 0x30, 0x03, 0x18, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFF, 0xC1, 0xE0, 0xF0, 0xC0, 0x18, 0xC0, 0x06, 0x60, 0x03, 0x60, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x06, 0xC0, 0x06, 0x60, 0x03, 0x18, 0x03, 0x0F, 0x07, 0x83, 0xFF, 0x80, 0x7F, 0x00,
|
||||
/* 0xD7 */ 0x81, 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x81,
|
||||
/* 0xD8 */ 0x07, 0xF0, 0x8F, 0xFE, 0x8F, 0x07, 0xC6, 0x00, 0xE6, 0x00, 0xF3, 0x00, 0xDF, 0x00, 0xC7, 0x80, 0xC3, 0xC0, 0xC1, 0xE0, 0xC0, 0xF0, 0xC0, 0x78, 0xC0, 0x3E, 0xC0, 0x33, 0xC0, 0x19, 0xC0, 0x1C, 0xF8, 0x3C, 0xDF, 0xF8, 0x43, 0xF8, 0x00,
|
||||
/* 0xD9 */ 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0,
|
||||
/* 0xDA */ 0x03, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0,
|
||||
/* 0xDB */ 0x07, 0x00, 0x7C, 0x06, 0x20, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0,
|
||||
/* 0xDC */ 0x0C, 0xC0, 0x66, 0x00, 0x01, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0x01, 0xDC, 0x1C, 0x7F, 0xC1, 0xF8, 0x00,
|
||||
/* 0xDD */ 0x01, 0x80, 0x0C, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
|
||||
/* 0xDE */ 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xF8, 0xFF, 0xEC, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x6F, 0xFE, 0xFF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00,
|
||||
/* 0xDF */ 0x1F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0D, 0x81, 0xB0, 0x66, 0x38, 0xC7, 0xD8, 0x1B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x3E, 0x0E, 0xCF, 0x99, 0xE0,
|
||||
/* 0xE0 */ 0x1C, 0x00, 0xC0, 0x06, 0x00, 0x20, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7,
|
||||
/* 0xE1 */ 0x07, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7,
|
||||
/* 0xE2 */ 0x0C, 0x01, 0xE0, 0x1B, 0x03, 0x30, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7,
|
||||
/* 0xE3 */ 0x19, 0x83, 0xF0, 0x27, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7,
|
||||
/* 0xE4 */ 0x19, 0x81, 0x98, 0x00, 0x00, 0x00, 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
|
||||
/* 0xE5 */ 0x0E, 0x01, 0xF0, 0x1B, 0x81, 0xB8, 0x1F, 0x00, 0xE0, 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
|
||||
/* 0xE6 */ 0x3F, 0x1F, 0x0F, 0xF7, 0xF3, 0x87, 0xC3, 0x60, 0x70, 0x30, 0x0C, 0x06, 0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0x06, 0x00, 0xC0, 0xC0, 0x18, 0x3C, 0x0F, 0x8F, 0xC7, 0x3F, 0x9F, 0xE3, 0xC1, 0xF0,
|
||||
/* 0xE7 */ 0x1F, 0x0F, 0xE7, 0x1D, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x02, 0x00, 0xE0, 0x0C, 0x23, 0x07, 0x80,
|
||||
/* 0xE8 */ 0x1C, 0x01, 0x80, 0x18, 0x01, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0,
|
||||
/* 0xE9 */ 0x03, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0,
|
||||
/* 0xEA */ 0x0C, 0x03, 0xC0, 0x6C, 0x18, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0,
|
||||
/* 0xEB */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x03, 0xC0, 0x7F, 0xFF, 0xFF, 0xE0, 0x0C, 0x01, 0xC0, 0xDC, 0x31, 0xFC, 0x1F, 0x00,
|
||||
/* 0xEC */ 0xC6, 0x31, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
/* 0xED */ 0x39, 0x99, 0x80, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x80,
|
||||
/* 0xEE */ 0x71, 0xED, 0xA3, 0x00, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
|
||||
/* 0xEF */ 0xCF, 0x30, 0x00, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30,
|
||||
/* 0xF0 */ 0x20, 0x07, 0xE0, 0x70, 0x3B, 0x00, 0x30, 0x3F, 0x0F, 0xF3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF1 */ 0x19, 0x8F, 0xE2, 0x70, 0x00, 0x00, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
|
||||
/* 0xF2 */ 0x1C, 0x01, 0x80, 0x18, 0x01, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF3 */ 0x07, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF4 */ 0x0C, 0x03, 0xC0, 0xD8, 0x19, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF5 */ 0x19, 0x87, 0xE0, 0x9C, 0x00, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0,
|
||||
/* 0xF6 */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00,
|
||||
/* 0xF7 */ 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00,
|
||||
/* 0xF8 */ 0x1F, 0x27, 0xF5, 0xC7, 0x70, 0x7C, 0x17, 0x84, 0xF1, 0x1E, 0x43, 0xD0, 0x7C, 0x1D, 0xC7, 0x3F, 0xC9, 0xF0,
|
||||
/* 0xF9 */ 0x18, 0x03, 0x00, 0x60, 0x08, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30,
|
||||
/* 0xFA */ 0x03, 0x01, 0x80, 0x60, 0x30, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30,
|
||||
/* 0xFB */ 0x0C, 0x07, 0x81, 0x20, 0xCC, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30,
|
||||
/* 0xFC */ 0x31, 0x8C, 0x60, 0x00, 0x00, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0,
|
||||
/* 0xFD */ 0x03, 0x80, 0x60, 0x18, 0x06, 0x00, 0x01, 0xC0, 0xD8, 0x1B, 0x06, 0x70, 0xC6, 0x18, 0xC6, 0x18, 0xC1, 0x98, 0x36, 0x06, 0xC0, 0x78, 0x0E, 0x01, 0xC0, 0x30, 0x06, 0x01, 0xC0, 0xF0, 0x1C, 0x00,
|
||||
/* 0xFE */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xCF, 0x8F, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
|
||||
/* 0xFF */ 0x19, 0x83, 0x30, 0x00, 0x00, 0x0E, 0x06, 0xC0, 0xD8, 0x33, 0x86, 0x30, 0xC6, 0x30, 0xC6, 0x0C, 0xC1, 0xB0, 0x36, 0x03, 0xC0, 0x70, 0x0E, 0x01, 0x80, 0x30, 0x0E, 0x07, 0x80, 0xE0, 0x00,
|
||||
};
|
||||
|
||||
const GFXglyph FreeSans12pt_Win1252Glyphs[] PROGMEM = {
|
||||
/* 0x01 */ { 0, 19, 20, 21, 1, -17 },
|
||||
/* 0x02 */ { 48, 19, 20, 21, 1, -17 },
|
||||
/* 0x03 */ { 96, 21, 20, 23, 1, -17 },
|
||||
/* 0x04 */ { 149, 21, 20, 23, 1, -17 },
|
||||
/* 0x05 */ { 202, 20, 20, 22, 1, -17 },
|
||||
/* 0x06 */ { 252, 20, 20, 22, 1, -17 },
|
||||
/* 0x07 */ { 302, 0, 0, 8, 0, 0 },
|
||||
/* 0x08 */ { 302, 23, 20, 25, 1, -17 },
|
||||
/* 0x09 */ { 360, 23, 16, 25, 1, -16 },
|
||||
/* 0x0A */ { 406, 0, 0, 8, 0, 0 },
|
||||
/* 0x0B */ { 406, 21, 20, 23, 1, -17 },
|
||||
/* 0x0C */ { 459, 19, 18, 21, 1, -15 },
|
||||
/* 0x0D */ { 502, 0, 0, 8, 0, 0 },
|
||||
/* 0x0E */ { 502, 20, 20, 22, 1, -17 },
|
||||
/* 0x0F */ { 552, 21, 21, 23, 1, -18 },
|
||||
/* 0x10 */ { 608, 19, 20, 21, 1, -17 },
|
||||
/* 0x11 */ { 656, 21, 20, 23, 1, -17 },
|
||||
/* 0x12 */ { 709, 20, 20, 22, 1, -17 },
|
||||
/* 0x13 */ { 759, 21, 20, 23, 1, -17 },
|
||||
/* 0x14 */ { 812, 21, 20, 23, 1, -17 },
|
||||
/* 0x15 */ { 865, 22, 20, 24, 1, -17 },
|
||||
/* 0x16 */ { 920, 16, 20, 18, 1, -17 },
|
||||
/* 0x17 */ { 960, 21, 20, 23, 1, -17 },
|
||||
/* 0x18 */ { 1013, 23, 20, 25, 1, -17 },
|
||||
/* 0x19 */ { 1071, 21, 20, 23, 1, -17 },
|
||||
/* 0x1A */ { 1124, 15, 19, 17, 1, -16 },
|
||||
/* 0x1B */ { 1160, 24, 21, 26, 1, -18 },
|
||||
/* 0x1C */ { 1223, 21, 20, 23, 1, -17 },
|
||||
/* 0x1D */ { 1276, 21, 21, 23, 1, -18 },
|
||||
/* 0x1E */ { 1332, 20, 20, 22, 1, -17 },
|
||||
/* 0x1F */ { 1382, 15, 20, 17, 1, -17 },
|
||||
/* ' ' 0x20 */ { 1420, 0, 0, 6, 0, 0 },
|
||||
/* '!' 0x21 */ { 1420, 2, 18, 8, 3, -16 },
|
||||
/* '"' 0x22 */ { 1425, 6, 6, 8, 1, -15 },
|
||||
/* '#' 0x23 */ { 1430, 13, 16, 13, 0, -14 },
|
||||
/* '$' 0x24 */ { 1456, 11, 20, 13, 1, -16 },
|
||||
/* '%' 0x25 */ { 1484, 20, 17, 21, 1, -15 },
|
||||
/* '&' 0x26 */ { 1527, 14, 17, 16, 1, -15 },
|
||||
/* ''' 0x27 */ { 1557, 2, 6, 5, 1, -15 },
|
||||
/* '(' 0x28 */ { 1559, 5, 23, 8, 2, -16 },
|
||||
/* ')' 0x29 */ { 1574, 5, 23, 8, 1, -16 },
|
||||
/* '*' 0x2A */ { 1589, 7, 7, 9, 1, -16 },
|
||||
/* '+' 0x2B */ { 1596, 10, 11, 14, 2, -9 },
|
||||
/* ',' 0x2C */ { 1610, 2, 6, 7, 2, 0 },
|
||||
/* '-' 0x2D */ { 1612, 6, 2, 8, 1, -6 },
|
||||
/* '.' 0x2E */ { 1614, 2, 2, 6, 2, 0 },
|
||||
/* '/' 0x2F */ { 1615, 7, 18, 7, 0, -16 },
|
||||
/* '0' 0x30 */ { 1631, 11, 17, 13, 1, -15 },
|
||||
/* '1' 0x31 */ { 1655, 5, 17, 13, 3, -15 },
|
||||
/* '2' 0x32 */ { 1666, 11, 17, 13, 1, -15 },
|
||||
/* '3' 0x33 */ { 1690, 11, 17, 13, 1, -15 },
|
||||
/* '4' 0x34 */ { 1714, 11, 17, 13, 1, -15 },
|
||||
/* '5' 0x35 */ { 1738, 11, 17, 13, 1, -15 },
|
||||
/* '6' 0x36 */ { 1762, 11, 17, 13, 1, -15 },
|
||||
/* '7' 0x37 */ { 1786, 11, 17, 13, 1, -15 },
|
||||
/* '8' 0x38 */ { 1810, 11, 17, 13, 1, -15 },
|
||||
/* '9' 0x39 */ { 1834, 11, 17, 13, 1, -15 },
|
||||
/* ':' 0x3A */ { 1858, 2, 13, 6, 2, -11 },
|
||||
/* ';' 0x3B */ { 1862, 2, 16, 6, 2, -10 },
|
||||
/* '<' 0x3C */ { 1866, 12, 11, 14, 1, -9 },
|
||||
/* '=' 0x3D */ { 1883, 12, 6, 14, 1, -7 },
|
||||
/* '>' 0x3E */ { 1892, 12, 11, 14, 1, -9 },
|
||||
/* '?' 0x3F */ { 1909, 10, 18, 13, 2, -16 },
|
||||
/* '@' 0x40 */ { 1932, 22, 21, 24, 1, -16 },
|
||||
/* 'A' 0x41 */ { 1990, 14, 18, 16, 1, -16 },
|
||||
/* 'B' 0x42 */ { 2022, 13, 18, 16, 2, -16 },
|
||||
/* 'C' 0x43 */ { 2052, 15, 18, 17, 1, -16 },
|
||||
/* 'D' 0x44 */ { 2086, 14, 18, 17, 2, -16 },
|
||||
/* 'E' 0x45 */ { 2118, 12, 18, 15, 2, -16 },
|
||||
/* 'F' 0x46 */ { 2145, 11, 18, 14, 2, -16 },
|
||||
/* 'G' 0x47 */ { 2170, 16, 18, 18, 1, -16 },
|
||||
/* 'H' 0x48 */ { 2206, 13, 18, 17, 2, -16 },
|
||||
/* 'I' 0x49 */ { 2236, 2, 18, 7, 2, -16 },
|
||||
/* 'J' 0x4A */ { 2241, 9, 18, 13, 1, -16 },
|
||||
/* 'K' 0x4B */ { 2262, 13, 18, 16, 2, -16 },
|
||||
/* 'L' 0x4C */ { 2292, 10, 18, 14, 2, -16 },
|
||||
/* 'M' 0x4D */ { 2315, 16, 18, 20, 2, -16 },
|
||||
/* 'N' 0x4E */ { 2351, 13, 18, 18, 2, -16 },
|
||||
/* 'O' 0x4F */ { 2381, 17, 18, 19, 1, -16 },
|
||||
/* 'P' 0x50 */ { 2420, 12, 18, 16, 2, -16 },
|
||||
/* 'Q' 0x51 */ { 2447, 17, 19, 19, 1, -16 },
|
||||
/* 'R' 0x52 */ { 2488, 14, 18, 17, 2, -16 },
|
||||
/* 'S' 0x53 */ { 2520, 14, 18, 16, 1, -16 },
|
||||
/* 'T' 0x54 */ { 2552, 12, 18, 15, 1, -16 },
|
||||
/* 'U' 0x55 */ { 2579, 13, 18, 17, 2, -16 },
|
||||
/* 'V' 0x56 */ { 2609, 14, 18, 15, 1, -16 },
|
||||
/* 'W' 0x57 */ { 2641, 22, 18, 22, 0, -16 },
|
||||
/* 'X' 0x58 */ { 2691, 14, 18, 16, 1, -16 },
|
||||
/* 'Y' 0x59 */ { 2723, 14, 18, 16, 1, -16 },
|
||||
/* 'Z' 0x5A */ { 2755, 13, 18, 15, 1, -16 },
|
||||
/* '[' 0x5B */ { 2785, 4, 23, 7, 2, -16 },
|
||||
/* '\' 0x5C */ { 2797, 7, 18, 7, 0, -16 },
|
||||
/* ']' 0x5D */ { 2813, 4, 23, 7, 1, -16 },
|
||||
/* '^' 0x5E */ { 2825, 9, 9, 11, 1, -15 },
|
||||
/* '_' 0x5F */ { 2836, 15, 1, 13, -1, 5 },
|
||||
/* '`' 0x60 */ { 2838, 5, 4, 6, 1, -16 },
|
||||
/* 'a' 0x61 */ { 2841, 12, 13, 13, 1, -11 },
|
||||
/* 'b' 0x62 */ { 2861, 12, 18, 13, 1, -16 },
|
||||
/* 'c' 0x63 */ { 2888, 10, 13, 12, 1, -11 },
|
||||
/* 'd' 0x64 */ { 2905, 11, 18, 13, 1, -16 },
|
||||
/* 'e' 0x65 */ { 2930, 11, 13, 13, 1, -11 },
|
||||
/* 'f' 0x66 */ { 2948, 5, 18, 7, 1, -16 },
|
||||
/* 'g' 0x67 */ { 2960, 11, 18, 13, 1, -11 },
|
||||
/* 'h' 0x68 */ { 2985, 10, 18, 13, 1, -16 },
|
||||
/* 'i' 0x69 */ { 3008, 2, 18, 5, 2, -16 },
|
||||
/* 'j' 0x6A */ { 3013, 4, 23, 6, 0, -16 },
|
||||
/* 'k' 0x6B */ { 3025, 10, 18, 12, 1, -16 },
|
||||
/* 'l' 0x6C */ { 3048, 2, 18, 5, 1, -16 },
|
||||
/* 'm' 0x6D */ { 3053, 17, 13, 19, 1, -11 },
|
||||
/* 'n' 0x6E */ { 3081, 10, 13, 13, 1, -11 },
|
||||
/* 'o' 0x6F */ { 3098, 11, 13, 13, 1, -11 },
|
||||
/* 'p' 0x70 */ { 3116, 12, 17, 13, 1, -11 },
|
||||
/* 'q' 0x71 */ { 3142, 11, 17, 13, 1, -11 },
|
||||
/* 'r' 0x72 */ { 3166, 6, 13, 8, 1, -11 },
|
||||
/* 's' 0x73 */ { 3176, 10, 13, 12, 1, -11 },
|
||||
/* 't' 0x74 */ { 3193, 5, 16, 7, 1, -14 },
|
||||
/* 'u' 0x75 */ { 3203, 10, 13, 13, 1, -11 },
|
||||
/* 'v' 0x76 */ { 3220, 11, 13, 12, 0, -11 },
|
||||
/* 'w' 0x77 */ { 3238, 17, 13, 17, 0, -11 },
|
||||
/* 'x' 0x78 */ { 3266, 10, 13, 11, 1, -11 },
|
||||
/* 'y' 0x79 */ { 3283, 11, 18, 11, 0, -11 },
|
||||
/* 'z' 0x7A */ { 3308, 10, 13, 12, 1, -11 },
|
||||
/* '{' 0x7B */ { 3325, 5, 23, 8, 1, -16 },
|
||||
/* '|' 0x7C */ { 3340, 2, 23, 6, 2, -16 },
|
||||
/* '}' 0x7D */ { 3346, 5, 23, 8, 2, -16 },
|
||||
/* '~' 0x7E */ { 3361, 10, 5, 12, 1, -9 },
|
||||
/* 0x7F */ { 3368, 0, 0, 0, 0, 0 },
|
||||
/* 0x80 */ { 3368, 14, 17, 16, 1, -15 },
|
||||
/* 0x81 */ { 3398, 0, 0, 8, 0, 0 },
|
||||
/* 0x82 */ { 3398, 2, 5, 6, 2, 0 },
|
||||
/* 0x83 */ { 3400, 6, 23, 7, 0, -16 },
|
||||
/* 0x84 */ { 3418, 6, 5, 10, 2, 0 },
|
||||
/* 0x85 */ { 3422, 12, 2, 16, 2, 0 },
|
||||
/* 0x86 */ { 3425, 10, 21, 13, 2, -15 },
|
||||
/* 0x87 */ { 3452, 10, 20, 13, 2, -15 },
|
||||
/* 0x88 */ { 3477, 7, 4, 8, 0, -16 },
|
||||
/* 0x89 */ { 3481, 23, 18, 24, 0, -16 },
|
||||
/* 0x8A */ { 3533, 14, 21, 16, 1, -19 },
|
||||
/* 0x8B */ { 3570, 3, 8, 6, 1, -9 },
|
||||
/* 0x8C */ { 3573, 22, 18, 24, 1, -16 },
|
||||
/* 0x8D */ { 3623, 0, 0, 8, 0, 0 },
|
||||
/* 0x8E */ { 3623, 13, 21, 15, 1, -19 },
|
||||
/* 0x8F */ { 3658, 0, 0, 8, 0, 0 },
|
||||
/* 0x90 */ { 3658, 0, 0, 8, 0, 0 },
|
||||
/* 0x91 */ { 3658, 2, 6, 6, 2, -16 },
|
||||
/* 0x92 */ { 3660, 2, 6, 6, 2, -16 },
|
||||
/* 0x93 */ { 3662, 6, 6, 10, 2, -16 },
|
||||
/* 0x94 */ { 3667, 6, 6, 10, 2, -16 },
|
||||
/* 0x95 */ { 3672, 6, 6, 10, 2, -9 },
|
||||
/* 0x96 */ { 3677, 10, 2, 12, 1, -6 },
|
||||
/* 0x97 */ { 3680, 22, 2, 24, 1, -6 },
|
||||
/* 0x98 */ { 3686, 7, 3, 8, 0, -16 },
|
||||
/* 0x99 */ { 3689, 22, 13, 24, 2, -16 },
|
||||
/* 0x9A */ { 3725, 10, 18, 12, 1, -16 },
|
||||
/* 0x9B */ { 3748, 3, 8, 6, 2, -8 },
|
||||
/* 0x9C */ { 3751, 20, 13, 22, 1, -11 },
|
||||
/* 0x9D */ { 3784, 0, 0, 8, 0, 0 },
|
||||
/* 0x9E */ { 3784, 10, 18, 12, 1, -16 },
|
||||
/* 0x9F */ { 3807, 14, 21, 16, 1, -19 },
|
||||
/* 0xA0 */ { 3844, 0, 0, 7, 0, 0 },
|
||||
/* 0xA1 */ { 3844, 2, 18, 8, 3, -11 },
|
||||
/* 0xA2 */ { 3849, 11, 17, 13, 1, -13 },
|
||||
/* 0xA3 */ { 3873, 12, 18, 13, 0, -16 },
|
||||
/* 0xA4 */ { 3900, 9, 9, 13, 2, -11 },
|
||||
/* 0xA5 */ { 3911, 12, 17, 13, 1, -15 },
|
||||
/* 0xA6 */ { 3937, 2, 23, 6, 2, -16 },
|
||||
/* 0xA7 */ { 3943, 11, 23, 13, 1, -16 },
|
||||
/* 0xA8 */ { 3975, 6, 2, 8, 1, -15 },
|
||||
/* 0xA9 */ { 3977, 18, 17, 19, 1, -15 },
|
||||
/* 0xAA */ { 4016, 7, 11, 9, 1, -16 },
|
||||
/* 0xAB */ { 4026, 8, 8, 12, 2, -9 },
|
||||
/* 0xAC */ { 4034, 12, 6, 14, 1, -7 },
|
||||
/* 0xAD */ { 4043, 6, 2, 8, 1, -6 },
|
||||
/* 0xAE */ { 4045, 18, 17, 19, 1, -15 },
|
||||
/* 0xAF */ { 4084, 6, 2, 8, 1, -15 },
|
||||
/* 0xB0 */ { 4086, 7, 8, 15, 4, -15 },
|
||||
/* 0xB1 */ { 4093, 12, 15, 14, 1, -13 },
|
||||
/* 0xB2 */ { 4116, 7, 10, 8, 1, -17 },
|
||||
/* 0xB3 */ { 4125, 7, 10, 8, 1, -17 },
|
||||
/* 0xB4 */ { 4134, 5, 4, 8, 2, -16 },
|
||||
/* 0xB5 */ { 4137, 12, 17, 13, 2, -11 },
|
||||
/* 0xB6 */ { 4163, 11, 21, 13, 2, -16 },
|
||||
/* 0xB7 */ { 4192, 2, 2, 6, 2, -6 },
|
||||
/* 0xB8 */ { 4193, 6, 5, 8, 1, 2 },
|
||||
/* 0xB9 */ { 4197, 3, 10, 8, 3, -18 },
|
||||
/* 0xBA */ { 4201, 6, 11, 9, 1, -16 },
|
||||
/* 0xBB */ { 4210, 8, 8, 12, 2, -8 },
|
||||
/* 0xBC */ { 4218, 17, 17, 21, 3, -15 },
|
||||
/* 0xBD */ { 4255, 18, 18, 21, 3, -16 },
|
||||
/* 0xBE */ { 4296, 19, 18, 21, 1, -16 },
|
||||
/* 0xBF */ { 4339, 9, 18, 13, 3, -11 },
|
||||
/* 0xC0 */ { 4360, 14, 22, 16, 1, -20 },
|
||||
/* 0xC1 */ { 4399, 14, 22, 16, 1, -20 },
|
||||
/* 0xC2 */ { 4438, 14, 22, 16, 1, -20 },
|
||||
/* 0xC3 */ { 4477, 14, 22, 16, 1, -20 },
|
||||
/* 0xC4 */ { 4516, 14, 21, 16, 1, -19 },
|
||||
/* 0xC5 */ { 4553, 14, 24, 16, 1, -22 },
|
||||
/* 0xC6 */ { 4595, 22, 18, 24, 0, -16 },
|
||||
/* 0xC7 */ { 4645, 15, 23, 17, 1, -16 },
|
||||
/* 0xC8 */ { 4689, 12, 22, 15, 2, -20 },
|
||||
/* 0xC9 */ { 4722, 12, 22, 15, 2, -20 },
|
||||
/* 0xCA */ { 4755, 12, 22, 15, 2, -20 },
|
||||
/* 0xCB */ { 4788, 12, 21, 15, 2, -19 },
|
||||
/* 0xCC */ { 4820, 4, 22, 7, 0, -20 },
|
||||
/* 0xCD */ { 4831, 4, 22, 7, 1, -20 },
|
||||
/* 0xCE */ { 4842, 6, 22, 7, 0, -20 },
|
||||
/* 0xCF */ { 4859, 7, 21, 7, 0, -19 },
|
||||
/* 0xD0 */ { 4878, 15, 18, 17, 1, -16 },
|
||||
/* 0xD1 */ { 4912, 13, 22, 18, 2, -20 },
|
||||
/* 0xD2 */ { 4948, 17, 22, 19, 1, -20 },
|
||||
/* 0xD3 */ { 4995, 17, 22, 19, 1, -20 },
|
||||
/* 0xD4 */ { 5042, 17, 22, 19, 1, -20 },
|
||||
/* 0xD5 */ { 5089, 17, 22, 19, 1, -20 },
|
||||
/* 0xD6 */ { 5136, 17, 21, 19, 1, -19 },
|
||||
/* 0xD7 */ { 5181, 8, 9, 14, 3, -8 },
|
||||
/* 0xD8 */ { 5190, 17, 18, 19, 1, -16 },
|
||||
/* 0xD9 */ { 5229, 13, 22, 17, 2, -20 },
|
||||
/* 0xDA */ { 5265, 13, 22, 17, 2, -20 },
|
||||
/* 0xDB */ { 5301, 13, 22, 17, 2, -20 },
|
||||
/* 0xDC */ { 5337, 13, 21, 17, 2, -19 },
|
||||
/* 0xDD */ { 5372, 14, 22, 16, 1, -20 },
|
||||
/* 0xDE */ { 5411, 12, 18, 15, 2, -16 },
|
||||
/* 0xDF */ { 5438, 11, 18, 14, 2, -16 },
|
||||
/* 0xE0 */ { 5463, 12, 18, 13, 1, -16 },
|
||||
/* 0xE1 */ { 5490, 12, 18, 13, 1, -16 },
|
||||
/* 0xE2 */ { 5517, 12, 18, 13, 1, -16 },
|
||||
/* 0xE3 */ { 5544, 12, 18, 13, 1, -16 },
|
||||
/* 0xE4 */ { 5571, 12, 17, 13, 1, -15 },
|
||||
/* 0xE5 */ { 5597, 12, 19, 13, 1, -17 },
|
||||
/* 0xE6 */ { 5626, 19, 13, 21, 1, -11 },
|
||||
/* 0xE7 */ { 5657, 10, 18, 12, 1, -11 },
|
||||
/* 0xE8 */ { 5680, 11, 18, 13, 1, -16 },
|
||||
/* 0xE9 */ { 5705, 11, 18, 13, 1, -16 },
|
||||
/* 0xEA */ { 5730, 11, 18, 13, 1, -16 },
|
||||
/* 0xEB */ { 5755, 11, 17, 13, 1, -15 },
|
||||
/* 0xEC */ { 5779, 4, 18, 5, 1, -16 },
|
||||
/* 0xED */ { 5788, 5, 18, 5, 0, -16 },
|
||||
/* 0xEE */ { 5800, 6, 18, 6, 0, -16 },
|
||||
/* 0xEF */ { 5814, 6, 17, 6, 0, -15 },
|
||||
/* 0xF0 */ { 5827, 11, 18, 13, 1, -16 },
|
||||
/* 0xF1 */ { 5852, 10, 18, 13, 1, -16 },
|
||||
/* 0xF2 */ { 5875, 11, 18, 13, 1, -16 },
|
||||
/* 0xF3 */ { 5900, 11, 18, 13, 1, -16 },
|
||||
/* 0xF4 */ { 5925, 11, 18, 13, 1, -16 },
|
||||
/* 0xF5 */ { 5950, 11, 18, 13, 1, -16 },
|
||||
/* 0xF6 */ { 5975, 11, 17, 13, 1, -15 },
|
||||
/* 0xF7 */ { 5999, 12, 11, 14, 1, -9 },
|
||||
/* 0xF8 */ { 6016, 11, 13, 13, 1, -11 },
|
||||
/* 0xF9 */ { 6034, 10, 18, 13, 1, -16 },
|
||||
/* 0xFA */ { 6057, 10, 18, 13, 1, -16 },
|
||||
/* 0xFB */ { 6080, 10, 18, 13, 1, -16 },
|
||||
/* 0xFC */ { 6103, 10, 17, 13, 1, -15 },
|
||||
/* 0xFD */ { 6125, 11, 23, 11, 0, -16 },
|
||||
/* 0xFE */ { 6157, 12, 21, 13, 1, -15 },
|
||||
/* 0xFF */ { 6189, 11, 22, 11, 0, -15 },
|
||||
};
|
||||
|
||||
const GFXfont FreeSans12pt_Win1252 PROGMEM = {
|
||||
(uint8_t*)FreeSans12pt_Win1252Bitmaps,
|
||||
(GFXglyph*)FreeSans12pt_Win1252Glyphs,
|
||||
0x01, 0xFF, 19
|
||||
};
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
using namespace NicheGraphics;
|
||||
|
||||
InkHUD::AppletFont InkHUD::Applet::fontLarge; // General purpose font. Set by setDefaultFonts
|
||||
InkHUD::AppletFont InkHUD::Applet::fontSmall; // General purpose font. Set by setDefaultFonts
|
||||
InkHUD::AppletFont InkHUD::Applet::fontLarge; // General purpose fonts. Set in nicheGraphics.h
|
||||
InkHUD::AppletFont InkHUD::Applet::fontMedium;
|
||||
InkHUD::AppletFont InkHUD::Applet::fontSmall;
|
||||
constexpr float InkHUD::Applet::LOGO_ASPECT_RATIO; // Ratio of the Meshtastic logo
|
||||
|
||||
InkHUD::Applet::Applet() : GFX(0, 0)
|
||||
|
||||
@@ -95,7 +95,7 @@ class Applet : public GFX
|
||||
|
||||
static uint16_t getHeaderHeight(); // How tall the "standard" applet header is
|
||||
|
||||
static AppletFont fontSmall, fontLarge; // The general purpose fonts, used by all applets
|
||||
static AppletFont fontSmall, fontMedium, fontLarge; // The general purpose fonts, used by all applets
|
||||
|
||||
const char *name = nullptr; // Shown in applet selection menu. Also used as an identifier by InkHUD::getSystemApplet
|
||||
|
||||
|
||||
@@ -61,20 +61,26 @@ class AppletFont
|
||||
// Line padding has been adjusted manually, to compensate for a few *extra tall* diacritics
|
||||
|
||||
// Central European
|
||||
#include "graphics/niche/Fonts/FreeSans12pt_Win1250.h"
|
||||
#include "graphics/niche/Fonts/FreeSans6pt_Win1250.h"
|
||||
#include "graphics/niche/Fonts/FreeSans9pt_Win1250.h"
|
||||
#define FREESANS_12PT_WIN1250 InkHUD::AppletFont(FreeSans12pt_Win1250, InkHUD::AppletFont::WINDOWS_1250, -3, 1)
|
||||
#define FREESANS_9PT_WIN1250 InkHUD::AppletFont(FreeSans9pt_Win1250, InkHUD::AppletFont::WINDOWS_1250, -1, -1)
|
||||
#define FREESANS_6PT_WIN1250 InkHUD::AppletFont(FreeSans6pt_Win1250, InkHUD::AppletFont::WINDOWS_1250, -1, -2)
|
||||
|
||||
// Cyrillic
|
||||
#include "graphics/niche/Fonts/FreeSans12pt_Win1251.h"
|
||||
#include "graphics/niche/Fonts/FreeSans6pt_Win1251.h"
|
||||
#include "graphics/niche/Fonts/FreeSans9pt_Win1251.h"
|
||||
#define FREESANS_12PT_WIN1251 InkHUD::AppletFont(FreeSans12pt_Win1251, InkHUD::AppletFont::WINDOWS_1251, -3, 1)
|
||||
#define FREESANS_9PT_WIN1251 InkHUD::AppletFont(FreeSans9pt_Win1251, InkHUD::AppletFont::WINDOWS_1251, -2, -1)
|
||||
#define FREESANS_6PT_WIN1251 InkHUD::AppletFont(FreeSans6pt_Win1251, InkHUD::AppletFont::WINDOWS_1251, -1, -2)
|
||||
|
||||
// Western European
|
||||
#include "graphics/niche/Fonts/FreeSans12pt_Win1252.h"
|
||||
#include "graphics/niche/Fonts/FreeSans6pt_Win1252.h"
|
||||
#include "graphics/niche/Fonts/FreeSans9pt_Win1252.h"
|
||||
#define FREESANS_12PT_WIN1252 InkHUD::AppletFont(FreeSans12pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -3, 1)
|
||||
#define FREESANS_9PT_WIN1252 InkHUD::AppletFont(FreeSans9pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -2, -1)
|
||||
#define FREESANS_6PT_WIN1252 InkHUD::AppletFont(FreeSans6pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -1, -2)
|
||||
|
||||
|
||||
@@ -168,11 +168,11 @@ void InkHUD::NodeListApplet::onRender()
|
||||
|
||||
// Define two lines of text for the card
|
||||
// We will center our text on these lines
|
||||
uint16_t lineAY = cardTopY + (fontLarge.lineHeight() / 2);
|
||||
uint16_t lineBY = cardTopY + fontLarge.lineHeight() + (fontSmall.lineHeight() / 2);
|
||||
uint16_t lineAY = cardTopY + (fontMedium.lineHeight() / 2);
|
||||
uint16_t lineBY = cardTopY + fontMedium.lineHeight() + (fontSmall.lineHeight() / 2);
|
||||
|
||||
// Print the short name
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(0, lineAY, shortName, LEFT, MIDDLE);
|
||||
|
||||
// Print the distance
|
||||
@@ -182,8 +182,8 @@ void InkHUD::NodeListApplet::onRender()
|
||||
// If we have a direct connection to the node, draw the signal indicator
|
||||
if (hopsAway == 0 && signal != SIGNAL_UNKNOWN) {
|
||||
uint16_t signalW = getTextWidth("Xkm"); // Indicator should be similar width to distance label
|
||||
uint16_t signalH = fontLarge.lineHeight() * 0.75;
|
||||
int16_t signalY = lineAY + (fontLarge.lineHeight() / 2) - (fontLarge.lineHeight() * 0.75);
|
||||
uint16_t signalH = fontMedium.lineHeight() * 0.75;
|
||||
int16_t signalY = lineAY + (fontMedium.lineHeight() / 2) - (fontMedium.lineHeight() * 0.75);
|
||||
int16_t signalX = width() - signalW;
|
||||
drawSignalIndicator(signalX, signalY, signalW, signalH, signal);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ class NodeListApplet : public Applet, public MeshModule
|
||||
|
||||
// Card Dimensions
|
||||
// - for rendering and for maxCards calc
|
||||
const uint8_t cardMarginH = fontSmall.lineHeight() / 2; // Gap between cards
|
||||
const uint16_t cardH = fontLarge.lineHeight() + fontSmall.lineHeight() + cardMarginH; // Height of card
|
||||
uint8_t cardMarginH = fontSmall.lineHeight() / 2; // Gap between cards
|
||||
uint16_t cardH = fontMedium.lineHeight() + fontSmall.lineHeight() + cardMarginH; // Height of card
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
@@ -15,7 +15,7 @@ InkHUD::LogoApplet::LogoApplet() : concurrency::OSThread("LogoApplet")
|
||||
// This behavior assists manufacturers during mass production, and should not be modified without good reason
|
||||
if (!settings->tips.safeShutdownSeen) {
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
fontTitle = fontLarge;
|
||||
fontTitle = fontMedium;
|
||||
textLeft = xstr(APP_VERSION_SHORT);
|
||||
textRight = parseShortName(ourNode);
|
||||
textTitle = "Meshtastic";
|
||||
@@ -52,6 +52,40 @@ void InkHUD::LogoApplet::onRender()
|
||||
setTextColor(WHITE);
|
||||
}
|
||||
|
||||
#ifdef USERPREFS_OEM_IMAGE_DATA // Custom boot screen, if defined in userPrefs.jsonc
|
||||
|
||||
// Only show the custom screen at startup
|
||||
// This allows us to draw the usual Meshtastic logo at shutdown
|
||||
// The effect is similar to the two-stage userPrefs boot screen used by BaseUI
|
||||
if (millis() < 10 * 1000UL) {
|
||||
|
||||
// Draw the custom logo
|
||||
const uint8_t logo[] = USERPREFS_OEM_IMAGE_DATA;
|
||||
drawXBitmap(logoCX - (USERPREFS_OEM_IMAGE_WIDTH / 2), // Left
|
||||
logoCY - (USERPREFS_OEM_IMAGE_HEIGHT / 2), // Top
|
||||
logo, // XBM data
|
||||
USERPREFS_OEM_IMAGE_WIDTH, // Width
|
||||
USERPREFS_OEM_IMAGE_HEIGHT, // Height
|
||||
inverted ? WHITE : BLACK // Color
|
||||
);
|
||||
|
||||
// Select the largest font which will still comfortably fit the custom text
|
||||
setFont(fontLarge);
|
||||
if (getTextWidth(USERPREFS_OEM_TEXT) > 0.8 * width())
|
||||
setFont(fontMedium);
|
||||
if (getTextWidth(USERPREFS_OEM_TEXT) > 0.8 * width())
|
||||
setFont(fontSmall);
|
||||
|
||||
// Draw custom text below logo
|
||||
int16_t logoB = logoCY + (USERPREFS_OEM_IMAGE_HEIGHT / 2); // Bottom of the logo
|
||||
printAt(X(0.5), logoB + Y(0.1), USERPREFS_OEM_TEXT, CENTER, TOP);
|
||||
|
||||
// Don't draw the normal boot screen, we've already drawn our custom version
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
drawLogo(logoCX, logoCY, logoW, logoH, inverted ? WHITE : BLACK);
|
||||
|
||||
if (!textLeft.empty()) {
|
||||
@@ -116,7 +150,7 @@ void InkHUD::LogoApplet::onShutdown()
|
||||
textLeft = "";
|
||||
textRight = "";
|
||||
textTitle = parseShortName(ourNode);
|
||||
fontTitle = fontLarge;
|
||||
fontTitle = fontMedium;
|
||||
|
||||
// This is then drawn by InkHUD::Events::onShutdown, with a blocking FULL update, after InkHUD's flash write is complete
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ enum MenuAction {
|
||||
LAYOUT,
|
||||
TOGGLE_BATTERY_ICON,
|
||||
TOGGLE_NOTIFICATIONS,
|
||||
TOGGLE_INVERT_COLOR,
|
||||
TOGGLE_12H_CLOCK,
|
||||
};
|
||||
|
||||
|
||||
@@ -205,6 +205,15 @@ void InkHUD::MenuApplet::execute(MenuItem item)
|
||||
settings->optionalFeatures.notifications = !settings->optionalFeatures.notifications;
|
||||
break;
|
||||
|
||||
case TOGGLE_INVERT_COLOR:
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED)
|
||||
config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
|
||||
else
|
||||
config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_INVERTED;
|
||||
|
||||
nodeDB->saveToDisk(SEGMENT_CONFIG);
|
||||
break;
|
||||
|
||||
case SET_RECENTS:
|
||||
// Set value of settings.recentlyActiveSeconds
|
||||
// Uses menu cursor to read RECENTS_OPTIONS_MINUTES array (defined at top of this file)
|
||||
@@ -214,7 +223,7 @@ void InkHUD::MenuApplet::execute(MenuItem item)
|
||||
|
||||
case SHUTDOWN:
|
||||
LOG_INFO("Shutting down from menu");
|
||||
power->shutdown();
|
||||
shutdownAtMsec = millis();
|
||||
// Menu is then sent to background via onShutdown
|
||||
break;
|
||||
|
||||
@@ -316,6 +325,10 @@ void InkHUD::MenuApplet::showPage(MenuPage page)
|
||||
&settings->optionalFeatures.notifications));
|
||||
items.push_back(MenuItem("Battery Icon", MenuAction::TOGGLE_BATTERY_ICON, MenuPage::OPTIONS,
|
||||
&settings->optionalFeatures.batteryIcon));
|
||||
|
||||
invertedColors = (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED);
|
||||
items.push_back(MenuItem("Invert Color", MenuAction::TOGGLE_INVERT_COLOR, MenuPage::OPTIONS, &invertedColors));
|
||||
|
||||
items.push_back(
|
||||
MenuItem("12-Hour Clock", MenuAction::TOGGLE_12H_CLOCK, MenuPage::OPTIONS, &config.display.use_12h_clock));
|
||||
items.push_back(MenuItem("Exit", MenuPage::EXIT));
|
||||
@@ -654,11 +667,11 @@ void InkHUD::MenuApplet::drawSystemInfoPanel(int16_t left, int16_t top, uint16_t
|
||||
// ====================
|
||||
std::string clockString = getTimeString();
|
||||
if (clockString.length() > 0) {
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(width / 2, top, clockString, CENTER, TOP);
|
||||
|
||||
height += fontLarge.lineHeight();
|
||||
height += fontLarge.lineHeight() * 0.1; // Padding below clock
|
||||
height += fontMedium.lineHeight();
|
||||
height += fontMedium.lineHeight() * 0.1; // Padding below clock
|
||||
}
|
||||
|
||||
// Stats
|
||||
|
||||
@@ -91,6 +91,8 @@ class MenuApplet : public SystemApplet, public concurrency::OSThread
|
||||
} cm;
|
||||
|
||||
Applet *borrowedTileOwner = nullptr; // Which applet we have temporarily replaced while displaying menu
|
||||
|
||||
bool invertedColors = false; // Helper to display current state of config.display.displaymode in InkHUD options
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
@@ -12,13 +12,13 @@ InkHUD::PairingApplet::PairingApplet()
|
||||
void InkHUD::PairingApplet::onRender()
|
||||
{
|
||||
// Header
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(X(0.5), Y(0.25), "Bluetooth", CENTER, BOTTOM);
|
||||
setFont(fontSmall);
|
||||
printAt(X(0.5), Y(0.25), "Enter this code", CENTER, TOP);
|
||||
|
||||
// Passkey
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printThick(X(0.5), Y(0.5), passkey.substr(0, 3) + " " + passkey.substr(3), 3, 2);
|
||||
|
||||
// Device's bluetooth name, if it will fit
|
||||
|
||||
@@ -50,11 +50,11 @@ void InkHUD::TipsApplet::onRender()
|
||||
break;
|
||||
|
||||
case Tip::FINISH_SETUP: {
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Finish Setup");
|
||||
|
||||
setFont(fontSmall);
|
||||
int16_t cursorY = fontLarge.lineHeight() * 1.5;
|
||||
int16_t cursorY = fontMedium.lineHeight() * 1.5;
|
||||
printAt(0, cursorY, "- connect antenna");
|
||||
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
@@ -80,7 +80,7 @@ void InkHUD::TipsApplet::onRender()
|
||||
} break;
|
||||
|
||||
case Tip::SAFE_SHUTDOWN: {
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Shutdown");
|
||||
|
||||
setFont(fontSmall);
|
||||
@@ -88,29 +88,29 @@ void InkHUD::TipsApplet::onRender()
|
||||
shutdown += "Before removing power, please shut down from InkHUD menu, or a client app. \n";
|
||||
shutdown += "\n";
|
||||
shutdown += "This ensures data is saved.";
|
||||
printWrapped(0, fontLarge.lineHeight() * 1.5, width(), shutdown);
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(), shutdown);
|
||||
|
||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||
|
||||
} break;
|
||||
|
||||
case Tip::CUSTOMIZATION: {
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Customization");
|
||||
|
||||
setFont(fontSmall);
|
||||
printWrapped(0, fontLarge.lineHeight() * 1.5, width(),
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
||||
"Configure & control display with the InkHUD menu. Optional features, layout, rotation, and more.");
|
||||
|
||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||
} break;
|
||||
|
||||
case Tip::BUTTONS: {
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Buttons");
|
||||
|
||||
setFont(fontSmall);
|
||||
int16_t cursorY = fontLarge.lineHeight() * 1.5;
|
||||
int16_t cursorY = fontMedium.lineHeight() * 1.5;
|
||||
|
||||
printAt(0, cursorY, "User Button");
|
||||
cursorY += fontSmall.lineHeight() * 1.2;
|
||||
@@ -123,11 +123,11 @@ void InkHUD::TipsApplet::onRender()
|
||||
} break;
|
||||
|
||||
case Tip::ROTATION: {
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
printAt(0, 0, "Tip: Rotation");
|
||||
|
||||
setFont(fontSmall);
|
||||
printWrapped(0, fontLarge.lineHeight() * 1.5, width(),
|
||||
printWrapped(0, fontMedium.lineHeight() * 1.5, width(),
|
||||
"To rotate the display, use the InkHUD menu. Long-press the user button > Options > Rotate.");
|
||||
|
||||
printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM);
|
||||
@@ -155,7 +155,7 @@ void InkHUD::TipsApplet::renderWelcome()
|
||||
uint16_t logoH = getLogoHeight(logoWLimit, logoHLimit);
|
||||
|
||||
// Title size
|
||||
setFont(fontLarge);
|
||||
setFont(fontMedium);
|
||||
std::string title;
|
||||
if (width() >= 200) // Future proofing: hide if *tiny* display
|
||||
title = "meshtastic.org";
|
||||
|
||||
@@ -101,15 +101,25 @@ void InkHUD::AllMessageApplet::onRender()
|
||||
// Extra gap below the header
|
||||
int16_t textTop = headerDivY + padDivH;
|
||||
|
||||
// Determine size if printed large
|
||||
// Attempt to print with fontLarge
|
||||
uint32_t textHeight;
|
||||
setFont(fontLarge);
|
||||
uint32_t textHeight = getWrappedTextHeight(0, width(), text);
|
||||
textHeight = getWrappedTextHeight(0, width(), text);
|
||||
if (textHeight <= (uint32_t)height()) {
|
||||
printWrapped(0, textTop, width(), text);
|
||||
return;
|
||||
}
|
||||
|
||||
// If too large, swap to small font
|
||||
if (textHeight + textTop > (uint32_t)height()) // (compare signed and unsigned)
|
||||
setFont(fontSmall);
|
||||
// Fallback (too large): attempt to print with fontMedium
|
||||
setFont(fontMedium);
|
||||
textHeight = getWrappedTextHeight(0, width(), text);
|
||||
if (textHeight <= (uint32_t)height()) {
|
||||
printWrapped(0, textTop, width(), text);
|
||||
return;
|
||||
}
|
||||
|
||||
// Print text
|
||||
// Fallback (too large): print with fontSmall
|
||||
setFont(fontSmall);
|
||||
printWrapped(0, textTop, width(), text);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,15 +97,25 @@ void InkHUD::DMApplet::onRender()
|
||||
// Extra gap below the header
|
||||
int16_t textTop = headerDivY + padDivH;
|
||||
|
||||
// Determine size if printed large
|
||||
// Attempt to print with fontLarge
|
||||
uint32_t textHeight;
|
||||
setFont(fontLarge);
|
||||
uint32_t textHeight = getWrappedTextHeight(0, width(), text);
|
||||
textHeight = getWrappedTextHeight(0, width(), text);
|
||||
if (textHeight <= (uint32_t)height()) {
|
||||
printWrapped(0, textTop, width(), text);
|
||||
return;
|
||||
}
|
||||
|
||||
// If too large, swap to small font
|
||||
if (textHeight + textTop > (uint32_t)height()) // (compare signed and unsigned)
|
||||
setFont(fontSmall);
|
||||
// Fallback (too large): attempt to print with fontMedium
|
||||
setFont(fontMedium);
|
||||
textHeight = getWrappedTextHeight(0, width(), text);
|
||||
if (textHeight <= (uint32_t)height()) {
|
||||
printWrapped(0, textTop, width(), text);
|
||||
return;
|
||||
}
|
||||
|
||||
// Print text
|
||||
// Fallback (too large): print with fontSmall
|
||||
setFont(fontSmall);
|
||||
printWrapped(0, textTop, width(), text);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ void InkHUD::Events::begin()
|
||||
void InkHUD::Events::onButtonShort()
|
||||
{
|
||||
// Audio feedback (via buzzer)
|
||||
// Short low tone
|
||||
playBoop();
|
||||
// Short tone
|
||||
playChirp();
|
||||
// Cancel any beeping, buzzing, blinking
|
||||
// Some button handling suppressed if we are dismissing an external notification (see below)
|
||||
bool dismissedExt = dismissExternalNotification();
|
||||
@@ -64,8 +64,8 @@ void InkHUD::Events::onButtonShort()
|
||||
void InkHUD::Events::onButtonLong()
|
||||
{
|
||||
// Audio feedback (via buzzer)
|
||||
// Low tone, longer than playBoop
|
||||
playBeep();
|
||||
// Slightly longer than playChirp
|
||||
playBoop();
|
||||
|
||||
// Check which system applet wants to handle the button press (if any)
|
||||
SystemApplet *consumer = nullptr;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[inkhud]
|
||||
build_src_filter =
|
||||
+<graphics/niche/>; Include the nicheGraphics directory
|
||||
+<../variants/$PIOENV>; Include nicheGraphics.h from our variant folder
|
||||
build_flags =
|
||||
-D MESHTASTIC_INCLUDE_NICHE_GRAPHICS ; Use NicheGraphics
|
||||
-D MESHTASTIC_INCLUDE_INKHUD ; Use InkHUD (a NicheGraphics UI)
|
||||
|
||||
@@ -224,6 +224,13 @@ void InkHUD::Renderer::render(bool async)
|
||||
renderPlaceholders();
|
||||
renderSystemApplets();
|
||||
|
||||
// Invert Buffer if set by user
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
|
||||
for (size_t i = 0; i < imageBufferWidth * imageBufferHeight; ++i) {
|
||||
imageBuffer[i] = ~imageBuffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Tell display to begin process of drawing new image
|
||||
LOG_INFO("Updating display");
|
||||
driver->update(imageBuffer, updateType);
|
||||
|
||||
@@ -312,18 +312,19 @@ As a general overview:
|
||||
|
||||
## Fonts
|
||||
|
||||
InkHUD uses AdafruitGFX fonts. The large and small font which are shared by all applets are set in nicheGraphics.h.
|
||||
InkHUD uses AdafruitGFX fonts. Three shared fonts (small, medium, large) are available for use by all applets. These are set per-variant in nicheGraphics.h.
|
||||
|
||||
```cpp
|
||||
// Prepare fonts
|
||||
InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252;
|
||||
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;
|
||||
InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252;
|
||||
InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252;
|
||||
|
||||
// Using a generic AdafruitGFX font instead:
|
||||
// InkHUD::Applet::fontLarge = FreeSerif9pt7b;
|
||||
// InkHUD::Applet::fontLarge = FreeSerif18pt7b;
|
||||
```
|
||||
|
||||
Any generic AdafruitGFX font may be used, but the fonts which are bundled with InkHUD have been customized with extended-ASCII character sets.
|
||||
Any generic AdafruitGFX font may be used, but the fonts which are bundled with InkHUD have been customized with extended-ASCII character sets and emoji.
|
||||
|
||||
### Parsing Unicode Text
|
||||
|
||||
@@ -351,10 +352,12 @@ InkHUD is bundled with extended-ASCII fonts for:
|
||||
The default builds use Windows-1252 encoding. This can be changed in nicheGraphics.h.
|
||||
|
||||
```cpp
|
||||
InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1250;
|
||||
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1250;
|
||||
InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1250;
|
||||
InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1250;
|
||||
|
||||
InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1251;
|
||||
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1251;
|
||||
InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1251;
|
||||
InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1251;
|
||||
```
|
||||
|
||||
|
||||
+21
-23
@@ -53,23 +53,21 @@ bool ButtonThread::initButton(const ButtonConfig &config)
|
||||
},
|
||||
this);
|
||||
|
||||
if (config.longPress != INPUT_BROKER_NONE) {
|
||||
_longPress = config.longPress;
|
||||
userButton.attachLongPressStart(
|
||||
[](void *callerThread) -> void {
|
||||
ButtonThread *thread = (ButtonThread *)callerThread;
|
||||
// if (millis() > 30000) // hold off 30s after boot
|
||||
thread->btnEvent = BUTTON_EVENT_LONG_PRESSED;
|
||||
},
|
||||
this);
|
||||
userButton.attachLongPressStop(
|
||||
[](void *callerThread) -> void {
|
||||
ButtonThread *thread = (ButtonThread *)callerThread;
|
||||
// if (millis() > 30000) // hold off 30s after boot
|
||||
thread->btnEvent = BUTTON_EVENT_LONG_RELEASED;
|
||||
},
|
||||
this);
|
||||
}
|
||||
_longPress = config.longPress;
|
||||
userButton.attachLongPressStart(
|
||||
[](void *callerThread) -> void {
|
||||
ButtonThread *thread = (ButtonThread *)callerThread;
|
||||
// if (millis() > 30000) // hold off 30s after boot
|
||||
thread->btnEvent = BUTTON_EVENT_LONG_PRESSED;
|
||||
},
|
||||
this);
|
||||
userButton.attachLongPressStop(
|
||||
[](void *callerThread) -> void {
|
||||
ButtonThread *thread = (ButtonThread *)callerThread;
|
||||
// if (millis() > 30000) // hold off 30s after boot
|
||||
thread->btnEvent = BUTTON_EVENT_LONG_RELEASED;
|
||||
},
|
||||
this);
|
||||
|
||||
if (config.doublePress != INPUT_BROKER_NONE) {
|
||||
_doublePress = config.doublePress;
|
||||
@@ -202,11 +200,11 @@ int32_t ButtonThread::runOnce()
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Forward long press to InputBroker (but NOT as DOWN/SELECT, just forward a "button long press" event)
|
||||
evt.inputEvent = _longPress;
|
||||
this->notifyObservers(&evt);
|
||||
|
||||
if (_longPress != INPUT_BROKER_NONE) {
|
||||
// Forward long press to InputBroker (but NOT as DOWN/SELECT, just forward a "button long press" event)
|
||||
evt.inputEvent = _longPress;
|
||||
this->notifyObservers(&evt);
|
||||
}
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
@@ -253,7 +251,7 @@ int32_t ButtonThread::runOnce()
|
||||
// may wake the board immediatedly.
|
||||
case BUTTON_EVENT_LONG_RELEASED: {
|
||||
|
||||
LOG_INFO("LONG PRESS RELEASE");
|
||||
LOG_INFO("LONG PRESS RELEASE AFTER %u MILLIS", millis() - buttonPressStartTime);
|
||||
if (millis() > 30000 && _longLongPress != INPUT_BROKER_NONE &&
|
||||
(millis() - buttonPressStartTime) >= _longLongPressTime) {
|
||||
evt.inputEvent = _longLongPress;
|
||||
|
||||
@@ -18,13 +18,13 @@ struct ButtonConfig {
|
||||
uint16_t longPressTime = 500;
|
||||
input_broker_event doublePress = INPUT_BROKER_NONE;
|
||||
input_broker_event longLongPress = INPUT_BROKER_NONE;
|
||||
uint16_t longLongPressTime = 5000;
|
||||
uint16_t longLongPressTime = 3900;
|
||||
input_broker_event triplePress = INPUT_BROKER_NONE;
|
||||
input_broker_event shortLong = INPUT_BROKER_NONE;
|
||||
bool touchQuirk = false;
|
||||
|
||||
// Constructor to set required parameter
|
||||
ButtonConfig(uint8_t pin = 0) : pinNumber(pin) {}
|
||||
explicit ButtonConfig(uint8_t pin = 0) : pinNumber(pin) {}
|
||||
};
|
||||
|
||||
#ifndef BUTTON_CLICK_MS
|
||||
@@ -62,7 +62,7 @@ class ButtonThread : public Observable<const InputEvent *>, public concurrency::
|
||||
BUTTON_EVENT_COMBO_SHORT_LONG,
|
||||
};
|
||||
|
||||
ButtonThread(const char *name);
|
||||
explicit ButtonThread(const char *name);
|
||||
int32_t runOnce() override;
|
||||
OneButton userButton;
|
||||
void attachButtonInterrupts();
|
||||
|
||||
@@ -199,7 +199,7 @@ void ExpressLRSFiveWay::sendKey(input_broker_event key)
|
||||
void ExpressLRSFiveWay::toggleGPS()
|
||||
{
|
||||
#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS
|
||||
if (!config.device.disable_triple_click && (gps != nullptr)) {
|
||||
if (gps != nullptr) {
|
||||
gps->toggleGpsMode();
|
||||
screen->startAlert("GPS Toggled");
|
||||
alerting = true;
|
||||
@@ -233,14 +233,7 @@ void ExpressLRSFiveWay::sendAdhocPing()
|
||||
// Contained as one method for easier remapping of buttons by user
|
||||
void ExpressLRSFiveWay::shutdown()
|
||||
{
|
||||
LOG_INFO("Shutdown from long press");
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
screen->startAlert("Shutting Down...");
|
||||
// Don't set alerting = true. We don't want to auto-dismiss this alert.
|
||||
|
||||
playShutdownMelody(); // In case user adds a buzzer
|
||||
|
||||
shutdownAtMsec = millis() + 3000;
|
||||
sendKey(INPUT_BROKER_SHUTDOWN);
|
||||
}
|
||||
|
||||
void ExpressLRSFiveWay::click()
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "SeesawRotary.h"
|
||||
#include "input/InputBroker.h"
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
SeesawRotary *seesawRotary;
|
||||
|
||||
SeesawRotary::SeesawRotary(const char *name) : OSThread(name)
|
||||
{
|
||||
_originName = name;
|
||||
}
|
||||
|
||||
bool SeesawRotary::init()
|
||||
{
|
||||
if (inputBroker)
|
||||
inputBroker->registerSource(this);
|
||||
|
||||
if (!ss.begin(SEESAW_ADDR)) {
|
||||
return false;
|
||||
}
|
||||
// attachButtonInterrupts();
|
||||
|
||||
uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF);
|
||||
if (version != 4991) {
|
||||
LOG_WARN("Wrong firmware loaded? %u", version);
|
||||
} else {
|
||||
LOG_INFO("Found Product 4991");
|
||||
}
|
||||
/*
|
||||
#ifdef ARCH_ESP32
|
||||
// Register callbacks for before and after lightsleep
|
||||
// Used to detach and reattach interrupts
|
||||
lsObserver.observe(¬ifyLightSleep);
|
||||
lsEndObserver.observe(¬ifyLightSleepEnd);
|
||||
#endif
|
||||
*/
|
||||
ss.pinMode(SS_SWITCH, INPUT_PULLUP);
|
||||
|
||||
// get starting position
|
||||
encoder_position = ss.getEncoderPosition();
|
||||
|
||||
ss.setGPIOInterrupts((uint32_t)1 << SS_SWITCH, 1);
|
||||
ss.enableEncoderInterrupt();
|
||||
canSleep = true; // Assume we should not keep the board awake
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t SeesawRotary::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
bool currentlyPressed = !ss.digitalRead(SS_SWITCH);
|
||||
|
||||
if (currentlyPressed && !wasPressed) {
|
||||
e.inputEvent = INPUT_BROKER_SELECT;
|
||||
}
|
||||
wasPressed = currentlyPressed;
|
||||
|
||||
int32_t new_position = ss.getEncoderPosition();
|
||||
// did we move arounde?
|
||||
if (encoder_position != new_position) {
|
||||
if (encoder_position == 0 && new_position != 1) {
|
||||
e.inputEvent = INPUT_BROKER_ALT_PRESS;
|
||||
} else if (new_position == 0 && encoder_position != 1) {
|
||||
e.inputEvent = INPUT_BROKER_USER_PRESS;
|
||||
} else if (new_position > encoder_position) {
|
||||
e.inputEvent = INPUT_BROKER_USER_PRESS;
|
||||
} else {
|
||||
e.inputEvent = INPUT_BROKER_ALT_PRESS;
|
||||
}
|
||||
encoder_position = new_position;
|
||||
}
|
||||
if (e.inputEvent != INPUT_BROKER_NONE) {
|
||||
e.source = this->_originName;
|
||||
e.kbchar = 0x00;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
return 50;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#ifdef ARCH_PORTDUINO
|
||||
|
||||
#include "Adafruit_seesaw.h"
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#define SS_SWITCH 24
|
||||
#define SS_NEOPIX 6
|
||||
|
||||
#define SEESAW_ADDR 0x36
|
||||
|
||||
class SeesawRotary : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
const char *_originName;
|
||||
bool init();
|
||||
SeesawRotary(const char *name);
|
||||
int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
Adafruit_seesaw ss;
|
||||
int32_t encoder_position;
|
||||
bool wasPressed = false;
|
||||
};
|
||||
|
||||
extern SeesawRotary *seesawRotary;
|
||||
#endif
|
||||
+31
-454
@@ -1,116 +1,18 @@
|
||||
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||
|
||||
#include "TCA8418Keyboard.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// REGISTERS
|
||||
// #define _TCA8418_REG_RESERVED 0x00
|
||||
#define _TCA8418_REG_CFG 0x01 // Configuration register
|
||||
#define _TCA8418_REG_INT_STAT 0x02 // Interrupt status
|
||||
#define _TCA8418_REG_KEY_LCK_EC 0x03 // Key lock and event counter
|
||||
#define _TCA8418_REG_KEY_EVENT_A 0x04 // Key event register A
|
||||
#define _TCA8418_REG_KEY_EVENT_B 0x05 // Key event register B
|
||||
#define _TCA8418_REG_KEY_EVENT_C 0x06 // Key event register C
|
||||
#define _TCA8418_REG_KEY_EVENT_D 0x07 // Key event register D
|
||||
#define _TCA8418_REG_KEY_EVENT_E 0x08 // Key event register E
|
||||
#define _TCA8418_REG_KEY_EVENT_F 0x09 // Key event register F
|
||||
#define _TCA8418_REG_KEY_EVENT_G 0x0A // Key event register G
|
||||
#define _TCA8418_REG_KEY_EVENT_H 0x0B // Key event register H
|
||||
#define _TCA8418_REG_KEY_EVENT_I 0x0C // Key event register I
|
||||
#define _TCA8418_REG_KEY_EVENT_J 0x0D // Key event register J
|
||||
#define _TCA8418_REG_KP_LCK_TIMER 0x0E // Keypad lock1 to lock2 timer
|
||||
#define _TCA8418_REG_UNLOCK_1 0x0F // Unlock register 1
|
||||
#define _TCA8418_REG_UNLOCK_2 0x10 // Unlock register 2
|
||||
#define _TCA8418_REG_GPIO_INT_STAT_1 0x11 // GPIO interrupt status 1
|
||||
#define _TCA8418_REG_GPIO_INT_STAT_2 0x12 // GPIO interrupt status 2
|
||||
#define _TCA8418_REG_GPIO_INT_STAT_3 0x13 // GPIO interrupt status 3
|
||||
#define _TCA8418_REG_GPIO_DAT_STAT_1 0x14 // GPIO data status 1
|
||||
#define _TCA8418_REG_GPIO_DAT_STAT_2 0x15 // GPIO data status 2
|
||||
#define _TCA8418_REG_GPIO_DAT_STAT_3 0x16 // GPIO data status 3
|
||||
#define _TCA8418_REG_GPIO_DAT_OUT_1 0x17 // GPIO data out 1
|
||||
#define _TCA8418_REG_GPIO_DAT_OUT_2 0x18 // GPIO data out 2
|
||||
#define _TCA8418_REG_GPIO_DAT_OUT_3 0x19 // GPIO data out 3
|
||||
#define _TCA8418_REG_GPIO_INT_EN_1 0x1A // GPIO interrupt enable 1
|
||||
#define _TCA8418_REG_GPIO_INT_EN_2 0x1B // GPIO interrupt enable 2
|
||||
#define _TCA8418_REG_GPIO_INT_EN_3 0x1C // GPIO interrupt enable 3
|
||||
#define _TCA8418_REG_KP_GPIO_1 0x1D // Keypad/GPIO select 1
|
||||
#define _TCA8418_REG_KP_GPIO_2 0x1E // Keypad/GPIO select 2
|
||||
#define _TCA8418_REG_KP_GPIO_3 0x1F // Keypad/GPIO select 3
|
||||
#define _TCA8418_REG_GPI_EM_1 0x20 // GPI event mode 1
|
||||
#define _TCA8418_REG_GPI_EM_2 0x21 // GPI event mode 2
|
||||
#define _TCA8418_REG_GPI_EM_3 0x22 // GPI event mode 3
|
||||
#define _TCA8418_REG_GPIO_DIR_1 0x23 // GPIO data direction 1
|
||||
#define _TCA8418_REG_GPIO_DIR_2 0x24 // GPIO data direction 2
|
||||
#define _TCA8418_REG_GPIO_DIR_3 0x25 // GPIO data direction 3
|
||||
#define _TCA8418_REG_GPIO_INT_LVL_1 0x26 // GPIO edge/level detect 1
|
||||
#define _TCA8418_REG_GPIO_INT_LVL_2 0x27 // GPIO edge/level detect 2
|
||||
#define _TCA8418_REG_GPIO_INT_LVL_3 0x28 // GPIO edge/level detect 3
|
||||
#define _TCA8418_REG_DEBOUNCE_DIS_1 0x29 // Debounce disable 1
|
||||
#define _TCA8418_REG_DEBOUNCE_DIS_2 0x2A // Debounce disable 2
|
||||
#define _TCA8418_REG_DEBOUNCE_DIS_3 0x2B // Debounce disable 3
|
||||
#define _TCA8418_REG_GPIO_PULL_1 0x2C // GPIO pull-up disable 1
|
||||
#define _TCA8418_REG_GPIO_PULL_2 0x2D // GPIO pull-up disable 2
|
||||
#define _TCA8418_REG_GPIO_PULL_3 0x2E // GPIO pull-up disable 3
|
||||
// #define _TCA8418_REG_RESERVED 0x2F
|
||||
|
||||
// FIELDS CONFIG REGISTER 1
|
||||
#define _TCA8418_REG_CFG_AI 0x80 // Auto-increment for read/write
|
||||
#define _TCA8418_REG_CFG_GPI_E_CGF 0x40 // Event mode config
|
||||
#define _TCA8418_REG_CFG_OVR_FLOW_M 0x20 // Overflow mode enable
|
||||
#define _TCA8418_REG_CFG_INT_CFG 0x10 // Interrupt config
|
||||
#define _TCA8418_REG_CFG_OVR_FLOW_IEN 0x08 // Overflow interrupt enable
|
||||
#define _TCA8418_REG_CFG_K_LCK_IEN 0x04 // Keypad lock interrupt enable
|
||||
#define _TCA8418_REG_CFG_GPI_IEN 0x02 // GPI interrupt enable
|
||||
#define _TCA8418_REG_CFG_KE_IEN 0x01 // Key events interrupt enable
|
||||
|
||||
// FIELDS INT_STAT REGISTER 2
|
||||
#define _TCA8418_REG_STAT_CAD_INT 0x10 // Ctrl-alt-del seq status
|
||||
#define _TCA8418_REG_STAT_OVR_FLOW_INT 0x08 // Overflow interrupt status
|
||||
#define _TCA8418_REG_STAT_K_LCK_INT 0x04 // Key lock interrupt status
|
||||
#define _TCA8418_REG_STAT_GPI_INT 0x02 // GPI interrupt status
|
||||
#define _TCA8418_REG_STAT_K_INT 0x01 // Key events interrupt status
|
||||
|
||||
// FIELDS KEY_LCK_EC REGISTER 3
|
||||
#define _TCA8418_REG_LCK_EC_K_LCK_EN 0x40 // Key lock enable
|
||||
#define _TCA8418_REG_LCK_EC_LCK_2 0x20 // Keypad lock status 2
|
||||
#define _TCA8418_REG_LCK_EC_LCK_1 0x10 // Keypad lock status 1
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_3 0x08 // Key event count bit 3
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_2 0x04 // Key event count bit 2
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_1 0x02 // Key event count bit 1
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_0 0x01 // Key event count bit 0
|
||||
|
||||
// Pin IDs for matrix rows/columns
|
||||
enum {
|
||||
_TCA8418_ROW0, // Pin ID for row 0
|
||||
_TCA8418_ROW1, // Pin ID for row 1
|
||||
_TCA8418_ROW2, // Pin ID for row 2
|
||||
_TCA8418_ROW3, // Pin ID for row 3
|
||||
_TCA8418_ROW4, // Pin ID for row 4
|
||||
_TCA8418_ROW5, // Pin ID for row 5
|
||||
_TCA8418_ROW6, // Pin ID for row 6
|
||||
_TCA8418_ROW7, // Pin ID for row 7
|
||||
_TCA8418_COL0, // Pin ID for column 0
|
||||
_TCA8418_COL1, // Pin ID for column 1
|
||||
_TCA8418_COL2, // Pin ID for column 2
|
||||
_TCA8418_COL3, // Pin ID for column 3
|
||||
_TCA8418_COL4, // Pin ID for column 4
|
||||
_TCA8418_COL5, // Pin ID for column 5
|
||||
_TCA8418_COL6, // Pin ID for column 6
|
||||
_TCA8418_COL7, // Pin ID for column 7
|
||||
_TCA8418_COL8, // Pin ID for column 8
|
||||
_TCA8418_COL9 // Pin ID for column 9
|
||||
};
|
||||
|
||||
#define _TCA8418_COLS 3
|
||||
#define _TCA8418_ROWS 4
|
||||
#define _TCA8418_NUM_KEYS 12
|
||||
|
||||
uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {13, 7, 7, 7, 7, 7,
|
||||
9, 7, 9, 2, 2, 2}; // Num chars per key, Modulus for rotating through characters
|
||||
#define _TCA8418_LONG_PRESS_THRESHOLD 2000
|
||||
#define _TCA8418_MULTI_TAP_THRESHOLD 750
|
||||
|
||||
unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
||||
using Key = TCA8418KeyboardBase::TCA8418Key;
|
||||
|
||||
// Num chars per key, Modulus for rotating through characters
|
||||
static uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {13, 7, 7, 7, 7, 7, 9, 7, 9, 2, 2, 2};
|
||||
|
||||
static unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
||||
{'1', '.', ',', '?', '!', ':', ';', '-', '_', '\\', '/', '(', ')'}, // 1
|
||||
{'2', 'a', 'b', 'c', 'A', 'B', 'C'}, // 2
|
||||
{'3', 'd', 'e', 'f', 'D', 'E', 'F'}, // 3
|
||||
@@ -125,176 +27,35 @@ unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
||||
{'#', '@'}, // #
|
||||
};
|
||||
|
||||
unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
||||
_TCA8418_ESC, // 1
|
||||
_TCA8418_UP, // 2
|
||||
_TCA8418_NONE, // 3
|
||||
_TCA8418_LEFT, // 4
|
||||
_TCA8418_NONE, // 5
|
||||
_TCA8418_RIGHT, // 6
|
||||
_TCA8418_NONE, // 7
|
||||
_TCA8418_DOWN, // 8
|
||||
_TCA8418_NONE, // 9
|
||||
_TCA8418_BSP, // *
|
||||
_TCA8418_NONE, // 0
|
||||
_TCA8418_NONE, // #
|
||||
static unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
||||
Key::ESC, // 1
|
||||
Key::UP, // 2
|
||||
Key::NONE, // 3
|
||||
Key::LEFT, // 4
|
||||
Key::NONE, // 5
|
||||
Key::RIGHT, // 6
|
||||
Key::NONE, // 7
|
||||
Key::DOWN, // 8
|
||||
Key::NONE, // 9
|
||||
Key::BSP, // *
|
||||
Key::NONE, // 0
|
||||
Key::NONE, // #
|
||||
};
|
||||
|
||||
#define _TCA8418_LONG_PRESS_THRESHOLD 2000
|
||||
#define _TCA8418_MULTI_TAP_THRESHOLD 750
|
||||
|
||||
TCA8418Keyboard::TCA8418Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr)
|
||||
TCA8418Keyboard::TCA8418Keyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), last_key(-1), next_key(-1), last_tap(0L), char_idx(0), tap_interval(0),
|
||||
should_backspace(false)
|
||||
{
|
||||
state = Init;
|
||||
last_key = -1;
|
||||
should_backspace = false;
|
||||
last_tap = 0L;
|
||||
char_idx = 0;
|
||||
tap_interval = 0;
|
||||
backlight_on = true;
|
||||
queue = "";
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::begin(uint8_t addr, TwoWire *wire)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = wire;
|
||||
|
||||
m_wire->begin();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = nullptr;
|
||||
writeCallback = w;
|
||||
readCallback = r;
|
||||
reset();
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::reset()
|
||||
{
|
||||
LOG_DEBUG("TCA8418 Reset");
|
||||
// GPIO
|
||||
// set default all GIO pins to INPUT
|
||||
writeRegister(_TCA8418_REG_GPIO_DIR_1, 0x00);
|
||||
writeRegister(_TCA8418_REG_GPIO_DIR_2, 0x00);
|
||||
TCA8418KeyboardBase::reset();
|
||||
|
||||
// Set COL9 as GPIO output
|
||||
writeRegister(_TCA8418_REG_GPIO_DIR_3, 0x02);
|
||||
writeRegister(TCA8418_REG_GPIO_DIR_3, 0x02);
|
||||
// Switch off keyboard backlight (COL9 = LOW)
|
||||
writeRegister(_TCA8418_REG_GPIO_DAT_OUT_3, 0x00);
|
||||
|
||||
// add all pins to key events
|
||||
writeRegister(_TCA8418_REG_GPI_EM_1, 0xFF);
|
||||
writeRegister(_TCA8418_REG_GPI_EM_2, 0xFF);
|
||||
writeRegister(_TCA8418_REG_GPI_EM_3, 0xFF);
|
||||
|
||||
// set all pins to FALLING interrupts
|
||||
writeRegister(_TCA8418_REG_GPIO_INT_LVL_1, 0x00);
|
||||
writeRegister(_TCA8418_REG_GPIO_INT_LVL_2, 0x00);
|
||||
writeRegister(_TCA8418_REG_GPIO_INT_LVL_3, 0x00);
|
||||
|
||||
// add all pins to interrupts
|
||||
writeRegister(_TCA8418_REG_GPIO_INT_EN_1, 0xFF);
|
||||
writeRegister(_TCA8418_REG_GPIO_INT_EN_2, 0xFF);
|
||||
writeRegister(_TCA8418_REG_GPIO_INT_EN_3, 0xFF);
|
||||
|
||||
// Set keyboard matrix size
|
||||
matrix(_TCA8418_ROWS, _TCA8418_COLS);
|
||||
enableDebounce();
|
||||
flush();
|
||||
state = Idle;
|
||||
}
|
||||
|
||||
bool TCA8418Keyboard::matrix(uint8_t rows, uint8_t columns)
|
||||
{
|
||||
if ((rows > 8) || (columns > 10))
|
||||
return false;
|
||||
|
||||
// Skip zero size matrix
|
||||
if ((rows != 0) && (columns != 0)) {
|
||||
// Setup the keypad matrix.
|
||||
uint8_t mask = 0x00;
|
||||
for (int r = 0; r < rows; r++) {
|
||||
mask <<= 1;
|
||||
mask |= 1;
|
||||
}
|
||||
writeRegister(_TCA8418_REG_KP_GPIO_1, mask);
|
||||
|
||||
mask = 0x00;
|
||||
for (int c = 0; c < columns && c < 8; c++) {
|
||||
mask <<= 1;
|
||||
mask |= 1;
|
||||
}
|
||||
writeRegister(_TCA8418_REG_KP_GPIO_2, mask);
|
||||
|
||||
if (columns > 8) {
|
||||
if (columns == 9)
|
||||
mask = 0x01;
|
||||
else
|
||||
mask = 0x03;
|
||||
writeRegister(_TCA8418_REG_KP_GPIO_3, mask);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t TCA8418Keyboard::keyCount() const
|
||||
{
|
||||
uint8_t eventCount = readRegister(_TCA8418_REG_KEY_LCK_EC);
|
||||
eventCount &= 0x0F; // lower 4 bits only
|
||||
return eventCount;
|
||||
}
|
||||
|
||||
bool TCA8418Keyboard::hasEvent()
|
||||
{
|
||||
return queue.length() > 0;
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::queueEvent(char next)
|
||||
{
|
||||
if (next == _TCA8418_NONE) {
|
||||
return;
|
||||
}
|
||||
queue.concat(next);
|
||||
}
|
||||
|
||||
char TCA8418Keyboard::dequeueEvent()
|
||||
{
|
||||
if (queue.length() < 1) {
|
||||
return _TCA8418_NONE;
|
||||
}
|
||||
char next = queue.charAt(0);
|
||||
queue.remove(0, 1);
|
||||
return next;
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::trigger()
|
||||
{
|
||||
if (keyCount() == 0) {
|
||||
return;
|
||||
}
|
||||
if (state != Init) {
|
||||
// Read the key register
|
||||
uint8_t k = readRegister(_TCA8418_REG_KEY_EVENT_A);
|
||||
uint8_t key = k & 0x7F;
|
||||
if (k & 0x80) {
|
||||
if (state == Idle)
|
||||
pressed(key);
|
||||
return;
|
||||
} else {
|
||||
if (state == Held) {
|
||||
released();
|
||||
}
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
writeRegister(TCA8418_REG_GPIO_DAT_OUT_3, 0x00);
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::pressed(uint8_t key)
|
||||
@@ -354,7 +115,7 @@ void TCA8418Keyboard::released()
|
||||
int32_t held_interval = now - last_tap;
|
||||
last_tap = now;
|
||||
if (tap_interval < _TCA8418_MULTI_TAP_THRESHOLD && should_backspace) {
|
||||
queueEvent(_TCA8418_BSP);
|
||||
queueEvent(BSP);
|
||||
}
|
||||
if (held_interval > _TCA8418_LONG_PRESS_THRESHOLD) {
|
||||
queueEvent(TCA8418LongPressMap[last_key]);
|
||||
@@ -366,195 +127,11 @@ void TCA8418Keyboard::released()
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t TCA8418Keyboard::flush()
|
||||
{
|
||||
// Flush key events
|
||||
uint8_t count = 0;
|
||||
while (readRegister(_TCA8418_REG_KEY_EVENT_A) != 0)
|
||||
count++;
|
||||
// Flush gpio events
|
||||
readRegister(_TCA8418_REG_GPIO_INT_STAT_1);
|
||||
readRegister(_TCA8418_REG_GPIO_INT_STAT_2);
|
||||
readRegister(_TCA8418_REG_GPIO_INT_STAT_3);
|
||||
// Clear INT_STAT register
|
||||
writeRegister(_TCA8418_REG_INT_STAT, 3);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t TCA8418Keyboard::digitalRead(uint8_t pinnum) const
|
||||
{
|
||||
if (pinnum > _TCA8418_COL9)
|
||||
return 0xFF;
|
||||
|
||||
uint8_t reg = _TCA8418_REG_GPIO_DAT_STAT_1 + pinnum / 8;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
// Level 0 = low other = high
|
||||
uint8_t value = readRegister(reg);
|
||||
if (value & mask)
|
||||
return HIGH;
|
||||
return LOW;
|
||||
}
|
||||
|
||||
bool TCA8418Keyboard::digitalWrite(uint8_t pinnum, uint8_t level)
|
||||
{
|
||||
if (pinnum > _TCA8418_COL9)
|
||||
return false;
|
||||
|
||||
uint8_t reg = _TCA8418_REG_GPIO_DAT_OUT_1 + pinnum / 8;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
// Level 0 = low other = high
|
||||
uint8_t value = readRegister(reg);
|
||||
if (level == LOW)
|
||||
value &= ~mask;
|
||||
else
|
||||
value |= mask;
|
||||
writeRegister(reg, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCA8418Keyboard::pinMode(uint8_t pinnum, uint8_t mode)
|
||||
{
|
||||
if (pinnum > _TCA8418_COL9)
|
||||
return false;
|
||||
|
||||
uint8_t idx = pinnum / 8;
|
||||
uint8_t reg = _TCA8418_REG_GPIO_DIR_1 + idx;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
// Mode 0 = input 1 = output
|
||||
uint8_t value = readRegister(reg);
|
||||
if (mode == OUTPUT)
|
||||
value |= mask;
|
||||
else
|
||||
value &= ~mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
// Pullup 0 = enabled 1 = disabled
|
||||
reg = _TCA8418_REG_GPIO_PULL_1 + idx;
|
||||
value = readRegister(reg);
|
||||
if (mode == INPUT_PULLUP)
|
||||
value &= ~mask;
|
||||
else
|
||||
value |= mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCA8418Keyboard::pinIRQMode(uint8_t pinnum, uint8_t mode)
|
||||
{
|
||||
if (pinnum > _TCA8418_COL9)
|
||||
return false;
|
||||
if ((mode != RISING) && (mode != FALLING))
|
||||
return false;
|
||||
|
||||
// Mode 0 = falling 1 = rising
|
||||
uint8_t idx = pinnum / 8;
|
||||
uint8_t reg = _TCA8418_REG_GPIO_INT_LVL_1 + idx;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
uint8_t value = readRegister(reg);
|
||||
if (mode == RISING)
|
||||
value |= mask;
|
||||
else
|
||||
value &= ~mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
// Enable interrupt
|
||||
reg = _TCA8418_REG_GPIO_INT_EN_1 + idx;
|
||||
value = readRegister(reg);
|
||||
value |= mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::enableInterrupts()
|
||||
{
|
||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||
value |= (_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||
writeRegister(_TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418Keyboard::disableInterrupts()
|
||||
{
|
||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||
value &= ~(_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||
writeRegister(_TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418Keyboard::enableMatrixOverflow()
|
||||
{
|
||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||
value |= _TCA8418_REG_CFG_OVR_FLOW_M;
|
||||
writeRegister(_TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418Keyboard::disableMatrixOverflow()
|
||||
{
|
||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||
value &= ~_TCA8418_REG_CFG_OVR_FLOW_M;
|
||||
writeRegister(_TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418Keyboard::enableDebounce()
|
||||
{
|
||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_1, 0x00);
|
||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_2, 0x00);
|
||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_3, 0x00);
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::disableDebounce()
|
||||
{
|
||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_1, 0xFF);
|
||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_2, 0xFF);
|
||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_3, 0xFF);
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::setBacklight(bool on)
|
||||
{
|
||||
if (on) {
|
||||
digitalWrite(_TCA8418_COL9, HIGH);
|
||||
digitalWrite(TCA8418_COL9, HIGH);
|
||||
} else {
|
||||
digitalWrite(_TCA8418_COL9, LOW);
|
||||
digitalWrite(TCA8418_COL9, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t TCA8418Keyboard::readRegister(uint8_t reg) const
|
||||
{
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(reg);
|
||||
m_wire->endTransmission();
|
||||
|
||||
m_wire->requestFrom(m_addr, (uint8_t)1);
|
||||
if (m_wire->available() < 1)
|
||||
return 0;
|
||||
|
||||
return m_wire->read();
|
||||
}
|
||||
if (readCallback) {
|
||||
uint8_t data;
|
||||
readCallback(m_addr, reg, &data, 1);
|
||||
return data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TCA8418Keyboard::writeRegister(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = reg;
|
||||
data[1] = value;
|
||||
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(data, sizeof(uint8_t) * 2);
|
||||
m_wire->endTransmission();
|
||||
}
|
||||
if (writeCallback) {
|
||||
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||
}
|
||||
}
|
||||
+13
-72
@@ -1,82 +1,23 @@
|
||||
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||
#include "configuration.h"
|
||||
#include <Wire.h>
|
||||
#include "TCA8418KeyboardBase.h"
|
||||
|
||||
#define _TCA8418_NONE 0x00
|
||||
#define _TCA8418_REBOOT 0x90
|
||||
#define _TCA8418_LEFT 0xb4
|
||||
#define _TCA8418_UP 0xb5
|
||||
#define _TCA8418_DOWN 0xb6
|
||||
#define _TCA8418_RIGHT 0xb7
|
||||
#define _TCA8418_ESC 0x1b
|
||||
#define _TCA8418_BSP 0x08
|
||||
#define _TCA8418_SELECT 0x0d
|
||||
|
||||
class TCA8418Keyboard
|
||||
/**
|
||||
* @brief 3x4 keypad with 3 columns and 4 rows
|
||||
*/
|
||||
class TCA8418Keyboard : public TCA8418KeyboardBase
|
||||
{
|
||||
public:
|
||||
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||
TCA8418Keyboard();
|
||||
void reset(void) override;
|
||||
void setBacklight(bool on) override;
|
||||
|
||||
enum KeyState { Init = 0, Idle, Held, Busy };
|
||||
protected:
|
||||
void pressed(uint8_t key) override;
|
||||
void released(void) override;
|
||||
|
||||
KeyState state;
|
||||
int8_t last_key;
|
||||
bool should_backspace;
|
||||
int8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
bool backlight_on;
|
||||
|
||||
String queue;
|
||||
|
||||
TCA8418Keyboard();
|
||||
|
||||
void begin(uint8_t addr = XPOWERS_AXP192_AXP2101_ADDRESS, TwoWire *wire = &Wire);
|
||||
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = XPOWERS_AXP192_AXP2101_ADDRESS);
|
||||
|
||||
void reset(void);
|
||||
// Configure the size of the keypad.
|
||||
// All other rows and columns are set as inputs.
|
||||
bool matrix(uint8_t rows, uint8_t columns);
|
||||
|
||||
// Flush all events in the FIFO buffer + GPIO events.
|
||||
uint8_t flush(void);
|
||||
|
||||
// Key events available in the internal FIFO buffer.
|
||||
uint8_t keyCount(void) const;
|
||||
|
||||
void trigger(void);
|
||||
void pressed(uint8_t key);
|
||||
void released(void);
|
||||
bool hasEvent(void);
|
||||
char dequeueEvent(void);
|
||||
void queueEvent(char);
|
||||
|
||||
uint8_t digitalRead(uint8_t pinnum) const;
|
||||
bool digitalWrite(uint8_t pinnum, uint8_t level);
|
||||
bool pinMode(uint8_t pinnum, uint8_t mode);
|
||||
bool pinIRQMode(uint8_t pinnum, uint8_t mode); // MODE FALLING or RISING
|
||||
|
||||
// enable / disable interrupts for matrix and GPI pins
|
||||
void enableInterrupts();
|
||||
void disableInterrupts();
|
||||
|
||||
// ignore key events when FIFO buffer is full or not.
|
||||
void enableMatrixOverflow();
|
||||
void disableMatrixOverflow();
|
||||
|
||||
// debounce keys.
|
||||
void enableDebounce();
|
||||
void disableDebounce();
|
||||
|
||||
void setBacklight(bool on);
|
||||
|
||||
uint8_t readRegister(uint8_t reg) const;
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
|
||||
private:
|
||||
TwoWire *m_wire;
|
||||
uint8_t m_addr;
|
||||
i2c_com_fptr_t readCallback;
|
||||
i2c_com_fptr_t writeCallback;
|
||||
bool should_backspace;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||
|
||||
#include "TCA8418KeyboardBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// FIELDS CONFIG REGISTER 1
|
||||
#define _TCA8418_REG_CFG_AI 0x80 // Auto-increment for read/write
|
||||
#define _TCA8418_REG_CFG_GPI_E_CGF 0x40 // Event mode config
|
||||
#define _TCA8418_REG_CFG_OVR_FLOW_M 0x20 // Overflow mode enable
|
||||
#define _TCA8418_REG_CFG_INT_CFG 0x10 // Interrupt config
|
||||
#define _TCA8418_REG_CFG_OVR_FLOW_IEN 0x08 // Overflow interrupt enable
|
||||
#define _TCA8418_REG_CFG_K_LCK_IEN 0x04 // Keypad lock interrupt enable
|
||||
#define _TCA8418_REG_CFG_GPI_IEN 0x02 // GPI interrupt enable
|
||||
#define _TCA8418_REG_CFG_KE_IEN 0x01 // Key events interrupt enable
|
||||
|
||||
// FIELDS INT_STAT REGISTER 2
|
||||
#define _TCA8418_REG_STAT_CAD_INT 0x10 // Ctrl-alt-del seq status
|
||||
#define _TCA8418_REG_STAT_OVR_FLOW_INT 0x08 // Overflow interrupt status
|
||||
#define _TCA8418_REG_STAT_K_LCK_INT 0x04 // Key lock interrupt status
|
||||
#define _TCA8418_REG_STAT_GPI_INT 0x02 // GPI interrupt status
|
||||
#define _TCA8418_REG_STAT_K_INT 0x01 // Key events interrupt status
|
||||
|
||||
// FIELDS KEY_LCK_EC REGISTER 3
|
||||
#define _TCA8418_REG_LCK_EC_K_LCK_EN 0x40 // Key lock enable
|
||||
#define _TCA8418_REG_LCK_EC_LCK_2 0x20 // Keypad lock status 2
|
||||
#define _TCA8418_REG_LCK_EC_LCK_1 0x10 // Keypad lock status 1
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_3 0x08 // Key event count bit 3
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_2 0x04 // Key event count bit 2
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_1 0x02 // Key event count bit 1
|
||||
#define _TCA8418_REG_LCK_EC_KLEC_0 0x01 // Key event count bit 0
|
||||
|
||||
TCA8418KeyboardBase::TCA8418KeyboardBase(uint8_t rows, uint8_t columns)
|
||||
: rows(rows), columns(columns), state(Init), queue(""), m_wire(nullptr), m_addr(0), readCallback(nullptr),
|
||||
writeCallback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::begin(uint8_t addr, TwoWire *wire)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = wire;
|
||||
m_wire->begin();
|
||||
reset();
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
||||
{
|
||||
m_addr = addr;
|
||||
m_wire = nullptr;
|
||||
writeCallback = w;
|
||||
readCallback = r;
|
||||
reset();
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::reset()
|
||||
{
|
||||
LOG_DEBUG("TCA8418 Reset");
|
||||
// GPIO
|
||||
// set default all GIO pins to INPUT
|
||||
writeRegister(TCA8418_REG_GPIO_DIR_1, 0x00);
|
||||
writeRegister(TCA8418_REG_GPIO_DIR_2, 0x00);
|
||||
writeRegister(TCA8418_REG_GPIO_DIR_3, 0x00);
|
||||
|
||||
// add all pins to key events
|
||||
writeRegister(TCA8418_REG_GPI_EM_1, 0xFF);
|
||||
writeRegister(TCA8418_REG_GPI_EM_2, 0xFF);
|
||||
writeRegister(TCA8418_REG_GPI_EM_3, 0xFF);
|
||||
|
||||
// set all pins to FALLING interrupts
|
||||
writeRegister(TCA8418_REG_GPIO_INT_LVL_1, 0x00);
|
||||
writeRegister(TCA8418_REG_GPIO_INT_LVL_2, 0x00);
|
||||
writeRegister(TCA8418_REG_GPIO_INT_LVL_3, 0x00);
|
||||
|
||||
// add all pins to interrupts
|
||||
writeRegister(TCA8418_REG_GPIO_INT_EN_1, 0xFF);
|
||||
writeRegister(TCA8418_REG_GPIO_INT_EN_2, 0xFF);
|
||||
writeRegister(TCA8418_REG_GPIO_INT_EN_3, 0xFF);
|
||||
|
||||
// Set keyboard matrix size
|
||||
matrix(rows, columns);
|
||||
enableDebounce();
|
||||
flush();
|
||||
state = Idle;
|
||||
}
|
||||
|
||||
bool TCA8418KeyboardBase::matrix(uint8_t rows, uint8_t columns)
|
||||
{
|
||||
if (rows < 1 || rows > 8 || columns < 1 || columns > 10)
|
||||
return false;
|
||||
|
||||
// Setup the keypad matrix.
|
||||
uint8_t mask = 0x00;
|
||||
for (int r = 0; r < rows; r++) {
|
||||
mask <<= 1;
|
||||
mask |= 1;
|
||||
}
|
||||
writeRegister(TCA8418_REG_KP_GPIO_1, mask);
|
||||
|
||||
mask = 0x00;
|
||||
for (int c = 0; c < columns && c < 8; c++) {
|
||||
mask <<= 1;
|
||||
mask |= 1;
|
||||
}
|
||||
writeRegister(TCA8418_REG_KP_GPIO_2, mask);
|
||||
|
||||
if (columns > 8) {
|
||||
if (columns == 9)
|
||||
mask = 0x01;
|
||||
else
|
||||
mask = 0x03;
|
||||
writeRegister(TCA8418_REG_KP_GPIO_3, mask);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t TCA8418KeyboardBase::keyCount() const
|
||||
{
|
||||
uint8_t eventCount = readRegister(TCA8418_REG_KEY_LCK_EC);
|
||||
eventCount &= 0x0F; // lower 4 bits only
|
||||
return eventCount;
|
||||
}
|
||||
|
||||
bool TCA8418KeyboardBase::hasEvent() const
|
||||
{
|
||||
return queue.length() > 0;
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::queueEvent(char next)
|
||||
{
|
||||
if (next == NONE) {
|
||||
return;
|
||||
}
|
||||
queue.concat(next);
|
||||
}
|
||||
|
||||
char TCA8418KeyboardBase::dequeueEvent()
|
||||
{
|
||||
if (queue.length() < 1) {
|
||||
return NONE;
|
||||
}
|
||||
char next = queue.charAt(0);
|
||||
queue.remove(0, 1);
|
||||
return next;
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::trigger()
|
||||
{
|
||||
if (keyCount() == 0) {
|
||||
return;
|
||||
}
|
||||
if (state != Init) {
|
||||
// Read the key register
|
||||
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A);
|
||||
uint8_t key = k & 0x7F;
|
||||
if (k & 0x80) {
|
||||
if (state == Idle)
|
||||
pressed(key);
|
||||
return;
|
||||
} else {
|
||||
if (state == Held) {
|
||||
released();
|
||||
}
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::pressed(uint8_t key)
|
||||
{
|
||||
// must be defined in derived class
|
||||
LOG_ERROR("pressed() not implemented in derived class");
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::released()
|
||||
{
|
||||
// must be defined in derived class
|
||||
LOG_ERROR("released() not implemented in derived class");
|
||||
}
|
||||
|
||||
uint8_t TCA8418KeyboardBase::flush()
|
||||
{
|
||||
// Flush key events
|
||||
uint8_t count = 0;
|
||||
while (readRegister(TCA8418_REG_KEY_EVENT_A) != 0)
|
||||
count++;
|
||||
|
||||
// Flush gpio events
|
||||
readRegister(TCA8418_REG_GPIO_INT_STAT_1);
|
||||
readRegister(TCA8418_REG_GPIO_INT_STAT_2);
|
||||
readRegister(TCA8418_REG_GPIO_INT_STAT_3);
|
||||
|
||||
// Clear INT_STAT register
|
||||
writeRegister(TCA8418_REG_INT_STAT, 3);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t TCA8418KeyboardBase::digitalRead(uint8_t pinnum) const
|
||||
{
|
||||
if (pinnum > TCA8418_COL9)
|
||||
return 0xFF;
|
||||
|
||||
uint8_t reg = TCA8418_REG_GPIO_DAT_STAT_1 + pinnum / 8;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
// Level 0 = low other = high
|
||||
uint8_t value = readRegister(reg);
|
||||
if (value & mask)
|
||||
return HIGH;
|
||||
return LOW;
|
||||
}
|
||||
|
||||
bool TCA8418KeyboardBase::digitalWrite(uint8_t pinnum, uint8_t level)
|
||||
{
|
||||
if (pinnum > TCA8418_COL9)
|
||||
return false;
|
||||
|
||||
uint8_t reg = TCA8418_REG_GPIO_DAT_OUT_1 + pinnum / 8;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
// Level 0 = low other = high
|
||||
uint8_t value = readRegister(reg);
|
||||
if (level == LOW)
|
||||
value &= ~mask;
|
||||
else
|
||||
value |= mask;
|
||||
writeRegister(reg, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCA8418KeyboardBase::pinMode(uint8_t pinnum, uint8_t mode)
|
||||
{
|
||||
if (pinnum > TCA8418_COL9)
|
||||
return false;
|
||||
|
||||
uint8_t idx = pinnum / 8;
|
||||
uint8_t reg = TCA8418_REG_GPIO_DIR_1 + idx;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
// Mode 0 = input 1 = output
|
||||
uint8_t value = readRegister(reg);
|
||||
if (mode == OUTPUT)
|
||||
value |= mask;
|
||||
else
|
||||
value &= ~mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
// Pullup 0 = enabled 1 = disabled
|
||||
reg = TCA8418_REG_GPIO_PULL_1 + idx;
|
||||
value = readRegister(reg);
|
||||
if (mode == INPUT_PULLUP)
|
||||
value &= ~mask;
|
||||
else
|
||||
value |= mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCA8418KeyboardBase::pinIRQMode(uint8_t pinnum, uint8_t mode)
|
||||
{
|
||||
if (pinnum > TCA8418_COL9)
|
||||
return false;
|
||||
if ((mode != RISING) && (mode != FALLING))
|
||||
return false;
|
||||
|
||||
// Mode 0 = falling 1 = rising
|
||||
uint8_t idx = pinnum / 8;
|
||||
uint8_t reg = TCA8418_REG_GPIO_INT_LVL_1 + idx;
|
||||
uint8_t mask = (1 << (pinnum % 8));
|
||||
|
||||
uint8_t value = readRegister(reg);
|
||||
if (mode == RISING)
|
||||
value |= mask;
|
||||
else
|
||||
value &= ~mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
// Enable interrupt
|
||||
reg = TCA8418_REG_GPIO_INT_EN_1 + idx;
|
||||
value = readRegister(reg);
|
||||
value |= mask;
|
||||
writeRegister(reg, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::enableInterrupts()
|
||||
{
|
||||
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||
value |= (_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||
writeRegister(TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418KeyboardBase::disableInterrupts()
|
||||
{
|
||||
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||
value &= ~(_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||
writeRegister(TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418KeyboardBase::enableMatrixOverflow()
|
||||
{
|
||||
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||
value |= _TCA8418_REG_CFG_OVR_FLOW_M;
|
||||
writeRegister(TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418KeyboardBase::disableMatrixOverflow()
|
||||
{
|
||||
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||
value &= ~_TCA8418_REG_CFG_OVR_FLOW_M;
|
||||
writeRegister(TCA8418_REG_CFG, value);
|
||||
};
|
||||
|
||||
void TCA8418KeyboardBase::enableDebounce()
|
||||
{
|
||||
writeRegister(TCA8418_REG_DEBOUNCE_DIS_1, 0x00);
|
||||
writeRegister(TCA8418_REG_DEBOUNCE_DIS_2, 0x00);
|
||||
writeRegister(TCA8418_REG_DEBOUNCE_DIS_3, 0x00);
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::disableDebounce()
|
||||
{
|
||||
writeRegister(TCA8418_REG_DEBOUNCE_DIS_1, 0xFF);
|
||||
writeRegister(TCA8418_REG_DEBOUNCE_DIS_2, 0xFF);
|
||||
writeRegister(TCA8418_REG_DEBOUNCE_DIS_3, 0xFF);
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::setBacklight(bool on) {}
|
||||
|
||||
uint8_t TCA8418KeyboardBase::readRegister(uint8_t reg) const
|
||||
{
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(reg);
|
||||
m_wire->endTransmission();
|
||||
|
||||
m_wire->requestFrom(m_addr, (uint8_t)1);
|
||||
if (m_wire->available() < 1)
|
||||
return 0;
|
||||
|
||||
return m_wire->read();
|
||||
}
|
||||
if (readCallback) {
|
||||
uint8_t data;
|
||||
readCallback(m_addr, reg, &data, 1);
|
||||
return data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TCA8418KeyboardBase::writeRegister(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = reg;
|
||||
data[1] = value;
|
||||
|
||||
if (m_wire) {
|
||||
m_wire->beginTransmission(m_addr);
|
||||
m_wire->write(data, sizeof(uint8_t) * 2);
|
||||
m_wire->endTransmission();
|
||||
}
|
||||
if (writeCallback) {
|
||||
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||
#include "configuration.h"
|
||||
#include <Wire.h>
|
||||
|
||||
/**
|
||||
* @brief TCA8418KeyboardBase is the base class for TCA8418 keyboard handling.
|
||||
* It provides basic functionality for reading key events, managing the keyboard matrix,
|
||||
* and handling key states. It is designed to be extended for specific keyboard implementations.
|
||||
* It supports both I2C communication and function pointers for custom I2C operations.
|
||||
*/
|
||||
class TCA8418KeyboardBase
|
||||
{
|
||||
public:
|
||||
enum TCA8418Key : uint8_t {
|
||||
NONE = 0x00,
|
||||
BSP = 0x08,
|
||||
TAB = 0x09,
|
||||
SELECT = 0x0d,
|
||||
ESC = 0x1b,
|
||||
REBOOT = 0x90,
|
||||
LEFT = 0xb4,
|
||||
UP = 0xb5,
|
||||
DOWN = 0xb6,
|
||||
RIGHT = 0xb7,
|
||||
BT_TOGGLE = 0xAA,
|
||||
GPS_TOGGLE = 0x9E,
|
||||
MUTE_TOGGLE = 0xAC,
|
||||
SEND_PING = 0xAF,
|
||||
BL_TOGGLE = 0xAB
|
||||
};
|
||||
|
||||
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||
|
||||
TCA8418KeyboardBase(uint8_t rows, uint8_t columns);
|
||||
|
||||
virtual void begin(uint8_t addr = TCA8418_KB_ADDR, TwoWire *wire = &Wire);
|
||||
virtual void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = TCA8418_KB_ADDR);
|
||||
|
||||
virtual void reset(void);
|
||||
virtual void trigger(void);
|
||||
|
||||
virtual void setBacklight(bool on);
|
||||
|
||||
// Key events available
|
||||
virtual bool hasEvent(void) const;
|
||||
virtual char dequeueEvent(void);
|
||||
|
||||
protected:
|
||||
enum KeyState { Init, Idle, Held, Busy };
|
||||
|
||||
enum TCA8418Register : uint8_t {
|
||||
TCA8418_REG_RESERVED = 0x00,
|
||||
TCA8418_REG_CFG = 0x01,
|
||||
TCA8418_REG_INT_STAT = 0x02,
|
||||
TCA8418_REG_KEY_LCK_EC = 0x03,
|
||||
TCA8418_REG_KEY_EVENT_A = 0x04,
|
||||
TCA8418_REG_KEY_EVENT_B = 0x05,
|
||||
TCA8418_REG_KEY_EVENT_C = 0x06,
|
||||
TCA8418_REG_KEY_EVENT_D = 0x07,
|
||||
TCA8418_REG_KEY_EVENT_E = 0x08,
|
||||
TCA8418_REG_KEY_EVENT_F = 0x09,
|
||||
TCA8418_REG_KEY_EVENT_G = 0x0A,
|
||||
TCA8418_REG_KEY_EVENT_H = 0x0B,
|
||||
TCA8418_REG_KEY_EVENT_I = 0x0C,
|
||||
TCA8418_REG_KEY_EVENT_J = 0x0D,
|
||||
TCA8418_REG_KP_LCK_TIMER = 0x0E,
|
||||
TCA8418_REG_UNLOCK_1 = 0x0F,
|
||||
TCA8418_REG_UNLOCK_2 = 0x10,
|
||||
TCA8418_REG_GPIO_INT_STAT_1 = 0x11,
|
||||
TCA8418_REG_GPIO_INT_STAT_2 = 0x12,
|
||||
TCA8418_REG_GPIO_INT_STAT_3 = 0x13,
|
||||
TCA8418_REG_GPIO_DAT_STAT_1 = 0x14,
|
||||
TCA8418_REG_GPIO_DAT_STAT_2 = 0x15,
|
||||
TCA8418_REG_GPIO_DAT_STAT_3 = 0x16,
|
||||
TCA8418_REG_GPIO_DAT_OUT_1 = 0x17,
|
||||
TCA8418_REG_GPIO_DAT_OUT_2 = 0x18,
|
||||
TCA8418_REG_GPIO_DAT_OUT_3 = 0x19,
|
||||
TCA8418_REG_GPIO_INT_EN_1 = 0x1A,
|
||||
TCA8418_REG_GPIO_INT_EN_2 = 0x1B,
|
||||
TCA8418_REG_GPIO_INT_EN_3 = 0x1C,
|
||||
TCA8418_REG_KP_GPIO_1 = 0x1D,
|
||||
TCA8418_REG_KP_GPIO_2 = 0x1E,
|
||||
TCA8418_REG_KP_GPIO_3 = 0x1F,
|
||||
TCA8418_REG_GPI_EM_1 = 0x20,
|
||||
TCA8418_REG_GPI_EM_2 = 0x21,
|
||||
TCA8418_REG_GPI_EM_3 = 0x22,
|
||||
TCA8418_REG_GPIO_DIR_1 = 0x23,
|
||||
TCA8418_REG_GPIO_DIR_2 = 0x24,
|
||||
TCA8418_REG_GPIO_DIR_3 = 0x25,
|
||||
TCA8418_REG_GPIO_INT_LVL_1 = 0x26,
|
||||
TCA8418_REG_GPIO_INT_LVL_2 = 0x27,
|
||||
TCA8418_REG_GPIO_INT_LVL_3 = 0x28,
|
||||
TCA8418_REG_DEBOUNCE_DIS_1 = 0x29,
|
||||
TCA8418_REG_DEBOUNCE_DIS_2 = 0x2A,
|
||||
TCA8418_REG_DEBOUNCE_DIS_3 = 0x2B,
|
||||
TCA8418_REG_GPIO_PULL_1 = 0x2C,
|
||||
TCA8418_REG_GPIO_PULL_2 = 0x2D,
|
||||
TCA8418_REG_GPIO_PULL_3 = 0x2E
|
||||
};
|
||||
|
||||
// Pin IDs for matrix rows/columns
|
||||
enum TCA8418PinId : uint8_t {
|
||||
TCA8418_ROW0, // Pin ID for row 0
|
||||
TCA8418_ROW1, // Pin ID for row 1
|
||||
TCA8418_ROW2, // Pin ID for row 2
|
||||
TCA8418_ROW3, // Pin ID for row 3
|
||||
TCA8418_ROW4, // Pin ID for row 4
|
||||
TCA8418_ROW5, // Pin ID for row 5
|
||||
TCA8418_ROW6, // Pin ID for row 6
|
||||
TCA8418_ROW7, // Pin ID for row 7
|
||||
TCA8418_COL0, // Pin ID for column 0
|
||||
TCA8418_COL1, // Pin ID for column 1
|
||||
TCA8418_COL2, // Pin ID for column 2
|
||||
TCA8418_COL3, // Pin ID for column 3
|
||||
TCA8418_COL4, // Pin ID for column 4
|
||||
TCA8418_COL5, // Pin ID for column 5
|
||||
TCA8418_COL6, // Pin ID for column 6
|
||||
TCA8418_COL7, // Pin ID for column 7
|
||||
TCA8418_COL8, // Pin ID for column 8
|
||||
TCA8418_COL9 // Pin ID for column 9
|
||||
};
|
||||
|
||||
virtual void pressed(uint8_t key);
|
||||
virtual void released(void);
|
||||
|
||||
virtual void queueEvent(char);
|
||||
|
||||
virtual ~TCA8418KeyboardBase() {}
|
||||
|
||||
protected:
|
||||
// Set the size of the keypad matrix
|
||||
// All other rows and columns are set as inputs.
|
||||
bool matrix(uint8_t rows, uint8_t columns);
|
||||
|
||||
uint8_t keyCount(void) const;
|
||||
|
||||
// Flush all events in the FIFO buffer + GPIO events.
|
||||
uint8_t flush(void);
|
||||
|
||||
// debounce keys.
|
||||
void enableDebounce();
|
||||
void disableDebounce();
|
||||
|
||||
// enable / disable interrupts for matrix and GPI pins
|
||||
void enableInterrupts();
|
||||
void disableInterrupts();
|
||||
|
||||
// ignore key events when FIFO buffer is full or not.
|
||||
void enableMatrixOverflow();
|
||||
void disableMatrixOverflow();
|
||||
|
||||
uint8_t digitalRead(uint8_t pinnum) const;
|
||||
bool digitalWrite(uint8_t pinnum, uint8_t level);
|
||||
bool pinMode(uint8_t pinnum, uint8_t mode);
|
||||
bool pinIRQMode(uint8_t pinnum, uint8_t mode); // MODE FALLING or RISING
|
||||
uint8_t readRegister(uint8_t reg) const;
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
|
||||
protected:
|
||||
uint8_t rows;
|
||||
uint8_t columns;
|
||||
KeyState state;
|
||||
String queue;
|
||||
|
||||
private:
|
||||
TwoWire *m_wire;
|
||||
uint8_t m_addr;
|
||||
i2c_com_fptr_t readCallback;
|
||||
i2c_com_fptr_t writeCallback;
|
||||
};
|
||||
@@ -0,0 +1,196 @@
|
||||
#if defined(T_DECK_PRO)
|
||||
|
||||
#include "TDeckProKeyboard.h"
|
||||
|
||||
#define _TCA8418_COLS 10
|
||||
#define _TCA8418_ROWS 4
|
||||
#define _TCA8418_NUM_KEYS 35
|
||||
|
||||
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
|
||||
|
||||
using Key = TCA8418KeyboardBase::TCA8418Key;
|
||||
|
||||
constexpr uint8_t modifierRightShiftKey = 31 - 1; // keynum -1
|
||||
constexpr uint8_t modifierRightShift = 0b0001;
|
||||
constexpr uint8_t modifierLeftShiftKey = 35 - 1;
|
||||
constexpr uint8_t modifierLeftShift = 0b0001;
|
||||
constexpr uint8_t modifierSymKey = 32 - 1;
|
||||
constexpr uint8_t modifierSym = 0b0010;
|
||||
constexpr uint8_t modifierAltKey = 30 - 1;
|
||||
constexpr uint8_t modifierAlt = 0b0100;
|
||||
|
||||
// Num chars per key, Modulus for rotating through characters
|
||||
static uint8_t TDeckProTapMod[_TCA8418_NUM_KEYS] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
|
||||
|
||||
static unsigned char TDeckProTapMap[_TCA8418_NUM_KEYS][5] = {
|
||||
{'p', 'P', '@', 0x00, Key::SEND_PING},
|
||||
{'o', 'O', '+'},
|
||||
{'i', 'I', '-'},
|
||||
{'u', 'U', '_'},
|
||||
{'y', 'Y', ')'},
|
||||
{'t', 'T', '(', 0x00, Key::TAB},
|
||||
{'r', 'R', '3'},
|
||||
{'e', 'E', '2', 0x00, Key::UP},
|
||||
{'w', 'W', '1'},
|
||||
{'q', 'Q', '#', 0x00, Key::ESC}, // p, o, i, u, y, t, r, e, w, q
|
||||
{Key::BSP, 0x00, 0x00},
|
||||
{'l', 'L', '"'},
|
||||
{'k', 'K', '\''},
|
||||
{'j', 'J', ';'},
|
||||
{'h', 'H', ':'},
|
||||
{'g', 'G', '/', 0x00, Key::GPS_TOGGLE},
|
||||
{'f', 'F', '6', 0x00, Key::RIGHT},
|
||||
{'d', 'D', '5'},
|
||||
{'s', 'S', '4', 0x00, Key::LEFT},
|
||||
{'a', 'A', '*'}, // bsp, l, k, j, h, g, f, d, s, a
|
||||
{0x0d, 0x00, 0x00},
|
||||
{'$', 0x00, 0x00},
|
||||
{'m', 'M', '.', 0x00, Key::MUTE_TOGGLE},
|
||||
{'n', 'N', ','},
|
||||
{'b', 'B', '!', 0x00, Key::BL_TOGGLE},
|
||||
{'v', 'V', '?'},
|
||||
{'c', 'C', '9'},
|
||||
{'x', 'X', '8', 0x00, Key::DOWN},
|
||||
{'z', 'Z', '7'},
|
||||
{0x00, 0x00, 0x00}, // Ent, $, m, n, b, v, c, x, z, alt
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x20, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00} // R_Shift, sym, space, mic, L_Shift
|
||||
};
|
||||
|
||||
TDeckProKeyboard::TDeckProKeyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
|
||||
last_tap(0L), char_idx(0), tap_interval(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TDeckProKeyboard::reset()
|
||||
{
|
||||
TCA8418KeyboardBase::reset();
|
||||
pinMode(KB_BL_PIN, OUTPUT);
|
||||
setBacklight(false);
|
||||
}
|
||||
|
||||
// handle multi-key presses (shift and alt)
|
||||
void TDeckProKeyboard::trigger()
|
||||
{
|
||||
uint8_t count = keyCount();
|
||||
if (count == 0)
|
||||
return;
|
||||
for (uint8_t i = 0; i < count; ++i) {
|
||||
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A + i);
|
||||
uint8_t key = k & 0x7F;
|
||||
if (k & 0x80) {
|
||||
pressed(key);
|
||||
} else {
|
||||
released();
|
||||
state = Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TDeckProKeyboard::pressed(uint8_t key)
|
||||
{
|
||||
if (state == Init || state == Busy) {
|
||||
return;
|
||||
}
|
||||
if (modifierFlag && (millis() - last_modifier_time > _TCA8418_MULTI_TAP_THRESHOLD)) {
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
uint8_t next_key = 0;
|
||||
int row = (key - 1) / 10;
|
||||
int col = (key - 1) % 10;
|
||||
|
||||
if (row >= _TCA8418_ROWS || col >= _TCA8418_COLS) {
|
||||
return; // Invalid key
|
||||
}
|
||||
|
||||
next_key = row * _TCA8418_COLS + col;
|
||||
state = Held;
|
||||
|
||||
uint32_t now = millis();
|
||||
tap_interval = now - last_tap;
|
||||
|
||||
updateModifierFlag(next_key);
|
||||
if (isModifierKey(next_key)) {
|
||||
last_modifier_time = now;
|
||||
}
|
||||
|
||||
if (tap_interval < 0) {
|
||||
last_tap = 0;
|
||||
state = Busy;
|
||||
return;
|
||||
}
|
||||
|
||||
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
|
||||
char_idx = 0;
|
||||
} else {
|
||||
char_idx += 1;
|
||||
}
|
||||
|
||||
last_key = next_key;
|
||||
last_tap = now;
|
||||
}
|
||||
|
||||
void TDeckProKeyboard::released()
|
||||
{
|
||||
if (state != Held) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = -1;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t now = millis();
|
||||
last_tap = now;
|
||||
|
||||
if (TDeckProTapMap[last_key][modifierFlag % TDeckProTapMod[last_key]] == Key::BL_TOGGLE) {
|
||||
toggleBacklight();
|
||||
return;
|
||||
}
|
||||
|
||||
queueEvent(TDeckProTapMap[last_key][modifierFlag % TDeckProTapMod[last_key]]);
|
||||
if (isModifierKey(last_key) == false)
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
void TDeckProKeyboard::setBacklight(bool on)
|
||||
{
|
||||
if (on) {
|
||||
digitalWrite(KB_BL_PIN, HIGH);
|
||||
} else {
|
||||
digitalWrite(KB_BL_PIN, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void TDeckProKeyboard::toggleBacklight(void)
|
||||
{
|
||||
digitalWrite(KB_BL_PIN, !digitalRead(KB_BL_PIN));
|
||||
}
|
||||
|
||||
void TDeckProKeyboard::updateModifierFlag(uint8_t key)
|
||||
{
|
||||
if (key == modifierRightShiftKey) {
|
||||
modifierFlag ^= modifierRightShift;
|
||||
} else if (key == modifierLeftShiftKey) {
|
||||
modifierFlag ^= modifierLeftShift;
|
||||
} else if (key == modifierSymKey) {
|
||||
modifierFlag ^= modifierSym;
|
||||
} else if (key == modifierAltKey) {
|
||||
modifierFlag ^= modifierAlt;
|
||||
}
|
||||
}
|
||||
|
||||
bool TDeckProKeyboard::isModifierKey(uint8_t key)
|
||||
{
|
||||
return (key == modifierRightShiftKey || key == modifierLeftShiftKey || key == modifierAltKey || key == modifierSymKey);
|
||||
}
|
||||
|
||||
#endif // T_DECK_PRO
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "TCA8418KeyboardBase.h"
|
||||
|
||||
class TDeckProKeyboard : public TCA8418KeyboardBase
|
||||
{
|
||||
public:
|
||||
TDeckProKeyboard();
|
||||
void reset(void) override;
|
||||
void trigger(void) override;
|
||||
void setBacklight(bool on) override;
|
||||
|
||||
protected:
|
||||
void pressed(uint8_t key) override;
|
||||
void released(void) override;
|
||||
|
||||
void updateModifierFlag(uint8_t key);
|
||||
bool isModifierKey(uint8_t key);
|
||||
void toggleBacklight(void);
|
||||
|
||||
private:
|
||||
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
|
||||
uint32_t last_modifier_time; // Timestamp of the last modifier key press
|
||||
int8_t last_key;
|
||||
int8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "TCA8418KeyboardBase.h"
|
||||
|
||||
class TLoraPagerKeyboard : public TCA8418KeyboardBase
|
||||
{
|
||||
public:
|
||||
TLoraPagerKeyboard();
|
||||
void setBacklight(bool on) override{};
|
||||
|
||||
protected:
|
||||
void pressed(uint8_t key) override{};
|
||||
void released(void) override{};
|
||||
};
|
||||
@@ -4,8 +4,13 @@
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
#ifndef TB_DIRECTION
|
||||
#if ARCH_PORTDUINO
|
||||
#include "PortduinoGlue.h"
|
||||
#define TB_DIRECTION (PinStatus) settingsMap[tbDirection]
|
||||
#else
|
||||
#define TB_DIRECTION RISING
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class TrackballInterruptBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
|
||||
@@ -67,4 +67,5 @@ void CardKbI2cImpl::init()
|
||||
}
|
||||
#endif
|
||||
inputBroker->registerSource(this);
|
||||
kb_found = true;
|
||||
}
|
||||
+56
-15
@@ -3,10 +3,26 @@
|
||||
#include "detect/ScanI2C.h"
|
||||
#include "detect/ScanI2CTwoWire.h"
|
||||
|
||||
#if defined(T_DECK_PRO)
|
||||
#include "TDeckProKeyboard.h"
|
||||
#elif defined(T_LORA_PAGER)
|
||||
#include "TLoraPagerKeyboard.h"
|
||||
#else
|
||||
#include "TCA8418Keyboard.h"
|
||||
#endif
|
||||
|
||||
extern ScanI2C::DeviceAddress cardkb_found;
|
||||
extern uint8_t kb_model;
|
||||
|
||||
KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
|
||||
KbI2cBase::KbI2cBase(const char *name)
|
||||
: concurrency::OSThread(name),
|
||||
#if defined(T_DECK_PRO)
|
||||
TCAKeyboard(*(new TDeckProKeyboard()))
|
||||
#elif defined(T_LORA_PAGER)
|
||||
TCAKeyboard(*(new TLoraPagerKeyboard()))
|
||||
#else
|
||||
TCAKeyboard(*(new TCA8418Keyboard()))
|
||||
#endif
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
@@ -43,8 +59,8 @@ int32_t KbI2cBase::runOnce()
|
||||
if (cardkb_found.address == MPR121_KB_ADDR) {
|
||||
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
|
||||
}
|
||||
if (cardkb_found.address == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
||||
TCAKeyboard.begin(XPOWERS_AXP192_AXP2101_ADDRESS, &Wire1);
|
||||
if (cardkb_found.address == TCA8418_KB_ADDR) {
|
||||
TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -58,8 +74,8 @@ int32_t KbI2cBase::runOnce()
|
||||
if (cardkb_found.address == MPR121_KB_ADDR) {
|
||||
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
|
||||
}
|
||||
if (cardkb_found.address == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
||||
TCAKeyboard.begin(XPOWERS_AXP192_AXP2101_ADDRESS, &Wire);
|
||||
if (cardkb_found.address == TCA8418_KB_ADDR) {
|
||||
TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire);
|
||||
}
|
||||
break;
|
||||
case ScanI2C::NO_I2C:
|
||||
@@ -241,41 +257,65 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = 0x00;
|
||||
e.source = this->_originName;
|
||||
switch (nextEvent) {
|
||||
case _TCA8418_NONE:
|
||||
case TCA8418KeyboardBase::NONE:
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case _TCA8418_REBOOT:
|
||||
case TCA8418KeyboardBase::REBOOT:
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_REBOOT;
|
||||
break;
|
||||
case _TCA8418_LEFT:
|
||||
case TCA8418KeyboardBase::LEFT:
|
||||
e.inputEvent = INPUT_BROKER_LEFT;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case _TCA8418_UP:
|
||||
case TCA8418KeyboardBase::UP:
|
||||
e.inputEvent = INPUT_BROKER_UP;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case _TCA8418_DOWN:
|
||||
case TCA8418KeyboardBase::DOWN:
|
||||
e.inputEvent = INPUT_BROKER_DOWN;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case _TCA8418_RIGHT:
|
||||
case TCA8418KeyboardBase::RIGHT:
|
||||
e.inputEvent = INPUT_BROKER_RIGHT;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case _TCA8418_BSP:
|
||||
case TCA8418KeyboardBase::BSP:
|
||||
e.inputEvent = INPUT_BROKER_BACK;
|
||||
e.kbchar = 0x08;
|
||||
break;
|
||||
case _TCA8418_SELECT:
|
||||
case TCA8418KeyboardBase::SELECT:
|
||||
e.inputEvent = INPUT_BROKER_SELECT;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case _TCA8418_ESC:
|
||||
case TCA8418KeyboardBase::ESC:
|
||||
e.inputEvent = INPUT_BROKER_CANCEL;
|
||||
e.kbchar = 0;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case TCA8418KeyboardBase::GPS_TOGGLE:
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_GPS_TOGGLE;
|
||||
break;
|
||||
case TCA8418KeyboardBase::SEND_PING:
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_SEND_PING;
|
||||
break;
|
||||
case TCA8418KeyboardBase::MUTE_TOGGLE:
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_MUTE_TOGGLE;
|
||||
break;
|
||||
case TCA8418KeyboardBase::BT_TOGGLE:
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_BLUETOOTH_TOGGLE;
|
||||
break;
|
||||
case TCA8418KeyboardBase::BL_TOGGLE:
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_BLUETOOTH_TOGGLE;
|
||||
break;
|
||||
case TCA8418KeyboardBase::TAB:
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_TAB;
|
||||
break;
|
||||
default:
|
||||
if (nextEvent > 127) {
|
||||
@@ -291,6 +331,7 @@ int32_t KbI2cBase::runOnce()
|
||||
LOG_DEBUG("TCA8418 Notifying: %i Char: %c", e.inputEvent, e.kbchar);
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
TCAKeyboard.trigger();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
#include "BBQ10Keyboard.h"
|
||||
#include "InputBroker.h"
|
||||
#include "MPR121Keyboard.h"
|
||||
#include "TCA8418Keyboard.h"
|
||||
#include "Wire.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
class TCA8418KeyboardBase;
|
||||
|
||||
class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
@@ -22,6 +23,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
|
||||
|
||||
BBQ10Keyboard Q10keyboard;
|
||||
MPR121Keyboard MPRkeyboard;
|
||||
TCA8418Keyboard TCAKeyboard;
|
||||
TCA8418KeyboardBase &TCAKeyboard;
|
||||
bool is_sym = false;
|
||||
};
|
||||
+20
-22
@@ -33,7 +33,6 @@
|
||||
#include "mesh/generated/meshtastic/config.pb.h"
|
||||
#include "meshUtils.h"
|
||||
#include "modules/Modules.h"
|
||||
#include "shutdown.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include <memory>
|
||||
@@ -286,7 +285,7 @@ void lateInitVariant() {}
|
||||
*/
|
||||
void printInfo()
|
||||
{
|
||||
LOG_INFO("S:B:%d,%s", HW_VENDOR, optstr(APP_VERSION));
|
||||
LOG_INFO("S:B:%d,%s,%s,%s", HW_VENDOR, optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO));
|
||||
}
|
||||
#ifndef PIO_UNIT_TESTING
|
||||
void setup()
|
||||
@@ -335,6 +334,15 @@ void setup()
|
||||
pinMode(TFT_CS, OUTPUT);
|
||||
digitalWrite(TFT_CS, HIGH);
|
||||
delay(100);
|
||||
#elif defined(T_DECK_PRO)
|
||||
pinMode(LORA_EN, OUTPUT);
|
||||
digitalWrite(LORA_EN, HIGH);
|
||||
pinMode(LORA_CS, OUTPUT);
|
||||
digitalWrite(LORA_CS, HIGH);
|
||||
pinMode(SDCARD_CS, OUTPUT);
|
||||
digitalWrite(SDCARD_CS, HIGH);
|
||||
pinMode(PIN_EINK_CS, OUTPUT);
|
||||
digitalWrite(PIN_EINK_CS, HIGH);
|
||||
#endif
|
||||
|
||||
concurrency::hasBeenSetup = true;
|
||||
@@ -515,25 +523,11 @@ void setup()
|
||||
LOG_INFO("Scan for i2c devices");
|
||||
#endif
|
||||
|
||||
#if defined(I2C_SDA1) && defined(ARCH_RP2040)
|
||||
Wire1.setSDA(I2C_SDA1);
|
||||
Wire1.setSCL(I2C_SCL1);
|
||||
Wire1.begin();
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
|
||||
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
|
||||
Wire1.begin(I2C_SDA1, I2C_SCL1);
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
|
||||
#elif defined(NRF52840_XXAA) && (WIRE_INTERFACES_COUNT == 2)
|
||||
#if defined(I2C_SDA1) || (defined(NRF52840_XXAA) && (WIRE_INTERFACES_COUNT == 2))
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
|
||||
#endif
|
||||
|
||||
#if defined(I2C_SDA) && defined(ARCH_RP2040)
|
||||
Wire.setSDA(I2C_SDA);
|
||||
Wire.setSCL(I2C_SCL);
|
||||
Wire.begin();
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
||||
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
#if defined(I2C_SDA)
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if (settingsStrings[i2cdev] != "") {
|
||||
@@ -1056,8 +1050,9 @@ void setup()
|
||||
mainDelay.interruptFromISR(&higherWake);
|
||||
};
|
||||
userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS;
|
||||
userConfigNoScreen.longPress = INPUT_BROKER_SHUTDOWN;
|
||||
userConfigNoScreen.longPressTime = 5000;
|
||||
userConfigNoScreen.longPress = INPUT_BROKER_NONE;
|
||||
userConfigNoScreen.longPressTime = 500;
|
||||
userConfigNoScreen.longLongPress = INPUT_BROKER_SHUTDOWN;
|
||||
userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING;
|
||||
userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE;
|
||||
UserButtonThread->initButton(userConfigNoScreen);
|
||||
@@ -1363,7 +1358,7 @@ void setup()
|
||||
if (!rIf->reconfigure()) {
|
||||
LOG_WARN("Reconfigure failed, rebooting");
|
||||
if (screen) {
|
||||
screen->showOverlayBanner("Rebooting...");
|
||||
screen->showSimpleBanner("Rebooting...");
|
||||
}
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
@@ -1436,6 +1431,9 @@ void setup()
|
||||
LOG_DEBUG("Free heap : %7d bytes", ESP.getFreeHeap());
|
||||
LOG_DEBUG("Free PSRAM : %7d bytes", ESP.getFreePsram());
|
||||
#endif
|
||||
|
||||
// We manually run this to update the NodeStatus
|
||||
nodeDB->notifyObservers(true);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1531,7 +1529,7 @@ void loop()
|
||||
#ifdef ARCH_NRF52
|
||||
nrf52Loop();
|
||||
#endif
|
||||
powerCommandsCheck();
|
||||
power->powerCommandsCheck();
|
||||
|
||||
#ifdef DEBUG_STACK
|
||||
static uint32_t lastPrint = 0;
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include "memGet.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
MemGet memGet;
|
||||
|
||||
/**
|
||||
@@ -24,6 +28,9 @@ uint32_t MemGet::getFreeHeap()
|
||||
return dbgHeapFree();
|
||||
#elif defined(ARCH_RP2040)
|
||||
return rp2040.getFreeHeap();
|
||||
#elif defined(ARCH_STM32WL)
|
||||
struct mallinfo m = mallinfo();
|
||||
return m.fordblks; // Total free space (bytes)
|
||||
#else
|
||||
// this platform does not have heap management function implemented
|
||||
return UINT32_MAX;
|
||||
@@ -42,6 +49,9 @@ uint32_t MemGet::getHeapSize()
|
||||
return dbgHeapTotal();
|
||||
#elif defined(ARCH_RP2040)
|
||||
return rp2040.getTotalHeap();
|
||||
#elif defined(ARCH_STM32WL)
|
||||
struct mallinfo m = mallinfo();
|
||||
return m.arena; // Non-mmapped space allocated (bytes)
|
||||
#else
|
||||
// this platform does not have heap management function implemented
|
||||
return UINT32_MAX;
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
#define min_node_info_broadcast_secs 60 * 60 // No regular broadcasts of more than once an hour
|
||||
#define min_neighbor_info_broadcast_secs 4 * 60 * 60
|
||||
#define default_map_publish_interval_secs 60 * 60
|
||||
#ifdef USERPREFS_RINGTONE_NAG_SECS
|
||||
#define default_ringtone_nag_secs USERPREFS_RINGTONE_NAG_SECS
|
||||
#else
|
||||
#define default_ringtone_nag_secs 60
|
||||
#endif
|
||||
|
||||
#define default_mqtt_address "mqtt.meshtastic.org"
|
||||
#define default_mqtt_username "meshdev"
|
||||
|
||||
@@ -121,7 +121,7 @@ meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool t
|
||||
bool MeshPacketQueue::find(const NodeNum from, const PacketId id)
|
||||
{
|
||||
for (auto it = queue.begin(); it != queue.end(); it++) {
|
||||
const auto p = (*it);
|
||||
const auto *p = *it;
|
||||
if (getFrom(p) == from && p->id == id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "meshUtils.h"
|
||||
#include "modules/NodeInfoModule.h"
|
||||
#include "modules/PositionModule.h"
|
||||
#include "modules/RoutingModule.h"
|
||||
#include "power.h"
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
@@ -333,6 +334,21 @@ void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage
|
||||
fromNum++;
|
||||
}
|
||||
|
||||
void MeshService::sendRoutingErrorResponse(meshtastic_Routing_Error error, const meshtastic_MeshPacket *mp)
|
||||
{
|
||||
if (!mp) {
|
||||
LOG_WARN("Cannot send routing error response: null packet");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the routing module to send the error response
|
||||
if (routingModule) {
|
||||
routingModule->sendAckNak(error, mp->from, mp->id, mp->channel);
|
||||
} else {
|
||||
LOG_ERROR("Cannot send routing error response: no routing module");
|
||||
}
|
||||
}
|
||||
|
||||
void MeshService::sendClientNotification(meshtastic_ClientNotification *n)
|
||||
{
|
||||
LOG_DEBUG("Send client notification to phone");
|
||||
|
||||
@@ -146,7 +146,10 @@ class MeshService
|
||||
virtual void sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m);
|
||||
|
||||
/// Send a ClientNotification to the phone
|
||||
void sendClientNotification(meshtastic_ClientNotification *cn);
|
||||
virtual void sendClientNotification(meshtastic_ClientNotification *cn);
|
||||
|
||||
/// Send an error response to the phone
|
||||
void sendRoutingErrorResponse(meshtastic_Routing_Error error, const meshtastic_MeshPacket *mp);
|
||||
|
||||
bool isToPhoneQueueEmpty();
|
||||
|
||||
|
||||
+94
-33
@@ -344,6 +344,22 @@ NodeDB::NodeDB()
|
||||
config.device.node_info_broadcast_secs = MAX_INTERVAL;
|
||||
if (config.position.position_broadcast_secs > MAX_INTERVAL)
|
||||
config.position.position_broadcast_secs = MAX_INTERVAL;
|
||||
if (config.position.gps_update_interval > MAX_INTERVAL)
|
||||
config.position.gps_update_interval = MAX_INTERVAL;
|
||||
if (config.position.gps_attempt_time > MAX_INTERVAL)
|
||||
config.position.gps_attempt_time = MAX_INTERVAL;
|
||||
if (config.position.position_flags > MAX_INTERVAL)
|
||||
config.position.position_flags = MAX_INTERVAL;
|
||||
if (config.position.rx_gpio > MAX_INTERVAL)
|
||||
config.position.rx_gpio = MAX_INTERVAL;
|
||||
if (config.position.tx_gpio > MAX_INTERVAL)
|
||||
config.position.tx_gpio = MAX_INTERVAL;
|
||||
if (config.position.broadcast_smart_minimum_distance > MAX_INTERVAL)
|
||||
config.position.broadcast_smart_minimum_distance = MAX_INTERVAL;
|
||||
if (config.position.broadcast_smart_minimum_interval_secs > MAX_INTERVAL)
|
||||
config.position.broadcast_smart_minimum_interval_secs = MAX_INTERVAL;
|
||||
if (config.position.gps_en_gpio > MAX_INTERVAL)
|
||||
config.position.gps_en_gpio = MAX_INTERVAL;
|
||||
if (moduleConfig.neighbor_info.update_interval > MAX_INTERVAL)
|
||||
moduleConfig.neighbor_info.update_interval = MAX_INTERVAL;
|
||||
if (moduleConfig.telemetry.device_update_interval > MAX_INTERVAL)
|
||||
@@ -369,6 +385,14 @@ NodeDB::NodeDB()
|
||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
|
||||
}
|
||||
|
||||
#if !HAS_TFT
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
// On a device without MUI, this display mode makes no sense, and will break logic.
|
||||
config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
|
||||
config.bluetooth.enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
if (nodeDatabaseCRC != crc32Buffer(&nodeDatabase, sizeof(nodeDatabase)))
|
||||
@@ -382,6 +406,9 @@ NodeDB::NodeDB()
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
||||
config.position.gps_enabled = 0;
|
||||
}
|
||||
#ifdef USERPREFS_FIRMWARE_EDITION
|
||||
myNodeInfo.firmware_edition = USERPREFS_FIRMWARE_EDITION;
|
||||
#endif
|
||||
#ifdef USERPREFS_FIXED_GPS
|
||||
if (myNodeInfo.reboot_count == 1) { // Check if First boot ever or after Factory Reset.
|
||||
meshtastic_Position fixedGPS = meshtastic_Position_init_default;
|
||||
@@ -407,6 +434,7 @@ NodeDB::NodeDB()
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
sortMeshDB();
|
||||
saveToDisk(saveWhat);
|
||||
}
|
||||
|
||||
@@ -603,11 +631,6 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
||||
#ifdef PIN_GPS_EN
|
||||
config.position.gps_en_gpio = PIN_GPS_EN;
|
||||
#endif
|
||||
#ifdef GPS_POWER_TOGGLE
|
||||
config.device.disable_triple_click = false;
|
||||
#else
|
||||
config.device.disable_triple_click = true;
|
||||
#endif
|
||||
#if defined(USERPREFS_CONFIG_GPS_MODE)
|
||||
config.position.gps_mode = USERPREFS_CONFIG_GPS_MODE;
|
||||
#elif !HAS_GPS || GPS_DEFAULT_NOT_PRESENT
|
||||
@@ -710,7 +733,6 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
||||
config.display.screen_on_secs = 30;
|
||||
config.display.wake_on_tap_or_motion = true;
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
|
||||
if (WiFiOTA::isUpdated()) {
|
||||
WiFiOTA::recoverConfig(&config.network);
|
||||
@@ -769,16 +791,23 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.output_buzzer = PIN_BUZZER;
|
||||
moduleConfig.external_notification.use_pwm = true;
|
||||
moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
||||
#endif
|
||||
#if defined(RAK4630) || defined(RAK11310)
|
||||
#if defined(PIN_VIBRATION)
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.output_vibra = PIN_VIBRATION;
|
||||
moduleConfig.external_notification.alert_message_vibra = true;
|
||||
moduleConfig.external_notification.output_ms = 500;
|
||||
moduleConfig.external_notification.nag_timeout = 2;
|
||||
#endif
|
||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312)
|
||||
// Default to RAK led pin 2 (blue)
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.output = PIN_LED2;
|
||||
moduleConfig.external_notification.active = true;
|
||||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 1000;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_I2S
|
||||
@@ -787,10 +816,10 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.use_i2s_as_buzzer = true;
|
||||
moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
#if HAS_TFT
|
||||
if (moduleConfig.external_notification.nag_timeout == 60)
|
||||
if (moduleConfig.external_notification.nag_timeout == default_ringtone_nag_secs)
|
||||
moduleConfig.external_notification.nag_timeout = 0;
|
||||
#else
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef NANO_G2_ULTRA
|
||||
@@ -1000,7 +1029,10 @@ void NodeDB::cleanupMeshDB()
|
||||
meshNodes->at(i).user.public_key.size = 0;
|
||||
}
|
||||
}
|
||||
meshNodes->at(newPos++) = meshNodes->at(i);
|
||||
if (newPos != i)
|
||||
meshNodes->at(newPos++) = meshNodes->at(i);
|
||||
else
|
||||
newPos++;
|
||||
} else {
|
||||
removed++;
|
||||
}
|
||||
@@ -1087,8 +1119,8 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t
|
||||
if (f) {
|
||||
LOG_INFO("Load %s", filename);
|
||||
pb_istream_t stream = {&readcb, &f, protoSize};
|
||||
|
||||
memset(dest_struct, 0, objSize);
|
||||
if (fields != &meshtastic_NodeDatabase_msg) // contains a vector object
|
||||
memset(dest_struct, 0, objSize);
|
||||
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||
LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream));
|
||||
state = LoadFileResult::DECODE_FAILED;
|
||||
@@ -1156,7 +1188,7 @@ void NodeDB::loadFromDisk()
|
||||
LOG_WARN("Node count %d exceeds MAX_NUM_NODES %d, truncating", numMeshNodes, MAX_NUM_NODES);
|
||||
numMeshNodes = MAX_NUM_NODES;
|
||||
}
|
||||
meshNodes->resize(MAX_NUM_NODES + 1); // The rp2040, rp2035, and maybe other targets, have a problem doing a sort() when full
|
||||
meshNodes->resize(MAX_NUM_NODES);
|
||||
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
state = loadProto(deviceStateFileName, meshtastic_DeviceState_size, sizeof(meshtastic_DeviceState),
|
||||
@@ -1297,6 +1329,13 @@ void NodeDB::loadFromDisk()
|
||||
|
||||
saveToDisk(SEGMENT_MODULECONFIG);
|
||||
}
|
||||
#if ARCH_PORTDUINO
|
||||
// set any config overrides
|
||||
if (settingsMap[has_configDisplayMode]) {
|
||||
config.display.displaymode = (_meshtastic_Config_DisplayConfig_DisplayMode)settingsMap[configDisplayMode];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Save a protobuf from a file, return true for success */
|
||||
@@ -1690,26 +1729,48 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeDB::set_favorite(bool is_favorite, uint32_t nodeId)
|
||||
{
|
||||
meshtastic_NodeInfoLite *lite = getMeshNode(nodeId);
|
||||
if (lite && lite->is_favorite != is_favorite) {
|
||||
lite->is_favorite = is_favorite;
|
||||
sortMeshDB();
|
||||
saveNodeDatabaseToDisk();
|
||||
}
|
||||
}
|
||||
|
||||
void NodeDB::pause_sort(bool paused)
|
||||
{
|
||||
sortingIsPaused = paused;
|
||||
}
|
||||
|
||||
void NodeDB::sortMeshDB()
|
||||
{
|
||||
if (!Throttle::isWithinTimespanMs(lastSort, 1000 * 5)) {
|
||||
if (!sortingIsPaused && (lastSort == 0 || !Throttle::isWithinTimespanMs(lastSort, 1000 * 5))) {
|
||||
lastSort = millis();
|
||||
std::sort(meshNodes->begin(), meshNodes->begin() + numMeshNodes,
|
||||
[](const meshtastic_NodeInfoLite &a, const meshtastic_NodeInfoLite &b) {
|
||||
if (a.num == myNodeInfo.my_node_num && b.num == myNodeInfo.my_node_num) // in theory impossible
|
||||
return false;
|
||||
if (a.num == myNodeInfo.my_node_num) {
|
||||
return true;
|
||||
}
|
||||
if (b.num == myNodeInfo.my_node_num) {
|
||||
return false;
|
||||
}
|
||||
bool aFav = a.is_favorite;
|
||||
bool bFav = b.is_favorite;
|
||||
if (aFav != bFav)
|
||||
return aFav;
|
||||
return a.last_heard > b.last_heard;
|
||||
});
|
||||
bool changed = true;
|
||||
while (changed) { // dumb reverse bubble sort, but probably not bad for what we're doing
|
||||
changed = false;
|
||||
for (int i = numMeshNodes - 1; i > 0; i--) { // lowest case this should examine is i == 1
|
||||
if (meshNodes->at(i - 1).num == getNodeNum()) {
|
||||
// noop
|
||||
} else if (meshNodes->at(i).num ==
|
||||
getNodeNum()) { // in the oddball case our own node num is not at location 0, put it there
|
||||
// TODO: Look for at(i-1) also matching own node num, and throw the DB in the trash
|
||||
std::swap(meshNodes->at(i), meshNodes->at(i - 1));
|
||||
changed = true;
|
||||
} else if (meshNodes->at(i).is_favorite && !meshNodes->at(i - 1).is_favorite) {
|
||||
std::swap(meshNodes->at(i), meshNodes->at(i - 1));
|
||||
changed = true;
|
||||
} else if (!meshNodes->at(i).is_favorite && meshNodes->at(i - 1).is_favorite) {
|
||||
// noop
|
||||
} else if (meshNodes->at(i).last_heard > meshNodes->at(i - 1).last_heard) {
|
||||
std::swap(meshNodes->at(i), meshNodes->at(i - 1));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_INFO("Sort took %u milliseconds", millis() - lastSort);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1811,7 +1872,7 @@ UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum)
|
||||
return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed;
|
||||
}
|
||||
|
||||
bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t keyToTest)
|
||||
bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest)
|
||||
{
|
||||
if (keyToTest.size == 32) {
|
||||
uint8_t keyHash[32] = {0};
|
||||
|
||||
+26
-11
@@ -191,6 +191,16 @@ class NodeDB
|
||||
*/
|
||||
bool updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex = 0);
|
||||
|
||||
/*
|
||||
* Sets a node either favorite or unfavorite
|
||||
*/
|
||||
void set_favorite(bool is_favorite, uint32_t nodeId);
|
||||
|
||||
/**
|
||||
* Other functions like the node picker can request a pause in the node sorting
|
||||
*/
|
||||
void pause_sort(bool paused);
|
||||
|
||||
/// @return our node number
|
||||
NodeNum getNodeNum() { return myNodeInfo.my_node_num; }
|
||||
|
||||
@@ -208,9 +218,6 @@ class NodeDB
|
||||
their denial?)
|
||||
*/
|
||||
|
||||
/// pick a provisional nodenum we hope no one is using
|
||||
void pickNewNodeNum();
|
||||
|
||||
// get channel channel index we heard a nodeNum on, defaults to 0 if not found
|
||||
uint8_t getMeshNodeChannel(NodeNum n);
|
||||
|
||||
@@ -272,12 +279,20 @@ class NodeDB
|
||||
|
||||
bool hasValidPosition(const meshtastic_NodeInfoLite *n);
|
||||
|
||||
bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t keyToTest);
|
||||
bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest);
|
||||
|
||||
bool backupPreferences(meshtastic_AdminMessage_BackupLocation location);
|
||||
bool restorePreferences(meshtastic_AdminMessage_BackupLocation location,
|
||||
int restoreWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
|
||||
|
||||
/// Notify observers of changes to the DB
|
||||
void notifyObservers(bool forceUpdate = false)
|
||||
{
|
||||
// Notify observers of the current node state
|
||||
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineMeshNodes(), getNumMeshNodes(), forceUpdate);
|
||||
newStatus.notifyObservers(&status);
|
||||
}
|
||||
|
||||
private:
|
||||
bool duplicateWarned = false;
|
||||
uint32_t lastNodeDbSave = 0; // when we last saved our db to flash
|
||||
@@ -286,13 +301,13 @@ class NodeDB
|
||||
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
||||
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
||||
|
||||
/// Notify observers of changes to the DB
|
||||
void notifyObservers(bool forceUpdate = false)
|
||||
{
|
||||
// Notify observers of the current node state
|
||||
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineMeshNodes(), getNumMeshNodes(), forceUpdate);
|
||||
newStatus.notifyObservers(&status);
|
||||
}
|
||||
/*
|
||||
* Internal boolean to track sorting paused
|
||||
*/
|
||||
bool sortingIsPaused = false;
|
||||
|
||||
/// pick a provisional nodenum we hope no one is using
|
||||
void pickNewNodeNum();
|
||||
|
||||
/// read our db from flash
|
||||
void loadFromDisk();
|
||||
|
||||
@@ -181,7 +181,7 @@ PacketHistory::PacketRecord *PacketHistory::find(NodeNum sender, PacketId id)
|
||||
}
|
||||
|
||||
/** Insert/Replace oldest PacketRecord in recentPackets. */
|
||||
void PacketHistory::insert(PacketRecord &r)
|
||||
void PacketHistory::insert(const PacketRecord &r)
|
||||
{
|
||||
uint32_t now_millis = millis(); // Should not jump with time changes
|
||||
uint32_t OldtrxTimeMsec = 0;
|
||||
@@ -246,8 +246,10 @@ void PacketHistory::insert(PacketRecord &r)
|
||||
#if RECENT_WARN_AGE > 0
|
||||
if (tu->rxTimeMsec && (OldtrxTimeMsec < RECENT_WARN_AGE)) {
|
||||
if (!(tu->id == r.id && tu->sender == r.sender)) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_WARN("Packet History - insert: Reusing slot aged %ds < %ds RECENT_WARN_AGE", OldtrxTimeMsec / 1000,
|
||||
RECENT_WARN_AGE / 1000);
|
||||
#endif
|
||||
} else {
|
||||
// debug only
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
@@ -275,7 +277,9 @@ void PacketHistory::insert(PacketRecord &r)
|
||||
#endif
|
||||
|
||||
if (r.rxTimeMsec == 0) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_WARN("Packet History - insert: I will not store packet with rxTimeMsec = 0.");
|
||||
#endif
|
||||
return; // Return early if we can't update the history
|
||||
}
|
||||
|
||||
@@ -304,7 +308,7 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketRecord *found = find(sender, id);
|
||||
const PacketRecord *found = find(sender, id);
|
||||
|
||||
if (found == NULL) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
@@ -323,7 +327,7 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, PacketRecord &r)
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const PacketRecord &r)
|
||||
{
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS; i++) {
|
||||
if (r.relayed_by[i] == relayer) {
|
||||
|
||||
@@ -31,11 +31,11 @@ class PacketHistory
|
||||
|
||||
/** Insert/Replace oldest PacketRecord in mx_recentPackets.
|
||||
* @param r PacketRecord to insert or replace */
|
||||
void insert(PacketRecord &r); // Insert or replace a packet record in the history
|
||||
void insert(const PacketRecord &r); // Insert or replace a packet record in the history
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, PacketRecord &r);
|
||||
bool wasRelayer(const uint8_t relayer, const PacketRecord &r);
|
||||
|
||||
PacketHistory(const PacketHistory &); // non construction-copyable
|
||||
PacketHistory &operator=(const PacketHistory &); // non copyable
|
||||
|
||||
@@ -205,6 +205,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
// app not to send locations on our behalf.
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
|
||||
strncpy(myNodeInfo.pio_env, optstr(APP_ENV), sizeof(myNodeInfo.pio_env));
|
||||
myNodeInfo.nodedb_count = static_cast<uint16_t>(nodeDB->getNumMeshNodes());
|
||||
fromRadioScratch.my_info = myNodeInfo;
|
||||
state = STATE_SEND_UIDATA;
|
||||
|
||||
@@ -686,7 +687,8 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
|
||||
LOG_WARN("Rate limit portnum %d", p.decoded.portnum);
|
||||
meshtastic_QueueStatus qs = router->getQueueStatus();
|
||||
service->sendQueueStatusToPhone(qs, 0, p.id);
|
||||
sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds");
|
||||
service->sendRoutingErrorResponse(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED, &p);
|
||||
// sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds");
|
||||
return false;
|
||||
}
|
||||
lastPortNumToRadio[p.decoded.portnum] = millis();
|
||||
|
||||
+36
-10
@@ -12,6 +12,12 @@
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
|
||||
// Calculate 2^n without calling pow()
|
||||
uint32_t pow_of_2(uint32_t n)
|
||||
{
|
||||
return 1 << n;
|
||||
}
|
||||
|
||||
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, wide_lora) \
|
||||
{ \
|
||||
meshtastic_Config_LoRaConfig_RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, \
|
||||
@@ -61,6 +67,7 @@ const RegionInfo regions[] = {
|
||||
/*
|
||||
https://www.iot.org.au/wp/wp-content/uploads/2016/12/IoTSpectrumFactSheet.pdf
|
||||
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
|
||||
Also used in Brazil.
|
||||
*/
|
||||
RDEF(ANZ, 915.0f, 928.0f, 100, 0, 30, true, false, false),
|
||||
|
||||
@@ -155,6 +162,29 @@ const RegionInfo regions[] = {
|
||||
RDEF(PH_433, 433.0f, 434.7f, 100, 0, 10, true, false, false), RDEF(PH_868, 868.0f, 869.4f, 100, 0, 14, true, false, false),
|
||||
RDEF(PH_915, 915.0f, 918.0f, 100, 0, 24, true, false, false),
|
||||
|
||||
/*
|
||||
Kazakhstan
|
||||
433.075 - 434.775 MHz <10 mW EIRP, Low Powered Devices (LPD)
|
||||
863 - 868 MHz <25 mW EIRP, 500kHz channels allowed, must not be used at airfields
|
||||
https://github.com/meshtastic/firmware/issues/7204
|
||||
*/
|
||||
RDEF(KZ_433, 433.075f, 434.775f, 100, 0, 10, true, false, false), RDEF(KZ_863, 863.0f, 868.0f, 100, 0, 30, true, false, true),
|
||||
|
||||
|
||||
/*
|
||||
Nepal
|
||||
865 MHz to 868 MHz frequency band for IoT (Internet of Things), M2M (Machine-to-Machine), and smart metering use, specifically in non-cellular mode.
|
||||
https://www.nta.gov.np/uploads/contents/Radio-Frequency-Policy-2080-English.pdf
|
||||
*/
|
||||
RDEF(NP_865, 865.0f, 868.0f, 100, 0, 30, true, false, false),
|
||||
|
||||
/*
|
||||
Brazil
|
||||
902 - 907.5 MHz , 1W power limit, no duty cycle restrictions
|
||||
https://github.com/meshtastic/firmware/issues/3741
|
||||
*/
|
||||
RDEF(BR_902, 902.0f, 907.5f, 100, 0, 30, true, false, false),
|
||||
|
||||
/*
|
||||
2.4 GHZ WLAN Band equivalent. Only for SX128x chips.
|
||||
*/
|
||||
@@ -246,7 +276,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const meshtastic_MeshPacket *p)
|
||||
float channelUtil = airTime->channelUtilizationPercent();
|
||||
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
|
||||
// Assuming we pick max. of CWsize and there will be a client with SNR at half the range
|
||||
return 2 * packetAirtime + (pow(2, CWsize) + 2 * CWmax + pow(2, int((CWmax + CWmin) / 2))) * slotTimeMsec +
|
||||
return 2 * packetAirtime + (pow_of_2(CWsize) + 2 * CWmax + pow_of_2(int((CWmax + CWmin) / 2))) * slotTimeMsec +
|
||||
PROCESSING_TIME_MSEC;
|
||||
}
|
||||
|
||||
@@ -259,7 +289,7 @@ uint32_t RadioInterface::getTxDelayMsec()
|
||||
float channelUtil = airTime->channelUtilizationPercent();
|
||||
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
|
||||
// LOG_DEBUG("Current channel utilization is %f so setting CWsize to %d", channelUtil, CWsize);
|
||||
return random(0, pow(2, CWsize)) * slotTimeMsec;
|
||||
return random(0, pow_of_2(CWsize)) * slotTimeMsec;
|
||||
}
|
||||
|
||||
/** The CW size to use when calculating SNR_based delays */
|
||||
@@ -279,7 +309,7 @@ uint32_t RadioInterface::getTxDelayMsecWeightedWorst(float snr)
|
||||
{
|
||||
uint8_t CWsize = getCWsize(snr);
|
||||
// offset the maximum delay for routers: (2 * CWmax * slotTimeMsec)
|
||||
return (2 * CWmax * slotTimeMsec) + pow(2, CWsize) * slotTimeMsec;
|
||||
return (2 * CWmax * slotTimeMsec) + pow_of_2(CWsize) * slotTimeMsec;
|
||||
}
|
||||
|
||||
/** The delay to use when we want to flood a message */
|
||||
@@ -296,7 +326,7 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr)
|
||||
LOG_DEBUG("rx_snr found in packet. Router: setting tx delay:%d", delay);
|
||||
} else {
|
||||
// offset the maximum delay for routers: (2 * CWmax * slotTimeMsec)
|
||||
delay = (2 * CWmax * slotTimeMsec) + random(0, pow(2, CWsize)) * slotTimeMsec;
|
||||
delay = (2 * CWmax * slotTimeMsec) + random(0, pow_of_2(CWsize)) * slotTimeMsec;
|
||||
LOG_DEBUG("rx_snr found in packet. Setting tx delay:%d", delay);
|
||||
}
|
||||
|
||||
@@ -596,7 +626,7 @@ void RadioInterface::applyModemConfig()
|
||||
uint32_t RadioInterface::computeSlotTimeMsec()
|
||||
{
|
||||
float sumPropagationTurnaroundMACTime = 0.2 + 0.4 + 7; // in milliseconds
|
||||
float symbolTime = pow(2, sf) / bw; // in milliseconds
|
||||
float symbolTime = pow_of_2(sf) / bw; // in milliseconds
|
||||
|
||||
if (myRegion->wideLora) {
|
||||
// CAD duration derived from AN1200.22 of SX1280
|
||||
@@ -631,10 +661,6 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
|
||||
if (power > loraMaxPower) // Clamp power to maximum defined level
|
||||
power = loraMaxPower;
|
||||
|
||||
if (TX_GAIN_LORA == 0) { // Setting power in config with defined TX_GAIN_LORA will cause decreasing power on each reboot
|
||||
config.lora.tx_power = power; // Set limited power in config
|
||||
}
|
||||
|
||||
LOG_INFO("Final Tx power: %d dBm", power);
|
||||
}
|
||||
|
||||
@@ -675,4 +701,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
|
||||
|
||||
sendingPacket = p;
|
||||
return p->encrypted.size + sizeof(PacketHeader);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-7
@@ -224,9 +224,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) {
|
||||
float hourlyTxPercent = airTime->utilizationTXPercent();
|
||||
if (hourlyTxPercent > myRegion->dutyCycle) {
|
||||
#ifdef DEBUG_PORT
|
||||
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle);
|
||||
|
||||
LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d mins", silentMinutes);
|
||||
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->has_reply_id = true;
|
||||
cn->reply_id = p->id;
|
||||
@@ -234,7 +235,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
cn->time = getValidTime(RTCQualityFromNet);
|
||||
sprintf(cn->message, "Duty cycle limit exceeded. You can send again in %d mins", silentMinutes);
|
||||
service->sendClientNotification(cn);
|
||||
#endif
|
||||
|
||||
meshtastic_Routing_Error err = meshtastic_Routing_Error_DUTY_CYCLE_LIMIT;
|
||||
if (isFromUs(p)) { // only send NAK to API, not to the mesh
|
||||
abortSendAndNak(err, p);
|
||||
@@ -651,11 +652,12 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
shouldIgnoreNonstandardPorts = true;
|
||||
#endif
|
||||
if (shouldIgnoreNonstandardPorts && p->which_payload_variant == meshtastic_MeshPacket_decoded_tag &&
|
||||
IS_ONE_OF(p->decoded.portnum, meshtastic_PortNum_ATAK_FORWARDER, meshtastic_PortNum_ATAK_PLUGIN,
|
||||
meshtastic_PortNum_PAXCOUNTER_APP, meshtastic_PortNum_IP_TUNNEL_APP, meshtastic_PortNum_AUDIO_APP,
|
||||
meshtastic_PortNum_PRIVATE_APP, meshtastic_PortNum_DETECTION_SENSOR_APP, meshtastic_PortNum_RANGE_TEST_APP,
|
||||
meshtastic_PortNum_REMOTE_HARDWARE_APP)) {
|
||||
LOG_DEBUG("Ignore packet on blacklisted portnum for CORE_PORTNUMS_ONLY");
|
||||
!IS_ONE_OF(p->decoded.portnum, meshtastic_PortNum_TEXT_MESSAGE_APP, meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP,
|
||||
meshtastic_PortNum_POSITION_APP, meshtastic_PortNum_NODEINFO_APP, meshtastic_PortNum_ROUTING_APP,
|
||||
meshtastic_PortNum_TELEMETRY_APP, meshtastic_PortNum_ADMIN_APP, meshtastic_PortNum_ALERT_APP,
|
||||
meshtastic_PortNum_KEY_VERIFICATION_APP, meshtastic_PortNum_WAYPOINT_APP,
|
||||
meshtastic_PortNum_STORE_FORWARD_APP, meshtastic_PortNum_TRACEROUTE_APP)) {
|
||||
LOG_DEBUG("Ignore packet on non-standard portnum for CORE_PORTNUMS_ONLY");
|
||||
cancelSending(p->from, p->id);
|
||||
skipHandle = true;
|
||||
}
|
||||
|
||||
+27
-1
@@ -10,6 +10,32 @@
|
||||
#include "aes-ccm.h"
|
||||
#if !MESHTASTIC_EXCLUDE_PKI
|
||||
|
||||
/**
|
||||
* Constant-time comparison of two byte arrays
|
||||
*
|
||||
* @param a First byte array to compare
|
||||
* @param b Second byte array to compare
|
||||
* @param len Number of bytes to compare
|
||||
* @return 0 if arrays are equal, -1 if different or if inputs are invalid
|
||||
*/
|
||||
static int constant_time_compare(const void *a_, const void *b_, size_t len)
|
||||
{
|
||||
/* Cast to volatile to prevent the compiler from optimizing out their comparison. */
|
||||
const volatile uint8_t *volatile a = (const volatile uint8_t *volatile)a_;
|
||||
const volatile uint8_t *volatile b = (const volatile uint8_t *volatile)b_;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (a == NULL || b == NULL)
|
||||
return -1;
|
||||
size_t i;
|
||||
volatile uint8_t d = 0U;
|
||||
for (i = 0U; i < len; i++) {
|
||||
d |= (a[i] ^ b[i]);
|
||||
}
|
||||
/* Constant time bit arithmetic to convert d > 0 to -1 and d = 0 to 0. */
|
||||
return (1 & ((d - 1) >> 8)) - 1;
|
||||
}
|
||||
|
||||
static void WPA_PUT_BE16(uint8_t *a, uint16_t val)
|
||||
{
|
||||
a[0] = val >> 8;
|
||||
@@ -146,7 +172,7 @@ bool aes_ccm_ad(const uint8_t *key, size_t key_len, const uint8_t *nonce, size_t
|
||||
aes_ccm_encr(L, crypt, crypt_len, plain, a);
|
||||
aes_ccm_auth_start(M, L, nonce, aad, aad_len, crypt_len, x);
|
||||
aes_ccm_auth(plain, crypt_len, x);
|
||||
if (memcmp(x, t, M) != 0) { // FIXME make const comp
|
||||
if (constant_time_compare(x, t, M) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -68,6 +68,11 @@ static int32_t reconnectETH()
|
||||
initApiServer();
|
||||
}
|
||||
#endif
|
||||
#if HAS_UDP_MULTICAST
|
||||
if (udpHandler && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
|
||||
udpHandler->start();
|
||||
}
|
||||
#endif
|
||||
|
||||
ethStartupComplete = true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
bool initEthernet();
|
||||
bool isEthernetAvailable();
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include "meshtastic/channel.pb.h"
|
||||
#include "meshtastic/config.pb.h"
|
||||
#include "meshtastic/connection_status.pb.h"
|
||||
#include "meshtastic/device_ui.pb.h"
|
||||
#include "meshtastic/mesh.pb.h"
|
||||
#include "meshtastic/module_config.pb.h"
|
||||
#include "meshtastic/device_ui.pb.h"
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
|
||||
@@ -102,7 +102,11 @@ typedef enum _meshtastic_Config_DeviceConfig_BuzzerMode {
|
||||
meshtastic_Config_DeviceConfig_BuzzerMode_NOTIFICATIONS_ONLY = 2,
|
||||
/* Non-notification system buzzer tones only.
|
||||
Buzzer is enabled only for non-notification tones such as button presses, startup, shutdown, but not for alerts. */
|
||||
meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY = 3
|
||||
meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY = 3,
|
||||
/* Direct Message notifications only.
|
||||
Buzzer is enabled only for direct messages and alerts, but not for button presses.
|
||||
External notification config determines the specifics of the notification behavior. */
|
||||
meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY = 4
|
||||
} meshtastic_Config_DeviceConfig_BuzzerMode;
|
||||
|
||||
/* Bit field of boolean configuration options, indicating which optional
|
||||
@@ -285,7 +289,15 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
|
||||
/* Philippines 915mhz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_PH_915 = 21,
|
||||
/* Australia / New Zealand 433MHz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 = 22
|
||||
meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 = 22,
|
||||
/* Kazakhstan 433MHz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_KZ_433 = 23,
|
||||
/* Kazakhstan 863MHz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_KZ_863 = 24,
|
||||
/* Nepal 865MHz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_NP_865 = 25,
|
||||
/* Brazil 902MHz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_BR_902 = 26
|
||||
} meshtastic_Config_LoRaConfig_RegionCode;
|
||||
|
||||
/* Standard predefined channel settings
|
||||
@@ -472,7 +484,8 @@ typedef struct _meshtastic_Config_DisplayConfig {
|
||||
/* Number of seconds the screen stays on after pressing the user button or receiving a message
|
||||
0 for default of one minute MAXUINT for always on */
|
||||
uint32_t screen_on_secs;
|
||||
/* How the GPS coordinates are formatted on the OLED screen. */
|
||||
/* Deprecated in 2.7.4: Unused
|
||||
How the GPS coordinates are formatted on the OLED screen. */
|
||||
meshtastic_Config_DisplayConfig_GpsCoordinateFormat gps_format;
|
||||
/* Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds.
|
||||
Potentially useful for devices without user buttons. */
|
||||
@@ -641,8 +654,8 @@ extern "C" {
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY+1))
|
||||
|
||||
#define _meshtastic_Config_DeviceConfig_BuzzerMode_MIN meshtastic_Config_DeviceConfig_BuzzerMode_ALL_ENABLED
|
||||
#define _meshtastic_Config_DeviceConfig_BuzzerMode_MAX meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY
|
||||
#define _meshtastic_Config_DeviceConfig_BuzzerMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_BuzzerMode)(meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY+1))
|
||||
#define _meshtastic_Config_DeviceConfig_BuzzerMode_MAX meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY
|
||||
#define _meshtastic_Config_DeviceConfig_BuzzerMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_BuzzerMode)(meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY+1))
|
||||
|
||||
#define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET
|
||||
#define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED
|
||||
@@ -681,8 +694,8 @@ extern "C" {
|
||||
#define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1))
|
||||
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_ANZ_433
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_ANZ_433+1))
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_BR_902
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_BR_902+1))
|
||||
|
||||
#define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST
|
||||
#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
#include <pb.h>
|
||||
#include <vector>
|
||||
#include "meshtastic/channel.pb.h"
|
||||
#include "meshtastic/mesh.pb.h"
|
||||
#include "meshtastic/telemetry.pb.h"
|
||||
#include "meshtastic/config.pb.h"
|
||||
#include "meshtastic/localonly.pb.h"
|
||||
#include "meshtastic/mesh.pb.h"
|
||||
#include "meshtastic/telemetry.pb.h"
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
@@ -362,7 +362,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
|
||||
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
|
||||
#define meshtastic_BackupPreferences_size 2271
|
||||
#define meshtastic_ChannelFile_size 718
|
||||
#define meshtastic_DeviceState_size 1722
|
||||
#define meshtastic_DeviceState_size 1728
|
||||
#define meshtastic_NodeInfoLite_size 196
|
||||
#define meshtastic_PositionLite_size 28
|
||||
#define meshtastic_UserLite_size 98
|
||||
|
||||
@@ -117,6 +117,8 @@ PB_BIND(meshtastic_ChunkedPayloadResponse, meshtastic_ChunkedPayloadResponse, AU
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
#include <pb.h>
|
||||
#include "meshtastic/channel.pb.h"
|
||||
#include "meshtastic/config.pb.h"
|
||||
#include "meshtastic/device_ui.pb.h"
|
||||
#include "meshtastic/module_config.pb.h"
|
||||
#include "meshtastic/portnums.pb.h"
|
||||
#include "meshtastic/telemetry.pb.h"
|
||||
#include "meshtastic/xmodem.pb.h"
|
||||
#include "meshtastic/device_ui.pb.h"
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
@@ -247,32 +247,26 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_NOMADSTAR_METEOR_PRO = 96,
|
||||
/* Elecrow CrowPanel Advance models, ESP32-S3 and TFT with SX1262 radio plugin */
|
||||
meshtastic_HardwareModel_CROWPANEL = 97,
|
||||
/* *
|
||||
Lilygo LINK32 board with sensors */
|
||||
/* Lilygo LINK32 board with sensors */
|
||||
meshtastic_HardwareModel_LINK_32 = 98,
|
||||
/* *
|
||||
Seeed Tracker L1 */
|
||||
/* Seeed Tracker L1 */
|
||||
meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1 = 99,
|
||||
/* *
|
||||
Seeed Tracker L1 EINK driver */
|
||||
/* Seeed Tracker L1 EINK driver */
|
||||
meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK = 100,
|
||||
/* Reserved ID for future and past use */
|
||||
meshtastic_HardwareModel_QWANTZ_TINY_ARMS = 101,
|
||||
/* *
|
||||
Lilygo T-Deck Pro */
|
||||
/* Lilygo T-Deck Pro */
|
||||
meshtastic_HardwareModel_T_DECK_PRO = 102,
|
||||
/* *
|
||||
Lilygo TLora Pager */
|
||||
/* Lilygo TLora Pager */
|
||||
meshtastic_HardwareModel_T_LORA_PAGER = 103,
|
||||
/* *
|
||||
GAT562 Mesh Trial Tracker */
|
||||
/* GAT562 Mesh Trial Tracker */
|
||||
meshtastic_HardwareModel_GAT562_MESH_TRIAL_TRACKER = 104,
|
||||
/* *
|
||||
RAKwireless WisMesh Tag */
|
||||
/* RAKwireless WisMesh Tag */
|
||||
meshtastic_HardwareModel_WISMESH_TAG = 105,
|
||||
/* *
|
||||
RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ */
|
||||
/* RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ */
|
||||
meshtastic_HardwareModel_RAK3312 = 106,
|
||||
/* Elecrow ThinkNode M5 https://www.elecrow.com/wiki/ThinkNode_M5_Meshtastic_LoRa_Signal_Transceiver_ESP32-S3.html */
|
||||
meshtastic_HardwareModel_THINKNODE_M5 = 107,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
@@ -331,6 +325,25 @@ typedef enum _meshtastic_CriticalErrorCode {
|
||||
meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE = 13
|
||||
} meshtastic_CriticalErrorCode;
|
||||
|
||||
/* Enum to indicate to clients whether this firmware is a special firmware build, like an event.
|
||||
The first 16 values are reserved for non-event special firmwares, like the Smart Citizen use case. */
|
||||
typedef enum _meshtastic_FirmwareEdition {
|
||||
/* Vanilla firmware */
|
||||
meshtastic_FirmwareEdition_VANILLA = 0,
|
||||
/* Firmware for use in the Smart Citizen environmental monitoring network */
|
||||
meshtastic_FirmwareEdition_SMART_CITIZEN = 1,
|
||||
/* Open Sauce, the maker conference held yearly in CA */
|
||||
meshtastic_FirmwareEdition_OPEN_SAUCE = 16,
|
||||
/* DEFCON, the yearly hacker conference */
|
||||
meshtastic_FirmwareEdition_DEFCON = 17,
|
||||
/* Burning Man, the yearly hippie gathering in the desert */
|
||||
meshtastic_FirmwareEdition_BURNING_MAN = 18,
|
||||
/* Hamvention, the Dayton amateur radio convention */
|
||||
meshtastic_FirmwareEdition_HAMVENTION = 19,
|
||||
/* Placeholder for DIY and unofficial events */
|
||||
meshtastic_FirmwareEdition_DIY_EDITION = 127
|
||||
} meshtastic_FirmwareEdition;
|
||||
|
||||
/* Enum for modules excluded from a device's configuration.
|
||||
Each value represents a ModuleConfigType that can be toggled as excluded
|
||||
by setting its corresponding bit in the `excluded_modules` bitmask field. */
|
||||
@@ -432,7 +445,10 @@ typedef enum _meshtastic_Routing_Error {
|
||||
/* Admin packet otherwise checks out, but uses a bogus or expired session key */
|
||||
meshtastic_Routing_Error_ADMIN_BAD_SESSION_KEY = 36,
|
||||
/* Admin packet sent using PKC, but not from a public key on the admin key list */
|
||||
meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37
|
||||
meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37,
|
||||
/* Airtime fairness rate limit exceeded for a packet
|
||||
This typically enforced per portnum and is used to prevent a single node from monopolizing airtime */
|
||||
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38
|
||||
} meshtastic_Routing_Error;
|
||||
|
||||
/* The priority of this message for sending.
|
||||
@@ -917,6 +933,11 @@ typedef struct _meshtastic_MyNodeInfo {
|
||||
meshtastic_MyNodeInfo_device_id_t device_id;
|
||||
/* The PlatformIO environment used to build this firmware */
|
||||
char pio_env[40];
|
||||
/* The indicator for whether this device is running event firmware and which */
|
||||
meshtastic_FirmwareEdition firmware_edition;
|
||||
/* The number of nodes in the nodedb.
|
||||
This is used by the phone to know how many NodeInfo packets to expect on want_config */
|
||||
uint16_t nodedb_count;
|
||||
} meshtastic_MyNodeInfo;
|
||||
|
||||
/* Debug output from the device.
|
||||
@@ -1215,6 +1236,10 @@ extern "C" {
|
||||
#define _meshtastic_CriticalErrorCode_MAX meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE
|
||||
#define _meshtastic_CriticalErrorCode_ARRAYSIZE ((meshtastic_CriticalErrorCode)(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE+1))
|
||||
|
||||
#define _meshtastic_FirmwareEdition_MIN meshtastic_FirmwareEdition_VANILLA
|
||||
#define _meshtastic_FirmwareEdition_MAX meshtastic_FirmwareEdition_DIY_EDITION
|
||||
#define _meshtastic_FirmwareEdition_ARRAYSIZE ((meshtastic_FirmwareEdition)(meshtastic_FirmwareEdition_DIY_EDITION+1))
|
||||
|
||||
#define _meshtastic_ExcludedModules_MIN meshtastic_ExcludedModules_EXCLUDED_NONE
|
||||
#define _meshtastic_ExcludedModules_MAX meshtastic_ExcludedModules_NETWORK_CONFIG
|
||||
#define _meshtastic_ExcludedModules_ARRAYSIZE ((meshtastic_ExcludedModules)(meshtastic_ExcludedModules_NETWORK_CONFIG+1))
|
||||
@@ -1228,8 +1253,8 @@ extern "C" {
|
||||
#define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1))
|
||||
|
||||
#define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE
|
||||
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED
|
||||
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED+1))
|
||||
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED
|
||||
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1))
|
||||
|
||||
#define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET
|
||||
#define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX
|
||||
@@ -1261,6 +1286,7 @@ extern "C" {
|
||||
#define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed
|
||||
|
||||
|
||||
#define meshtastic_MyNodeInfo_firmware_edition_ENUMTYPE meshtastic_FirmwareEdition
|
||||
|
||||
#define meshtastic_LogRecord_level_ENUMTYPE meshtastic_LogRecord_Level
|
||||
|
||||
@@ -1299,7 +1325,7 @@ extern "C" {
|
||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0}
|
||||
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0}
|
||||
#define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, ""}
|
||||
#define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, "", _meshtastic_FirmwareEdition_MIN, 0}
|
||||
#define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||
#define meshtastic_QueueStatus_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}}
|
||||
@@ -1330,7 +1356,7 @@ extern "C" {
|
||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0}
|
||||
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0}
|
||||
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, ""}
|
||||
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, "", _meshtastic_FirmwareEdition_MIN, 0}
|
||||
#define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||
#define meshtastic_QueueStatus_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}}
|
||||
@@ -1453,6 +1479,8 @@ extern "C" {
|
||||
#define meshtastic_MyNodeInfo_min_app_version_tag 11
|
||||
#define meshtastic_MyNodeInfo_device_id_tag 12
|
||||
#define meshtastic_MyNodeInfo_pio_env_tag 13
|
||||
#define meshtastic_MyNodeInfo_firmware_edition_tag 14
|
||||
#define meshtastic_MyNodeInfo_nodedb_count_tag 15
|
||||
#define meshtastic_LogRecord_message_tag 1
|
||||
#define meshtastic_LogRecord_time_tag 2
|
||||
#define meshtastic_LogRecord_source_tag 3
|
||||
@@ -1685,7 +1713,9 @@ X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, reboot_count, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, min_app_version, 11) \
|
||||
X(a, STATIC, SINGULAR, BYTES, device_id, 12) \
|
||||
X(a, STATIC, SINGULAR, STRING, pio_env, 13)
|
||||
X(a, STATIC, SINGULAR, STRING, pio_env, 13) \
|
||||
X(a, STATIC, SINGULAR, UENUM, firmware_edition, 14) \
|
||||
X(a, STATIC, SINGULAR, UINT32, nodedb_count, 15)
|
||||
#define meshtastic_MyNodeInfo_CALLBACK NULL
|
||||
#define meshtastic_MyNodeInfo_DEFAULT NULL
|
||||
|
||||
@@ -1968,7 +1998,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
||||
#define meshtastic_LowEntropyKey_size 0
|
||||
#define meshtastic_MeshPacket_size 378
|
||||
#define meshtastic_MqttClientProxyMessage_size 501
|
||||
#define meshtastic_MyNodeInfo_size 77
|
||||
#define meshtastic_MyNodeInfo_size 83
|
||||
#define meshtastic_NeighborInfo_size 258
|
||||
#define meshtastic_Neighbor_size 22
|
||||
#define meshtastic_NodeInfo_size 323
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
/* Enum definitions */
|
||||
/* Any significant power changing event in meshtastic should be tagged with a powermon state transition.
|
||||
If you are making new meshtastic features feel free to add new entries at the end of this definition. */
|
||||
If you are making new meshtastic features feel free to add new entries at the end of this definition. */
|
||||
typedef enum _meshtastic_PowerMon_State {
|
||||
meshtastic_PowerMon_State_None = 0,
|
||||
meshtastic_PowerMon_State_CPU_DeepSleep = 1,
|
||||
@@ -34,13 +34,13 @@ something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of
|
||||
meshtastic_PowerMon_State_Screen_Drawing = 512,
|
||||
meshtastic_PowerMon_State_Wifi_On = 1024,
|
||||
/* GPS is actively trying to find our location
|
||||
See GPSPowerState for more details */
|
||||
See GPSPowerState for more details */
|
||||
meshtastic_PowerMon_State_GPS_Active = 2048
|
||||
} meshtastic_PowerMon_State;
|
||||
|
||||
/* What operation would we like the UUT to perform.
|
||||
note: senders should probably set want_response in their request packets, so that they can know when the state
|
||||
machine has started processing their request */
|
||||
note: senders should probably set want_response in their request packets, so that they can know when the state
|
||||
machine has started processing their request */
|
||||
typedef enum _meshtastic_PowerStressMessage_Opcode {
|
||||
/* Unset/unused */
|
||||
meshtastic_PowerStressMessage_Opcode_UNSET = 0,
|
||||
@@ -67,7 +67,7 @@ typedef enum _meshtastic_PowerStressMessage_Opcode {
|
||||
|
||||
/* Struct definitions */
|
||||
/* Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs).
|
||||
But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) */
|
||||
But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) */
|
||||
typedef struct _meshtastic_PowerMon {
|
||||
char dummy_field;
|
||||
} meshtastic_PowerMon;
|
||||
|
||||
@@ -93,7 +93,13 @@ typedef enum _meshtastic_TelemetrySensorType {
|
||||
/* PCT2075 Temperature Sensor */
|
||||
meshtastic_TelemetrySensorType_PCT2075 = 39,
|
||||
/* ADS1X15 ADC */
|
||||
meshtastic_TelemetrySensorType_ADS1X15 = 40
|
||||
meshtastic_TelemetrySensorType_ADS1X15 = 40,
|
||||
/* ADS1X15 ADC_ALT */
|
||||
meshtastic_TelemetrySensorType_ADS1X15_ALT = 41,
|
||||
/* Sensirion SFA30 Formaldehyde sensor */
|
||||
meshtastic_TelemetrySensorType_SFA30 = 42,
|
||||
/* SEN5X PM SENSORS */
|
||||
meshtastic_TelemetrySensorType_SEN5X = 43
|
||||
} meshtastic_TelemetrySensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -242,45 +248,81 @@ typedef struct _meshtastic_PowerMetrics {
|
||||
|
||||
/* Air quality metrics */
|
||||
typedef struct _meshtastic_AirQualityMetrics {
|
||||
/* Concentration Units Standard PM1.0 */
|
||||
/* Concentration Units Standard PM1.0 in ug/m3 */
|
||||
bool has_pm10_standard;
|
||||
uint32_t pm10_standard;
|
||||
/* Concentration Units Standard PM2.5 */
|
||||
/* Concentration Units Standard PM2.5 in ug/m3 */
|
||||
bool has_pm25_standard;
|
||||
uint32_t pm25_standard;
|
||||
/* Concentration Units Standard PM10.0 */
|
||||
/* Concentration Units Standard PM10.0 in ug/m3 */
|
||||
bool has_pm100_standard;
|
||||
uint32_t pm100_standard;
|
||||
/* Concentration Units Environmental PM1.0 */
|
||||
/* Concentration Units Environmental PM1.0 in ug/m3 */
|
||||
bool has_pm10_environmental;
|
||||
uint32_t pm10_environmental;
|
||||
/* Concentration Units Environmental PM2.5 */
|
||||
/* Concentration Units Environmental PM2.5 in ug/m3 */
|
||||
bool has_pm25_environmental;
|
||||
uint32_t pm25_environmental;
|
||||
/* Concentration Units Environmental PM10.0 */
|
||||
/* Concentration Units Environmental PM10.0 in ug/m3 */
|
||||
bool has_pm100_environmental;
|
||||
uint32_t pm100_environmental;
|
||||
/* 0.3um Particle Count */
|
||||
/* 0.3um Particle Count in #/0.1l */
|
||||
bool has_particles_03um;
|
||||
uint32_t particles_03um;
|
||||
/* 0.5um Particle Count */
|
||||
/* 0.5um Particle Count in #/0.1l */
|
||||
bool has_particles_05um;
|
||||
uint32_t particles_05um;
|
||||
/* 1.0um Particle Count */
|
||||
/* 1.0um Particle Count in #/0.1l */
|
||||
bool has_particles_10um;
|
||||
uint32_t particles_10um;
|
||||
/* 2.5um Particle Count */
|
||||
/* 2.5um Particle Count in #/0.1l */
|
||||
bool has_particles_25um;
|
||||
uint32_t particles_25um;
|
||||
/* 5.0um Particle Count */
|
||||
/* 5.0um Particle Count in #/0.1l */
|
||||
bool has_particles_50um;
|
||||
uint32_t particles_50um;
|
||||
/* 10.0um Particle Count */
|
||||
/* 10.0um Particle Count in #/0.1l */
|
||||
bool has_particles_100um;
|
||||
uint32_t particles_100um;
|
||||
/* CO2 concentration in ppm */
|
||||
bool has_co2;
|
||||
uint32_t co2;
|
||||
/* CO2 sensor temperature in degC */
|
||||
bool has_co2_temperature;
|
||||
float co2_temperature;
|
||||
/* CO2 sensor relative humidity in % */
|
||||
bool has_co2_humidity;
|
||||
float co2_humidity;
|
||||
/* Formaldehyde sensor formaldehyde concentration in ppb */
|
||||
bool has_form_formaldehyde;
|
||||
float form_formaldehyde;
|
||||
/* Formaldehyde sensor relative humidity in %RH */
|
||||
bool has_form_humidity;
|
||||
float form_humidity;
|
||||
/* Formaldehyde sensor temperature in degrees Celsius */
|
||||
bool has_form_temperature;
|
||||
float form_temperature;
|
||||
/* Concentration Units Standard PM4.0 in ug/m3 */
|
||||
bool has_pm40_standard;
|
||||
uint32_t pm40_standard;
|
||||
/* 4.0um Particle Count in #/0.1l */
|
||||
bool has_particles_40um;
|
||||
uint32_t particles_40um;
|
||||
/* PM Sensor Temperature */
|
||||
bool has_pm_temperature;
|
||||
float pm_temperature;
|
||||
/* PM Sensor humidity */
|
||||
bool has_pm_humidity;
|
||||
float pm_humidity;
|
||||
/* PM Sensor VOC Index */
|
||||
bool has_pm_voc_idx;
|
||||
float pm_voc_idx;
|
||||
/* PM Sensor NOx Index */
|
||||
bool has_pm_nox_idx;
|
||||
float pm_nox_idx;
|
||||
/* Typical Particle Size in um */
|
||||
bool has_particles_tps;
|
||||
float particles_tps;
|
||||
} meshtastic_AirQualityMetrics;
|
||||
|
||||
/* Local device mesh statistics */
|
||||
@@ -392,8 +434,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_ADS1X15
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_ADS1X15+1))
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SEN5X
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SEN5X+1))
|
||||
|
||||
|
||||
|
||||
@@ -409,7 +451,7 @@ extern "C" {
|
||||
#define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0}
|
||||
#define meshtastic_HostMetrics_init_default {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
|
||||
@@ -418,7 +460,7 @@ extern "C" {
|
||||
#define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0}
|
||||
#define meshtastic_HostMetrics_init_zero {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
|
||||
@@ -482,6 +524,18 @@ extern "C" {
|
||||
#define meshtastic_AirQualityMetrics_particles_50um_tag 11
|
||||
#define meshtastic_AirQualityMetrics_particles_100um_tag 12
|
||||
#define meshtastic_AirQualityMetrics_co2_tag 13
|
||||
#define meshtastic_AirQualityMetrics_co2_temperature_tag 14
|
||||
#define meshtastic_AirQualityMetrics_co2_humidity_tag 15
|
||||
#define meshtastic_AirQualityMetrics_form_formaldehyde_tag 16
|
||||
#define meshtastic_AirQualityMetrics_form_humidity_tag 17
|
||||
#define meshtastic_AirQualityMetrics_form_temperature_tag 18
|
||||
#define meshtastic_AirQualityMetrics_pm40_standard_tag 19
|
||||
#define meshtastic_AirQualityMetrics_particles_40um_tag 20
|
||||
#define meshtastic_AirQualityMetrics_pm_temperature_tag 21
|
||||
#define meshtastic_AirQualityMetrics_pm_humidity_tag 22
|
||||
#define meshtastic_AirQualityMetrics_pm_voc_idx_tag 23
|
||||
#define meshtastic_AirQualityMetrics_pm_nox_idx_tag 24
|
||||
#define meshtastic_AirQualityMetrics_particles_tps_tag 25
|
||||
#define meshtastic_LocalStats_uptime_seconds_tag 1
|
||||
#define meshtastic_LocalStats_channel_utilization_tag 2
|
||||
#define meshtastic_LocalStats_air_util_tx_tag 3
|
||||
@@ -587,7 +641,19 @@ X(a, STATIC, OPTIONAL, UINT32, particles_10um, 9) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, particles_25um, 10) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, particles_50um, 11) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, particles_100um, 12) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, co2, 13)
|
||||
X(a, STATIC, OPTIONAL, UINT32, co2, 13) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, co2_temperature, 14) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, co2_humidity, 15) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, form_formaldehyde, 16) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, form_humidity, 17) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, form_temperature, 18) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, pm40_standard, 19) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, particles_40um, 20) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, pm_temperature, 21) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, pm_humidity, 22) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, pm_voc_idx, 23) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, pm_nox_idx, 24) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, particles_tps, 25)
|
||||
#define meshtastic_AirQualityMetrics_CALLBACK NULL
|
||||
#define meshtastic_AirQualityMetrics_DEFAULT NULL
|
||||
|
||||
@@ -676,7 +742,7 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size
|
||||
#define meshtastic_AirQualityMetrics_size 78
|
||||
#define meshtastic_AirQualityMetrics_size 150
|
||||
#define meshtastic_DeviceMetrics_size 27
|
||||
#define meshtastic_EnvironmentMetrics_size 113
|
||||
#define meshtastic_HealthMetrics_size 11
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
#include "main.h"
|
||||
#include "mesh/Router.h"
|
||||
|
||||
#include <AsyncUDP.h>
|
||||
#if HAS_ETHERNET && defined(ARCH_NRF52)
|
||||
#include "mesh/eth/ethClient.h"
|
||||
#else
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
#include <AsyncUDP.h>
|
||||
|
||||
#if HAS_ETHERNET && defined(USE_WS5500)
|
||||
#include <ETHClass2.h>
|
||||
@@ -22,11 +27,11 @@ class UdpMulticastHandler final
|
||||
void start()
|
||||
{
|
||||
if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT, 64)) {
|
||||
#ifndef ARCH_PORTDUINO
|
||||
// FIXME(PORTDUINO): arduino lacks IPAddress::toString()
|
||||
LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str());
|
||||
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
|
||||
LOG_DEBUG("UDP Listening on IP: %u.%u.%u.%u:%u", udpIpAddress[0], udpIpAddress[1], udpIpAddress[2], udpIpAddress[3],
|
||||
UDP_MULTICAST_DEFAUL_PORT);
|
||||
#else
|
||||
LOG_DEBUG("UDP Listening");
|
||||
LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str());
|
||||
#endif
|
||||
udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); });
|
||||
} else {
|
||||
@@ -37,7 +42,10 @@ class UdpMulticastHandler final
|
||||
void onReceive(AsyncUDPPacket packet)
|
||||
{
|
||||
size_t packetLength = packet.length();
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if defined(ARCH_NRF52)
|
||||
IPAddress ip = packet.remoteIP();
|
||||
LOG_DEBUG("UDP broadcast from: %u.%u.%u.%u, len=%u", ip[0], ip[1], ip[2], ip[3], packetLength);
|
||||
#elif !defined(ARCH_PORTDUINO)
|
||||
// FIXME(PORTDUINO): arduino lacks IPAddress::toString()
|
||||
LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength);
|
||||
#endif
|
||||
@@ -61,7 +69,11 @@ class UdpMulticastHandler final
|
||||
if (!mp || !udp) {
|
||||
return false;
|
||||
}
|
||||
#ifndef ARCH_PORTDUINO
|
||||
#if defined(ARCH_NRF52)
|
||||
if (!isEthernetAvailable()) {
|
||||
return false;
|
||||
}
|
||||
#elif !defined(ARCH_PORTDUINO)
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -87,16 +87,18 @@ static void onNetworkConnected()
|
||||
|
||||
// start mdns
|
||||
if (!MDNS.begin("Meshtastic")) {
|
||||
LOG_ERROR("Error setting up MDNS responder!");
|
||||
LOG_ERROR("Error setting up mDNS responder!");
|
||||
} else {
|
||||
LOG_INFO("mDNS Host: Meshtastic.local");
|
||||
MDNS.addService("meshtastic", "tcp", SERVER_API_DEFAULT_PORT);
|
||||
// ESPmDNS (ESP32) and SimpleMDNS (RP2040) have slightly different APIs for adding TXT records
|
||||
#ifdef ARCH_ESP32
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("https", "tcp", 443);
|
||||
MDNS.addServiceTxt("meshtastic", "tcp", "shortname", String(owner.short_name));
|
||||
MDNS.addServiceTxt("meshtastic", "tcp", "id", String(owner.id));
|
||||
// ESP32 prints obtained IP address in WiFiEvent
|
||||
#elif defined(ARCH_RP2040)
|
||||
// ARCH_RP2040 does not support HTTPS
|
||||
MDNS.addServiceTxt("meshtastic", "shortname", owner.short_name);
|
||||
MDNS.addServiceTxt("meshtastic", "id", owner.id);
|
||||
LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
+3
-2
@@ -13,8 +13,9 @@ template <class T> constexpr const T &clamp(const T &v, const T &lo, const T &hi
|
||||
|
||||
#if HAS_SCREEN
|
||||
#define IF_SCREEN(X) \
|
||||
if (screen) \
|
||||
X;
|
||||
if (screen) { \
|
||||
X; \
|
||||
}
|
||||
#else
|
||||
#define IF_SCREEN(...)
|
||||
#endif
|
||||
|
||||
+39
-15
@@ -43,6 +43,10 @@
|
||||
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C
|
||||
#include "motion/AccelerometerThread.h"
|
||||
#endif
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#include "SerialModule.h"
|
||||
#endif
|
||||
|
||||
AdminModule *adminModule;
|
||||
bool hasOpenEditTransaction;
|
||||
@@ -596,7 +600,6 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
||||
if (config.device.button_gpio == c.payload_variant.device.button_gpio &&
|
||||
config.device.buzzer_gpio == c.payload_variant.device.buzzer_gpio &&
|
||||
config.device.role == c.payload_variant.device.role &&
|
||||
config.device.disable_triple_click == c.payload_variant.device.disable_triple_click &&
|
||||
config.device.rebroadcast_mode == c.payload_variant.device.rebroadcast_mode) {
|
||||
requiresReboot = false;
|
||||
}
|
||||
@@ -630,6 +633,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
||||
#if USERPREFS_EVENT_MODE
|
||||
// If we're in event mode, nobody is a Router or Repeater
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
||||
}
|
||||
@@ -638,7 +642,16 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
||||
case meshtastic_Config_position_tag:
|
||||
LOG_INFO("Set config: Position");
|
||||
config.has_position = true;
|
||||
// If we have turned off the GPS (disabled or not present) and we're not using fixed position,
|
||||
// clear the stored position since it may not get updated
|
||||
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED &&
|
||||
c.payload_variant.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED &&
|
||||
config.position.fixed_position == false && c.payload_variant.position.fixed_position == false) {
|
||||
nodeDB->clearLocalPosition();
|
||||
saveChanges(SEGMENT_NODEDATABASE | SEGMENT_CONFIG, false);
|
||||
}
|
||||
config.position = c.payload_variant.position;
|
||||
|
||||
// Save nodedb as well in case we got a fixed position packet
|
||||
break;
|
||||
case meshtastic_Config_power_tag:
|
||||
@@ -798,8 +811,13 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
||||
|
||||
bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
||||
{
|
||||
if (!hasOpenEditTransaction)
|
||||
// If we are in an open transaction or configuring MQTT or Serial (which have validation), defer disabling Bluetooth
|
||||
// Otherwise, disable Bluetooth to prevent the phone from interfering with the config
|
||||
if (!hasOpenEditTransaction &&
|
||||
!IS_ONE_OF(c.which_payload_variant, meshtastic_ModuleConfig_mqtt_tag, meshtastic_ModuleConfig_serial_tag)) {
|
||||
disableBluetooth();
|
||||
}
|
||||
|
||||
switch (c.which_payload_variant) {
|
||||
case meshtastic_ModuleConfig_mqtt_tag:
|
||||
#if MESHTASTIC_EXCLUDE_MQTT
|
||||
@@ -810,12 +828,22 @@ bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
||||
if (!MQTT::isValidConfig(c.payload_variant.mqtt)) {
|
||||
return false;
|
||||
}
|
||||
// Disable Bluetooth to prevent interference during MQTT configuration
|
||||
disableBluetooth();
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.mqtt = c.payload_variant.mqtt;
|
||||
#endif
|
||||
break;
|
||||
case meshtastic_ModuleConfig_serial_tag:
|
||||
LOG_INFO("Set module config: Serial");
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
if (!SerialModule::isValidConfig(c.payload_variant.serial)) {
|
||||
LOG_ERROR("Invalid serial config");
|
||||
return false;
|
||||
}
|
||||
disableBluetooth(); // Disable Bluetooth to prevent interference during Serial configuration
|
||||
#endif
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.serial = c.payload_variant.serial;
|
||||
break;
|
||||
@@ -971,9 +999,10 @@ void AdminModule::handleGetConfig(const meshtastic_MeshPacket &req, const uint32
|
||||
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
|
||||
// using to the app (so that even old phone apps work with new device loads).
|
||||
// r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
|
||||
// hideSecret(r.get_radio_response.preferences.wifi_ssid); // hmm - leave public for now, because only minimally private
|
||||
// and useful for users to know current provisioning) hideSecret(r.get_radio_response.preferences.wifi_password);
|
||||
// r.get_config_response.which_payloadVariant = Config_ModuleConfig_telemetry_tag;
|
||||
// hideSecret(r.get_radio_response.preferences.wifi_ssid); // hmm - leave public for now, because only minimally
|
||||
// private and useful for users to know current provisioning)
|
||||
// hideSecret(r.get_radio_response.preferences.wifi_password); r.get_config_response.which_payloadVariant =
|
||||
// Config_ModuleConfig_telemetry_tag;
|
||||
res.which_payload_variant = meshtastic_AdminMessage_get_config_response_tag;
|
||||
setPassKey(&res);
|
||||
myReply = allocDataProtobuf(res);
|
||||
@@ -1057,9 +1086,10 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
||||
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
|
||||
// using to the app (so that even old phone apps work with new device loads).
|
||||
// r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
|
||||
// hideSecret(r.get_radio_response.preferences.wifi_ssid); // hmm - leave public for now, because only minimally private
|
||||
// and useful for users to know current provisioning) hideSecret(r.get_radio_response.preferences.wifi_password);
|
||||
// r.get_config_response.which_payloadVariant = Config_ModuleConfig_telemetry_tag;
|
||||
// hideSecret(r.get_radio_response.preferences.wifi_ssid); // hmm - leave public for now, because only minimally
|
||||
// private and useful for users to know current provisioning)
|
||||
// hideSecret(r.get_radio_response.preferences.wifi_password); r.get_config_response.which_payloadVariant =
|
||||
// Config_ModuleConfig_telemetry_tag;
|
||||
res.which_payload_variant = meshtastic_AdminMessage_get_module_config_response_tag;
|
||||
setPassKey(&res);
|
||||
myReply = allocDataProtobuf(res);
|
||||
@@ -1190,7 +1220,7 @@ void AdminModule::reboot(int32_t seconds)
|
||||
{
|
||||
LOG_INFO("Reboot in %d seconds", seconds);
|
||||
if (screen)
|
||||
screen->showOverlayBanner("Rebooting...", 0); // stays on screen
|
||||
screen->showSimpleBanner("Rebooting...", 0); // stays on screen
|
||||
rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000);
|
||||
}
|
||||
|
||||
@@ -1326,12 +1356,6 @@ void AdminModule::handleSendInputEvent(const meshtastic_AdminMessage_InputEvent
|
||||
LOG_DEBUG("Processing input event: event_code=%u, kb_char=%u, touch_x=%u, touch_y=%u", inputEvent.event_code,
|
||||
inputEvent.kb_char, inputEvent.touch_x, inputEvent.touch_y);
|
||||
|
||||
// Validate input parameters
|
||||
if (inputEvent.event_code > INPUT_BROKER_ANYKEY) {
|
||||
LOG_WARN("Invalid input event code: %u", inputEvent.event_code);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create InputEvent for injection
|
||||
InputEvent event = {.inputEvent = (input_broker_event)inputEvent.event_code,
|
||||
.kbchar = (unsigned char)inputEvent.kb_char,
|
||||
|
||||
@@ -56,6 +56,7 @@ CannedMessageModule::CannedMessageModule()
|
||||
disable();
|
||||
} else {
|
||||
LOG_INFO("CannedMessageModule is enabled");
|
||||
moduleConfig.canned_message.enabled = true;
|
||||
this->inputObserver.observe(inputBroker);
|
||||
}
|
||||
}
|
||||
@@ -442,25 +443,34 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event
|
||||
return 1;
|
||||
}
|
||||
|
||||
// UP
|
||||
if (isUp && destIndex > 0) {
|
||||
destIndex--;
|
||||
if (isUp) {
|
||||
if (destIndex > 0) {
|
||||
destIndex--;
|
||||
} else if (totalEntries > 0) {
|
||||
destIndex = totalEntries - 1;
|
||||
}
|
||||
|
||||
if ((destIndex / columns) < scrollIndex)
|
||||
scrollIndex = destIndex / columns;
|
||||
else if ((destIndex / columns) >= (scrollIndex + visibleRows))
|
||||
scrollIndex = (destIndex / columns) - visibleRows + 1;
|
||||
|
||||
screen->forceDisplay();
|
||||
screen->forceDisplay(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// DOWN
|
||||
if (isDown && destIndex + 1 < totalEntries) {
|
||||
destIndex++;
|
||||
if (isDown) {
|
||||
if (destIndex + 1 < totalEntries) {
|
||||
destIndex++;
|
||||
} else if (totalEntries > 0) {
|
||||
destIndex = 0;
|
||||
scrollIndex = 0;
|
||||
}
|
||||
|
||||
if ((destIndex / columns) >= (scrollIndex + visibleRows))
|
||||
scrollIndex = (destIndex / columns) - visibleRows + 1;
|
||||
|
||||
screen->forceDisplay();
|
||||
screen->forceDisplay(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -482,7 +492,7 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event
|
||||
|
||||
runState = returnToCannedList ? CANNED_MESSAGE_RUN_STATE_ACTIVE : CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||
returnToCannedList = false;
|
||||
screen->forceDisplay();
|
||||
screen->forceDisplay(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -495,7 +505,7 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event
|
||||
// UIFrameEvent e;
|
||||
// e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
||||
// notifyObservers(&e);
|
||||
screen->forceDisplay();
|
||||
screen->forceDisplay(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -707,7 +717,7 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
|
||||
}
|
||||
|
||||
// Backspace
|
||||
if (event->inputEvent == INPUT_BROKER_BACK) {
|
||||
if (event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() > 0) {
|
||||
payload = 0x08;
|
||||
lastTouchMillis = millis();
|
||||
runOnce();
|
||||
@@ -730,7 +740,8 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
|
||||
}
|
||||
|
||||
// Cancel (dismiss freetext screen)
|
||||
if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG) {
|
||||
if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG ||
|
||||
(event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() == 0)) {
|
||||
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
freetext = "";
|
||||
cursor = 0;
|
||||
@@ -840,7 +851,13 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha
|
||||
this->waitingForAck = true;
|
||||
|
||||
// Log outgoing message
|
||||
LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
LOG_INFO("Send message id=%u, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
|
||||
if (p->to != 0xffffffff) {
|
||||
LOG_INFO("Proactively adding %x as favorite node", p->to);
|
||||
nodeDB->set_favorite(true, p->to);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
}
|
||||
|
||||
// Send to mesh and phone (even if no phone connected, to track ACKs)
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
@@ -980,6 +997,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
this->cursor--;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
break;
|
||||
case INPUT_BROKER_MSG_TAB: // Tab key: handled by input handler
|
||||
@@ -1430,7 +1448,7 @@ void CannedMessageModule::drawEmotePickerScreen(OLEDDisplay *display, OLEDDispla
|
||||
int headerY = y;
|
||||
int listTop = headerY + headerFontHeight + headerMargin;
|
||||
|
||||
int visibleRows = (display->getHeight() - listTop - 2) / rowHeight;
|
||||
int _visibleRows = (display->getHeight() - listTop - 2) / rowHeight;
|
||||
int numEmotes = graphics::numEmotes;
|
||||
|
||||
// Clamp highlight index
|
||||
@@ -1440,11 +1458,11 @@ void CannedMessageModule::drawEmotePickerScreen(OLEDDisplay *display, OLEDDispla
|
||||
emotePickerIndex = numEmotes - 1;
|
||||
|
||||
// Determine which emote is at the top
|
||||
int topIndex = emotePickerIndex - visibleRows / 2;
|
||||
int topIndex = emotePickerIndex - _visibleRows / 2;
|
||||
if (topIndex < 0)
|
||||
topIndex = 0;
|
||||
if (topIndex > numEmotes - visibleRows)
|
||||
topIndex = std::max(0, numEmotes - visibleRows);
|
||||
if (topIndex > numEmotes - _visibleRows)
|
||||
topIndex = std::max(0, numEmotes - _visibleRows);
|
||||
|
||||
// Draw header/title
|
||||
display->setFont(FONT_SMALL);
|
||||
@@ -1692,7 +1710,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
} else {
|
||||
// Text: split by words and wrap inside word if needed
|
||||
String text = token.second;
|
||||
uint16_t pos = 0;
|
||||
pos = 0;
|
||||
while (pos < text.length()) {
|
||||
// Find next space (or end)
|
||||
int spacePos = text.indexOf(' ', pos);
|
||||
@@ -1736,7 +1754,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
int yLine = inputY;
|
||||
for (auto &line : lines) {
|
||||
int nextX = x;
|
||||
for (auto &token : line) {
|
||||
for (const auto &token : line) {
|
||||
if (token.first) {
|
||||
const graphics::Emote *emote = nullptr;
|
||||
for (int j = 0; j < graphics::numEmotes; j++) {
|
||||
@@ -1772,19 +1790,20 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
|
||||
int topMsg;
|
||||
std::vector<int> rowHeights;
|
||||
int visibleRows;
|
||||
int _visibleRows;
|
||||
|
||||
// Draw header (To: ...)
|
||||
drawHeader(display, x, y, buffer);
|
||||
|
||||
// Shift message list upward by 3 pixels to reduce spacing between header and first message
|
||||
const int listYOffset = y + FONT_HEIGHT_SMALL - 3;
|
||||
visibleRows = (display->getHeight() - listYOffset) / baseRowSpacing;
|
||||
_visibleRows = (display->getHeight() - listYOffset) / baseRowSpacing;
|
||||
|
||||
// Figure out which messages are visible and their needed heights
|
||||
topMsg =
|
||||
(messagesCount > visibleRows && currentMessageIndex >= visibleRows - 1) ? currentMessageIndex - visibleRows + 2 : 0;
|
||||
int countRows = std::min(messagesCount, visibleRows);
|
||||
topMsg = (messagesCount > _visibleRows && currentMessageIndex >= _visibleRows - 1)
|
||||
? currentMessageIndex - _visibleRows + 2
|
||||
: 0;
|
||||
int countRows = std::min(messagesCount, _visibleRows);
|
||||
|
||||
// --- Build per-row max height based on all emotes in line ---
|
||||
for (int i = 0; i < countRows; i++) {
|
||||
@@ -1811,7 +1830,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
int lineY = yCursor;
|
||||
const char *msg = getMessageByIndex(msgIdx);
|
||||
int rowHeight = rowHeights[vis];
|
||||
bool highlight = (msgIdx == currentMessageIndex);
|
||||
bool _highlight = (msgIdx == currentMessageIndex);
|
||||
|
||||
// --- Multi-emote tokenization ---
|
||||
std::vector<std::pair<bool, String>> tokens; // (isEmote, token)
|
||||
@@ -1864,20 +1883,20 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
int textYOffset = (rowHeight - FONT_HEIGHT_SMALL) / 2;
|
||||
|
||||
#ifdef USE_EINK
|
||||
int nextX = x + (highlight ? 12 : 0);
|
||||
if (highlight)
|
||||
int nextX = x + (_highlight ? 12 : 0);
|
||||
if (_highlight)
|
||||
display->drawString(x + 0, lineY + textYOffset, ">");
|
||||
#else
|
||||
int scrollPadding = 8;
|
||||
if (highlight) {
|
||||
if (_highlight) {
|
||||
display->fillRect(x + 0, lineY, display->getWidth() - scrollPadding, rowHeight);
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
int nextX = x + (highlight ? 2 : 0);
|
||||
int nextX = x + (_highlight ? 2 : 0);
|
||||
#endif
|
||||
|
||||
// Draw all tokens left to right
|
||||
for (auto &token : tokens) {
|
||||
for (const auto &token : tokens) {
|
||||
if (token.first) {
|
||||
// Emote
|
||||
const graphics::Emote *emote = nullptr;
|
||||
@@ -1899,7 +1918,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
}
|
||||
#ifndef USE_EINK
|
||||
if (highlight)
|
||||
if (_highlight)
|
||||
display->setColor(WHITE);
|
||||
#endif
|
||||
|
||||
@@ -1907,11 +1926,11 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
|
||||
// Scrollbar
|
||||
if (messagesCount > visibleRows) {
|
||||
if (messagesCount > _visibleRows) {
|
||||
int scrollHeight = display->getHeight() - listYOffset;
|
||||
int scrollTrackX = display->getWidth() - 6;
|
||||
display->drawRect(scrollTrackX, listYOffset, 4, scrollHeight);
|
||||
int barHeight = (scrollHeight * visibleRows) / messagesCount;
|
||||
int barHeight = (scrollHeight * _visibleRows) / messagesCount;
|
||||
int scrollPos = listYOffset + (scrollHeight * topMsg) / messagesCount;
|
||||
display->fillRect(scrollTrackX, scrollPos, 4, barHeight);
|
||||
}
|
||||
@@ -2057,6 +2076,9 @@ void CannedMessageModule::handleSetCannedMessageModuleMessages(const char *from_
|
||||
|
||||
if (changed) {
|
||||
this->saveProtoForModule();
|
||||
if (splitConfiguredMessages()) {
|
||||
moduleConfig.canned_message.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2066,4 +2088,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user