diff --git a/README.md b/README.md
index a41e3dcf..910ce69e 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-L
*SPI only*:
- Pyom: WiPy
-- WeMos: LoLin32, LoLin32 Lite, WeMos D32
+- WeMos: LoLin32, LoLin32 Lite, WeMos D32, [Wemos32 Oled](https://www.instructables.com/id/ESP32-With-Integrated-OLED-WEMOSLolin-Getting-Star/)
- Generic ESP32
Depending on board hardware following features are supported:
@@ -54,6 +54,7 @@ Depending on board hardware following features are supported:
- Real Time Clock (Maxim DS3231 I2C)
- IF482 (serial) and DCF77 (gpio) time telegram generator
- Switch external power / battery
+- 64x16 pixel LED Matrix display (similar to [this model](https://www.instructables.com/id/64x16-RED-LED-Marquee/))
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory. If you want to use a ESP32 board which is not yet supported, use hal file generic.h and tailor pin mappings to your needs. Pull requests for new boards welcome.
@@ -153,7 +154,7 @@ Output of user sensor data can be switched by user remote control command 0x13 s
Output of sensor and peripheral data is internally switched by a bitmask register. Default mask (0xFF) can be tailored by editing *cfg.payloadmask* initialization value in [*configmanager.cpp*](src/configmanager.cpp) following this scheme:
| Bit | Sensordata |
-|-----|---------------|
+| --- | ------------- |
| 0 | GPS |
| 1 | Beacon alarm |
| 2 | BME280/680 |
diff --git a/include/button.h b/include/button.h
index b6951ceb..e7799847 100644
--- a/include/button.h
+++ b/include/button.h
@@ -1,6 +1,9 @@
#ifndef _BUTTON_H
#define _BUTTON_H
+#include
+
+void button_init(int pin);
void readButton();
#endif
\ No newline at end of file
diff --git a/include/globals.h b/include/globals.h
index 7b427e5a..a3edad17 100644
--- a/include/globals.h
+++ b/include/globals.h
@@ -113,7 +113,7 @@ extern uint16_t volatile macs_total, macs_wifi, macs_ble,
batt_voltage; // display values
extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC
extern timesource_t timeSource;
-extern hw_timer_t *displayIRQ, *ppsIRQ, *gpsIRQ;
+extern hw_timer_t *displayIRQ, *matrixDisplayIRQ, *ppsIRQ, *gpsIRQ;
extern SemaphoreHandle_t I2Caccess;
extern TaskHandle_t irqHandlerTask, ClockTask;
extern TimerHandle_t WifiChanTimer;
@@ -138,6 +138,10 @@ extern time_t volatile gps_pps_time;
#include "display.h"
#endif
+#ifdef HAS_MATRIX_DISPLAY
+#include "ledmatrixdisplay.h"
+#endif
+
#ifdef HAS_BUTTON
#include "button.h"
#endif
diff --git a/include/irqhandler.h b/include/irqhandler.h
index 67af99ba..db5dd2f1 100644
--- a/include/irqhandler.h
+++ b/include/irqhandler.h
@@ -1,14 +1,15 @@
#ifndef _IRQHANDLER_H
#define _IRQHANDLER_H
-#define DISPLAY_IRQ 0x01
-#define BUTTON_IRQ 0x02
-#define SENDCYCLE_IRQ 0x04
-#define CYCLIC_IRQ 0x08
-#define TIMESYNC_IRQ 0x10
-#define MASK_IRQ 0x20
-#define UNMASK_IRQ 0x40
-#define GPS_IRQ 0x80
+#define DISPLAY_IRQ 0x001
+#define BUTTON_IRQ 0x002
+#define SENDCYCLE_IRQ 0x004
+#define CYCLIC_IRQ 0x008
+#define TIMESYNC_IRQ 0x010
+#define MASK_IRQ 0x020
+#define UNMASK_IRQ 0x040
+#define GPS_IRQ 0x080
+#define MATRIX_DISPLAY_IRQ 0x100
#include "globals.h"
#include "cyclic.h"
@@ -23,6 +24,10 @@ int unmask_user_IRQ();
void IRAM_ATTR DisplayIRQ();
#endif
+#ifdef HAS_MATRIX_DISPLAY
+void IRAM_ATTR MatrixDisplayIRQ();
+#endif
+
#ifdef HAS_BUTTON
void IRAM_ATTR ButtonIRQ();
#endif
diff --git a/include/ledmatrixdisplay.h b/include/ledmatrixdisplay.h
new file mode 100644
index 00000000..5c44676a
--- /dev/null
+++ b/include/ledmatrixdisplay.h
@@ -0,0 +1,17 @@
+#ifndef _MATRIX_DISPLAY_H
+#define _MATRIX_DISPLAY_H
+
+#include "LEDMatrix.h"
+#include "ledmatrixfonts.h"
+
+extern uint8_t MatrixDisplayIsOn = 0;
+
+extern LEDMatrix matrix;
+
+void init_matrix_display(const char *Productname, const char *Version);
+void refreshTheMatrixDisplay(void);
+void DrawNumber(String strNum, uint8_t iDotPos = 0);
+uint8_t GetCharFromFont(char cChar);
+uint8_t GetCharWidth(char cChar);
+
+#endif
\ No newline at end of file
diff --git a/include/ledmatrixfonts.h b/include/ledmatrixfonts.h
new file mode 100644
index 00000000..1539465a
--- /dev/null
+++ b/include/ledmatrixfonts.h
@@ -0,0 +1,40 @@
+// Fonts.h
+
+#ifndef _FONTS_h
+#define _FONTS_h
+
+#include "Arduino.h"
+
+struct FONT_CHAR_INFO {
+ uint8_t width; // width in bits
+ uint8_t height;
+ uint16_t offset; // offset of char into char array
+};
+
+struct FONT_INFO {
+ uint8_t CharHeight;
+ char StartChar;
+ char EndChar;
+ uint8_t SpaceWidth;
+ const FONT_CHAR_INFO *Descriptors;
+ const uint8_t *Bitmap;
+};
+
+// Font data for Microsoft Sans Serif 11pt
+extern const uint8_t arialNarrow_17ptBitmaps[];
+
+extern const uint8_t gillSansMTCondensed_18ptBitmaps[];
+extern const FONT_INFO gillSansMTCondensed_18ptFontInfo;
+extern const FONT_CHAR_INFO gillSansMTCondensed_18ptDescriptors[];
+
+// Font data for Gill Sans MT Condensed 16pt
+extern const uint8_t gillSansMTCondensed_16ptBitmaps[];
+extern const FONT_INFO gillSansMTCondensed_16ptFontInfo;
+extern const FONT_CHAR_INFO gillSansMTCondensed_16ptDescriptors[];
+
+// Font data for Digital-7 18pt
+extern const uint8_t digital7_18ptBitmaps[];
+extern const FONT_INFO digital7_18ptFontInfo;
+extern const FONT_CHAR_INFO digital7_18ptDescriptors[];
+
+#endif
\ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
index edc903b4..e42691a4 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -6,7 +6,7 @@
; ---> SELECT TARGET PLATFORM HERE! <---
[platformio]
-env_default = generic
+;env_default = generic
;env_default = ebox
;env_default = eboxtube
;env_default = ecopower
@@ -24,6 +24,7 @@ env_default = generic
;env_default = lolin32litelora
;env_default = lolin32lora
;env_default = lolin32lite
+env_default = wemos32oled
;env_default = octopus32
;env_default = ecopower, eboxtube, heltec, ttgobeam, lopy4, lopy, ttgov21old, ttgov21new, ttgofox
;
@@ -31,7 +32,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
[common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
-release_version = 1.7.55
+release_version = 1.7.61
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 3
@@ -49,6 +50,8 @@ lib_deps_lora =
https://github.com/mcci-catena/arduino-lmic.git
lib_deps_display =
U8g2@>=2.25.7
+lib_deps_matrix_display =
+ https://github.com/Seeed-Studio/Ultrathin_LED_Matrix.git
lib_deps_rgbled =
SmartLeds@>=1.1.5
lib_deps_gps =
@@ -60,6 +63,7 @@ lib_deps_basic =
ArduinoJson@^5.13.1
Timezone@^1.2.2
RTC@^2.3.0
+ SimpleButton
lib_deps_all =
${common.lib_deps_basic}
${common.lib_deps_lora}
@@ -357,6 +361,22 @@ upload_protocol = ${common.upload_protocol}
extra_scripts = ${common.extra_scripts}
monitor_speed = ${common.monitor_speed}
+[env:wemos32oled]
+platform = ${common.platform_espressif32}
+framework = arduino
+board = lolin32
+board_build.partitions = ${common.board_build.partitions}
+upload_speed = 921600
+lib_deps =
+ ${common.lib_deps_basic}
+ ${common.lib_deps_display}
+ ${common.lib_deps_matrix_display}
+build_flags =
+ ${common.build_flags_all}
+upload_protocol = ${common.upload_protocol}
+extra_scripts = ${common.extra_scripts}
+monitor_speed = ${common.monitor_speed}
+
[env:octopus32]
platform = ${common.platform_espressif32}
framework = arduino
diff --git a/src/TTN/plain_decoder.js b/src/TTN/plain_decoder.js
index d87fcb9e..96655ee7 100644
--- a/src/TTN/plain_decoder.js
+++ b/src/TTN/plain_decoder.js
@@ -81,7 +81,6 @@ function Decoder(bytes, port) {
decoded.time = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]);
decoded.timestatus = bytes[i++];
}
- return decoded;
}
-
+ return decoded;
}
diff --git a/src/button.cpp b/src/button.cpp
index 68e29d4e..ed34367f 100644
--- a/src/button.cpp
+++ b/src/button.cpp
@@ -3,17 +3,44 @@
#include "globals.h"
#include "button.h"
+using namespace simplebutton;
+
// Local logging tag
static const char TAG[] = __FILE__;
-void readButton() {
- ESP_LOGI(TAG, "Button pressed");
-#ifdef HAS_DISPLAY
- refreshtheDisplay(true); // switch to next display page
+static Button *b = NULL;
+
+void button_init(int pin) {
+#ifdef BUTTON_PULLDOWN
+ b = new Button(pin);
#else
- payload.reset();
- payload.addButton(0x01);
- SendPayload(BUTTONPORT, prio_normal);
+ b = new ButtonPullup(pin);
#endif
+
+ // attach events to the button
+
+ b->setOnDoubleClicked([]() {});
+
+ b->setOnClicked([]() {
+#ifdef HAS_DISPLAY
+ refreshtheDisplay(true); // switch to next display page
+#else
+ payload.reset();
+ payload.addButton(0x01);
+ SendPayload(BUTTONPORT, prio_normal);
+#endif
+ });
+
+ b->setOnHolding([]() {
+#if (HAS_LORA)
+ cfg.adrmode = !cfg.adrmode;
+ LMIC_setAdrMode(cfg.adrmode);
+#endif
+ });
+
+ // attach interrupt to the button
+ attachInterrupt(digitalPinToInterrupt(pin), ButtonIRQ, CHANGE);
}
+
+void readButton() { b->update(); }
#endif
\ No newline at end of file
diff --git a/src/hal/wemos32oled.h b/src/hal/wemos32oled.h
new file mode 100644
index 00000000..d5c27832
--- /dev/null
+++ b/src/hal/wemos32oled.h
@@ -0,0 +1,45 @@
+// clang-format off
+
+#ifndef _WEMOS32OLED_H
+#define _WEMOS32OLED_H
+
+#include
+
+// Hardware related definitions for TTGO T-Beam board
+// (only) for older T-Beam version T22_V05 eternal wiring LORA_IO1 to GPIO33 is needed!
+//
+// pinouts taken from http://tinymicros.com/wiki/TTGO_T-Beam
+
+#define HAS_LED NOT_A_PIN // no LED
+
+//#define HAS_LORA 1 // comment out if device shall not send data via LoRa
+//#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
+//#define BOARD_HAS_PSRAM // use extra 4MB external RAM
+//#define HAS_BUTTON GPIO_NUM_39 // on board button (next to reset)
+//#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
+//#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 100k/100k on board
+
+// GPS settings
+//#define HAS_GPS 1 // use on board GPS
+//#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M
+//#define GPS_INT GPIO_NUM_34 // 30ns accurary timepulse, to be external wired on pcb: NEO 6M Pin#3 -> GPIO34
+
+// enable only if device has these sensors, otherwise comment these lines
+// BME680 sensor on I2C bus
+//#define HAS_BME 1 // Enable BME sensors in general
+//#define HAS_BME680 SDA, SCL
+//#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !!
+
+// display (if connected)
+#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
+#define MY_OLED_SDA (5)
+#define MY_OLED_SCL (4)
+#define MY_OLED_RST U8X8_PIN_NONE
+#define DISPLAY_FLIP 1 // use if display is rotated
+
+// user defined sensors (if connected)
+//#define HAS_SENSORS 1 // comment out if device has user defined sensors
+
+//#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
+
+#endif
diff --git a/src/irqhandler.cpp b/src/irqhandler.cpp
index 97c026e0..da999da7 100644
--- a/src/irqhandler.cpp
+++ b/src/irqhandler.cpp
@@ -39,6 +39,12 @@ void irqHandler(void *pvParameters) {
refreshtheDisplay();
#endif
+// LED Matrix display needs refresh?
+#ifdef HAS_MATRIX_DISPLAY
+ if (InterruptStatus & MATRIX_DISPLAY_IRQ)
+ refreshTheMatrixDisplay();
+#endif
+
// gps refresh buffer?
#if (HAS_GPS)
if (InterruptStatus & GPS_IRQ)
@@ -79,6 +85,17 @@ void IRAM_ATTR DisplayIRQ() {
}
#endif
+#ifdef HAS_MATRIX_DISPLAY
+void IRAM_ATTR MatrixDisplayIRQ() {
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ xTaskNotifyFromISR(irqHandlerTask, MATRIX_DISPLAY_IRQ, eSetBits,
+ &xHigherPriorityTaskWoken);
+ if (xHigherPriorityTaskWoken)
+ portYIELD_FROM_ISR();
+}
+#endif
+
#ifdef HAS_BUTTON
void IRAM_ATTR ButtonIRQ() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
diff --git a/src/ledmatrixdisplay.cpp b/src/ledmatrixdisplay.cpp
new file mode 100644
index 00000000..6a4f39d4
--- /dev/null
+++ b/src/ledmatrixdisplay.cpp
@@ -0,0 +1,144 @@
+#ifdef HAS_MATRIX_DISPLAY
+
+#include "globals.h"
+
+#define NUMCHARS 5
+
+// local Tag for logging
+static const char TAG[] = __FILE__;
+
+uint8_t MatrixDisplayIsOn = 0;
+static unsigned long ulLastNumMacs = 0;
+
+LEDMatrix matrix(LED_MATRIX_LA_74138, LED_MATRIX_LB_74138, LED_MATRIX_LC_74138,
+ LED_MATRIX_LD_74138, LED_MATRIX_EN_74138, LED_MATRIX_DATA_R1,
+ LED_MATRIX_LATCHPIN, LED_MATRIX_CLOCKPIN);
+
+// Display Buffer 128 = 64 * 16 / 8
+uint8_t displaybuf[LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT / NUMCHARS];
+
+const FONT_INFO *ActiveFontInfo = &digital7_18ptFontInfo;
+const uint8_t *iaActiveFont = ActiveFontInfo->Bitmap;
+const FONT_CHAR_INFO *ActiveFontCharInfo = ActiveFontInfo->Descriptors;
+
+void init_matrix_display(const char *Productname, const char *Version) {
+ ESP_LOGI(TAG, "Initializing LED Matrix display");
+ matrix.begin(displaybuf, LED_MATRIX_WIDTH, LED_MATRIX_HEIGHT);
+ matrix.reverse();
+ matrix.clear();
+ DrawNumber(String("0"));
+} // init_display
+
+void refreshTheMatrixDisplay() {
+
+ // if Matrixdisplay is switched off we don't refresh it to relax cpu
+ if (!MatrixDisplayIsOn && (MatrixDisplayIsOn == cfg.screenon))
+ return;
+
+ // set display on/off according to current device configuration
+ if (MatrixDisplayIsOn != cfg.screenon) {
+ MatrixDisplayIsOn = cfg.screenon;
+ }
+
+ if (ulLastNumMacs != macs.size()) {
+ ulLastNumMacs = macs.size();
+ matrix.clear();
+ DrawNumber(String(macs.size()));
+ ESP_LOGI(TAG, "Setting display to counter: %lu", macs.size());
+ }
+
+ matrix.scan();
+}
+
+// (x, y) top-left position, x should be multiple of 8
+void DrawChar(uint16_t x, uint16_t y, char cChar) {
+ // Get address of char in font char descriptor from font descriptor
+ auto CharDescAddress = (cChar - ActiveFontInfo->StartChar);
+
+ // Get offset of char into font bitmap
+ uint16_t FontBitmapOffset = ActiveFontCharInfo[CharDescAddress].offset;
+ // Serial.printf("Address of %c is %i, bitmap offset is %u\r\n", cChar,
+ // CharDescAddress, FontBitmapOffset);
+
+ // Check font height, if it's less than matrix height we need to
+ // add some empty lines to font does not stick to the top
+ if (ActiveFontInfo->CharHeight < (LED_MATRIX_HEIGHT - y)) {
+ uint8_t FillerLines = (LED_MATRIX_HEIGHT - y) - ActiveFontInfo->CharHeight;
+ if (FillerLines % 2 == 0) {
+ // Use floor (round down) to get heighest possible divider
+ // for missing lines
+ y = floor(FillerLines / 2);
+ }
+ }
+
+ int iDst = (x / 8) + (y * 8);
+ int Shift = x % 8;
+ // Serial.printf("Got hex '%x'\r\n", pSrc);
+ for (uint8_t i = 0; i < ActiveFontCharInfo[CharDescAddress].height; i++) {
+ int iDigitA = iaActiveFont[FontBitmapOffset];
+
+ int Left = iDigitA >> Shift;
+ int Right = iDigitA << (8 - Shift);
+
+ displaybuf[iDst] |= Left;
+ displaybuf[iDst + 1] |= Right;
+
+ if (ActiveFontCharInfo[CharDescAddress].width > 8) {
+ int iDigitB = iaActiveFont[FontBitmapOffset + 1];
+ Left = iDigitB >> Shift;
+ Right = iDigitB << (8 - Shift);
+
+ displaybuf[iDst + 1] |= Left;
+ displaybuf[iDst + 2] |= Right;
+ FontBitmapOffset++;
+ }
+
+ FontBitmapOffset++;
+ iDst += 8;
+ }
+}
+
+void DrawNumber(String strNum, uint8_t iDotPos) {
+ uint8_t iNumLength = strNum.length();
+ uint8_t iDigitPos = 0;
+
+ // Serial.printf("Showing number '%s' (length: %i)\r\n", strNum.c_str(),
+ // iNumLength);
+ for (int i = 0; i < iNumLength; i++) {
+ // Serial.printf("Showing char '%c' at x:%i y:%i\r\n",
+ // strNum.charAt(i),
+ // iDigitPos, 0);
+ DrawChar(iDigitPos, 0, strNum.charAt(i));
+ if (i + 1 == iDotPos) {
+ // matrix.drawRect((iDigitPos * 8) - 1, 15, iDigitPos * 8,
+ // 16, 1);
+ iDigitPos = iDigitPos + GetCharWidth(strNum.charAt(i)) +
+ ActiveFontInfo->SpaceWidth;
+ DrawChar(iDigitPos, 0, '.');
+ iDigitPos = iDigitPos + GetCharWidth('.') + ActiveFontInfo->SpaceWidth;
+ } else {
+ iDigitPos = iDigitPos + GetCharWidth(strNum.charAt(i)) +
+ ActiveFontInfo->SpaceWidth;
+ }
+ }
+}
+
+uint8_t GetCharFromFont(char cChar) {
+ auto cStartChar = ActiveFontInfo->StartChar;
+ auto iCharLocation = cChar - cStartChar;
+ auto iCharBitmap = iaActiveFont[iCharLocation];
+
+ return iCharBitmap;
+}
+
+uint8_t GetCharWidth(char cChar) {
+ // Get address of char in font char descriptor from font descriptor
+ auto CharDescAddress = (cChar - ActiveFontInfo->StartChar);
+
+ // Get offset of char into font bitmap
+ auto CharDescriptor = ActiveFontCharInfo[CharDescAddress];
+ // Serial.printf("Char %c is %i wide\r\n", cChar, CharDescriptor.width);
+ return CharDescriptor.width;
+}
+
+#endif // HAS_MATRIX_DISPLAY
\ No newline at end of file
diff --git a/src/ledmatrixfonts.cpp b/src/ledmatrixfonts.cpp
new file mode 100644
index 00000000..1dfa2158
--- /dev/null
+++ b/src/ledmatrixfonts.cpp
@@ -0,0 +1,903 @@
+#include "ledmatrixfonts.h"
+#include "Arduino.h"
+//
+// Font data for Arial Narrow 17pt
+//
+
+// Character bitmaps for Arial Narrow 17pt
+const uint8_t arialNarrow_17ptBitmaps[] = {
+ // @0 '-' (10 pixels wide)
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00111110, 0b00000000, // #####
+ 0b00111110, 0b00000000, // #####
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+ 0b00000000, 0b00000000, //
+
+ // @32 '0' (10 pixels wide)
+ 0b00011110, 0b00000000, // ####
+ 0b00111111, 0b00000000, // ######
+ 0b00110011, 0b00000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b00110011, 0b00000000, // ## ##
+ 0b00111111, 0b00000000, // ######
+ 0b00011110, 0b00000000, // ####
+
+ // @64 '1' (10 pixels wide)
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00001110, 0b00000000, // ###
+ 0b00011110, 0b00000000, // ####
+ 0b00110110, 0b00000000, // ## ##
+ 0b00100110, 0b00000000, // # ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+
+ // @96 '2' (10 pixels wide)
+ 0b00011110, 0b00000000, // ####
+ 0b00111111, 0b00000000, // ######
+ 0b00110011, 0b10000000, // ## ###
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b00000001, 0b10000000, // ##
+ 0b00000001, 0b10000000, // ##
+ 0b00000011, 0b00000000, // ##
+ 0b00000111, 0b00000000, // ###
+ 0b00001110, 0b00000000, // ###
+ 0b00001100, 0b00000000, // ##
+ 0b00011000, 0b00000000, // ##
+ 0b00110000, 0b00000000, // ##
+ 0b00100000, 0b00000000, // #
+ 0b01111111, 0b10000000, // ########
+ 0b01111111, 0b10000000, // ########
+
+ // @128 '3' (10 pixels wide)
+ 0b00011110, 0b00000000, // ####
+ 0b00111111, 0b00000000, // ######
+ 0b01110011, 0b10000000, // ### ###
+ 0b01100001, 0b10000000, // ## ##
+ 0b00000001, 0b10000000, // ##
+ 0b00000011, 0b10000000, // ###
+ 0b00001111, 0b00000000, // ####
+ 0b00001110, 0b00000000, // ###
+ 0b00000011, 0b00000000, // ##
+ 0b00000001, 0b10000000, // ##
+ 0b00000001, 0b10000000, // ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b00110011, 0b10000000, // ## ###
+ 0b00111111, 0b00000000, // ######
+ 0b00011110, 0b00000000, // ####
+
+ // @160 '4' (10 pixels wide)
+ 0b00000111, 0b00000000, // ###
+ 0b00000111, 0b00000000, // ###
+ 0b00001111, 0b00000000, // ####
+ 0b00001111, 0b00000000, // ####
+ 0b00011011, 0b00000000, // ## ##
+ 0b00011011, 0b00000000, // ## ##
+ 0b00110011, 0b00000000, // ## ##
+ 0b01100011, 0b00000000, // ## ##
+ 0b01100011, 0b00000000, // ## ##
+ 0b11000011, 0b00000000, // ## ##
+ 0b11111111, 0b11000000, // ##########
+ 0b11111111, 0b11000000, // ##########
+ 0b00000011, 0b00000000, // ##
+ 0b00000011, 0b00000000, // ##
+ 0b00000011, 0b00000000, // ##
+ 0b00000011, 0b00000000, // ##
+
+ // @192 '5' (10 pixels wide)
+ 0b00111111, 0b00000000, // ######
+ 0b00111111, 0b00000000, // ######
+ 0b00110000, 0b00000000, // ##
+ 0b00110000, 0b00000000, // ##
+ 0b01100000, 0b00000000, // ##
+ 0b01101110, 0b00000000, // ## ###
+ 0b01111111, 0b00000000, // #######
+ 0b01110011, 0b10000000, // ### ###
+ 0b00000001, 0b10000000, // ##
+ 0b00000001, 0b10000000, // ##
+ 0b00000001, 0b10000000, // ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b00110011, 0b00000000, // ## ##
+ 0b00111111, 0b00000000, // ######
+ 0b00011110, 0b00000000, // ####
+
+ // @224 '6' (10 pixels wide)
+ 0b00001110, 0b00000000, // ###
+ 0b00011111, 0b00000000, // #####
+ 0b00110011, 0b10000000, // ## ###
+ 0b00100001, 0b10000000, // # ##
+ 0b01100000, 0b00000000, // ##
+ 0b01101110, 0b00000000, // ## ###
+ 0b01111111, 0b00000000, // #######
+ 0b01110011, 0b10000000, // ### ###
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b00110011, 0b00000000, // ## ##
+ 0b00111111, 0b00000000, // ######
+ 0b00011110, 0b00000000, // ####
+
+ // @256 '7' (10 pixels wide)
+ 0b01111111, 0b10000000, // ########
+ 0b01111111, 0b10000000, // ########
+ 0b00000001, 0b00000000, // #
+ 0b00000011, 0b00000000, // ##
+ 0b00000011, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000110, 0b00000000, // ##
+ 0b00000100, 0b00000000, // #
+ 0b00001100, 0b00000000, // ##
+ 0b00001100, 0b00000000, // ##
+ 0b00001100, 0b00000000, // ##
+ 0b00001100, 0b00000000, // ##
+ 0b00011000, 0b00000000, // ##
+ 0b00011000, 0b00000000, // ##
+ 0b00011000, 0b00000000, // ##
+ 0b00011000, 0b00000000, // ##
+
+ // @288 '8' (10 pixels wide)
+ 0b00011110, 0b00000000, // ####
+ 0b00111111, 0b00000000, // ######
+ 0b01110011, 0b10000000, // ### ###
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01110011, 0b10000000, // ### ###
+ 0b00111111, 0b00000000, // ######
+ 0b00111111, 0b00000000, // ######
+ 0b00110011, 0b00000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01110011, 0b10000000, // ### ###
+ 0b00111111, 0b00000000, // ######
+ 0b00011110, 0b00000000, // ####
+
+ // @320 '9' (10 pixels wide)
+ 0b00011110, 0b00000000, // ####
+ 0b00111111, 0b00000000, // ######
+ 0b00110011, 0b00000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01100001, 0b10000000, // ## ##
+ 0b01110011, 0b10000000, // ### ###
+ 0b00111111, 0b10000000, // #######
+ 0b00011101, 0b10000000, // ### ##
+ 0b00000001, 0b10000000, // ##
+ 0b01100001, 0b00000000, // ## #
+ 0b01110011, 0b00000000, // ### ##
+ 0b00111110, 0b00000000, // #####
+ 0b00011100, 0b00000000, // ###
+};
+
+//
+// Font data for Gill Sans MT Condensed 18pt
+//
+
+// Character bitmaps for Gill Sans MT Condensed 18pt
+const uint8_t gillSansMTCondensed_18ptBitmaps[] = {
+ // @0 '-' (8 pixels wide)
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b01111100, // #####
+ 0b01111100, // #####
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+
+ // @16 '0' (8 pixels wide)
+ 0b00111100, // ####
+ 0b01111110, // ######
+ 0b01111110, // ######
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b01111110, // ######
+ 0b01111110, // ######
+ 0b00111100, // ####
+
+ // @32 '1' (8 pixels wide)
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+
+ // @48 '2' (8 pixels wide)
+ 0b11111100, // ######
+ 0b11111110, // #######
+ 0b11001111, // ## ####
+ 0b00000111, // ###
+ 0b00000111, // ###
+ 0b00000111, // ###
+ 0b00000111, // ###
+ 0b00000110, // ##
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b01110000, // ###
+ 0b01111111, // #######
+ 0b11111111, // ########
+
+ // @64 '3' (8 pixels wide)
+ 0b11111000, // #####
+ 0b11111100, // ######
+ 0b00011110, // ####
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00011100, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b11011110, // ## ####
+ 0b11111100, // ######
+ 0b11111000, // #####
+
+ // @80 '4' (8 pixels wide)
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00011110, // ####
+ 0b00011110, // ####
+ 0b00111110, // #####
+ 0b00111110, // #####
+ 0b00111110, // #####
+ 0b01101110, // ## ###
+ 0b01101110, // ## ###
+ 0b11001110, // ## ###
+ 0b11001110, // ## ###
+ 0b11111111, // ########
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+
+ // @96 '5' (8 pixels wide)
+ 0b01111110, // ######
+ 0b01111110, // ######
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01111000, // ####
+ 0b01111100, // #####
+ 0b00011110, // ####
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00011100, // ###
+ 0b11111100, // ######
+ 0b11111000, // #####
+
+ // @112 '6' (8 pixels wide)
+ 0b00001110, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b01110000, // ###
+ 0b01111100, // #####
+ 0b11111110, // #######
+ 0b11110111, // #### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11111111, // ########
+ 0b01111110, // ######
+ 0b00111100, // ####
+
+ // @128 '7' (8 pixels wide)
+ 0b11111111, // ########
+ 0b11111111, // ########
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00110000, // ##
+ 0b01110000, // ###
+ 0b01110000, // ###
+
+ // @144 '8' (8 pixels wide)
+ 0b00111100, // ####
+ 0b01111110, // ######
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b01111110, // ######
+ 0b01111110, // ######
+ 0b01111110, // ######
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11111111, // ########
+ 0b01111110, // ######
+ 0b00111100, // ####
+
+ // @160 '9' (8 pixels wide)
+ 0b00111100, // ####
+ 0b01111110, // ######
+ 0b11111111, // ########
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11100111, // ### ###
+ 0b11101111, // ### ####
+ 0b01111111, // #######
+ 0b00111110, // #####
+ 0b00001110, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b01110000, // ###
+};
+
+// Character descriptors for Gill Sans MT Condensed 18pt
+// { [Char width in bits], [Char height in bits], [Offset into
+// gillSansMTCondensed_18ptCharBitmaps in bytes] }
+const FONT_CHAR_INFO gillSansMTCondensed_18ptDescriptors[] = {
+ {8, 16, 0}, // -
+ {0, 0, 0}, // .
+ {0, 0, 0}, // /
+ {8, 16, 16}, // 0
+ {8, 16, 32}, // 1
+ {8, 16, 48}, // 2
+ {8, 16, 64}, // 3
+ {8, 16, 80}, // 4
+ {8, 16, 96}, // 5
+ {8, 16, 112}, // 6
+ {8, 16, 128}, // 7
+ {8, 16, 144}, // 8
+ {8, 16, 160}, // 9
+};
+
+// Font information for Gill Sans MT Condensed 18pt
+const FONT_INFO gillSansMTCondensed_18ptFontInfo = {
+ 2, // Character height
+ '-', // Start character
+ '9', // End character
+ 2, // Width, in pixels, of space character
+ gillSansMTCondensed_18ptDescriptors,
+ gillSansMTCondensed_18ptBitmaps};
+
+//
+// Font data for Gill Sans MT Condensed 16pt
+//
+
+// Character bitmaps for Gill Sans MT Condensed 16pt
+const uint8_t gillSansMTCondensed_16ptBitmaps[] = {
+ // @0 '-' (7 pixels wide)
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00111110, // #####
+ 0b00111110, // #####
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+
+ // @14 '0' (7 pixels wide)
+ 0b00111000, // ###
+ 0b01111100, // #####
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b01111100, // #####
+ 0b00111000, // ###
+
+ // @28 '1' (7 pixels wide)
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+
+ // @42 '2' (7 pixels wide)
+ 0b11111000, // #####
+ 0b11111100, // ######
+ 0b00011110, // ####
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00001100, // ##
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b01110000, // ###
+ 0b01111110, // ######
+ 0b11111110, // #######
+
+ // @56 '3' (7 pixels wide)
+ 0b11110000, // ####
+ 0b11111000, // #####
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b11111000, // #####
+ 0b11110000, // ####
+
+ // @70 '4' (7 pixels wide)
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111100, // ####
+ 0b00111100, // ####
+ 0b01111100, // #####
+ 0b01111100, // #####
+ 0b01111100, // #####
+ 0b11011100, // ## ###
+ 0b11011100, // ## ###
+ 0b11111110, // #######
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+
+ // @84 '5' (7 pixels wide)
+ 0b01111110, // ######
+ 0b01111110, // ######
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01111100, // #####
+ 0b01111100, // #####
+ 0b00011110, // ####
+ 0b00001110, // ###
+ 0b00001110, // ###
+ 0b00011110, // ####
+ 0b11111100, // ######
+ 0b11111000, // #####
+
+ // @98 '6' (7 pixels wide)
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01111100, // #####
+ 0b11111100, // ######
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b01111100, // #####
+ 0b01111000, // ####
+
+ // @112 '7' (7 pixels wide)
+ 0b11111110, // #######
+ 0b11111110, // #######
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b01110000, // ###
+ 0b01110000, // ###
+ 0b01110000, // ###
+
+ // @126 '8' (7 pixels wide)
+ 0b01111100, // #####
+ 0b01111100, // #####
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b01111100, // #####
+ 0b01111100, // #####
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b01111100, // #####
+ 0b01111100, // #####
+
+ // @140 '9' (7 pixels wide)
+ 0b00111100, // ####
+ 0b01111100, // #####
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b11101110, // ### ###
+ 0b01111110, // ######
+ 0b01111100, // #####
+ 0b00011100, // ###
+ 0b00011100, // ###
+ 0b00111000, // ###
+ 0b00111000, // ###
+ 0b01110000, // ###
+};
+
+// Character descriptors for Gill Sans MT Condensed 16pt
+// { [Char width in bits], [Char height in bits], [Offset into
+// gillSansMTCondensed_16ptCharBitmaps in bytes] }
+const FONT_CHAR_INFO gillSansMTCondensed_16ptDescriptors[] = {
+ {7, 14, 0}, // -
+ {0, 0, 0}, // .
+ {0, 0, 0}, // /
+ {7, 14, 14}, // 0
+ {7, 14, 28}, // 1
+ {7, 14, 42}, // 2
+ {7, 14, 56}, // 3
+ {7, 14, 70}, // 4
+ {7, 14, 84}, // 5
+ {7, 14, 98}, // 6
+ {7, 14, 112}, // 7
+ {7, 14, 126}, // 8
+ {7, 14, 140}, // 9
+};
+
+// Font information for Gill Sans MT Condensed 16pt
+const FONT_INFO gillSansMTCondensed_16ptFontInfo = {
+ 2, // Character height
+ '-', // Start character
+ '9', // End character
+ 2, // Width, in pixels, of space character
+ gillSansMTCondensed_16ptDescriptors, // Character descriptor array
+ gillSansMTCondensed_16ptBitmaps, // Character bitmap array
+};
+
+//
+// Font data for Digital-7 18pt
+//
+
+// Character bitmaps for Digital-7 18pt
+const uint8_t digital7_18ptBitmaps[] = {
+ // @0 '-' (7 pixels wide)
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b11111110, // #######
+ 0b11111110, // #######
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+
+ // @16 '.' (3 pixels wide)
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b00000000, //
+ 0b11100000, // ###
+ 0b11100000, // ###
+
+ // @32 '0' (11 pixels wide)
+ 0b00111111, 0b10000000, // #######
+ 0b01111111, 0b11000000, // #########
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11000000, 0b01100000, // ## ##
+ 0b11000000, 0b01100000, // ## ##
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b01111111, 0b11000000, // #########
+ 0b00111111, 0b10000000, // #######
+
+ // @64 '1' (3 pixels wide)
+ 0b01100000, // ##
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b01100000, // ##
+ 0b01100000, // ##
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b11100000, // ###
+ 0b01100000, // ##
+
+ // @80 '2' (11 pixels wide)
+ 0b11111111, 0b10000000, // #########
+ 0b01111111, 0b11000000, // #########
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b01111111, 0b11100000, // ##########
+ 0b11111111, 0b11000000, // ##########
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b01111111, 0b11000000, // #########
+ 0b00111111, 0b11100000, // #########
+
+ // @112 '3' (10 pixels wide)
+ 0b11111111, 0b00000000, // ########
+ 0b11111111, 0b11000000, // ##########
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b01111111, 0b11000000, // #########
+ 0b01111111, 0b11000000, // #########
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b00000001, 0b11000000, // ###
+ 0b11111111, 0b11000000, // ##########
+ 0b11111111, 0b00000000, // ########
+
+ // @144 '4' (11 pixels wide)
+ 0b11000000, 0b01100000, // ## ##
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11111111, 0b11100000, // ###########
+ 0b01111111, 0b11100000, // ##########
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b01100000, // ##
+
+ // @176 '5' (11 pixels wide)
+ 0b00111111, 0b11000000, // ########
+ 0b01111111, 0b10000000, // ########
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11111111, 0b10000000, // #########
+ 0b01111111, 0b11100000, // ##########
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b01111111, 0b11000000, // #########
+ 0b11111111, 0b10000000, // #########
+
+ // @208 '6' (11 pixels wide)
+ 0b00111111, 0b11000000, // ########
+ 0b01111111, 0b10000000, // ########
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11100000, 0b00000000, // ###
+ 0b11111111, 0b10000000, // #########
+ 0b11111111, 0b11100000, // ###########
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11111111, 0b11100000, // ###########
+ 0b01111111, 0b10000000, // ########
+
+ // @240 '7' (11 pixels wide)
+ 0b00111111, 0b10000000, // #######
+ 0b01111111, 0b11100000, // ##########
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11000000, 0b01100000, // ## ##
+ 0b00000000, 0b01100000, // ##
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b01100000, // ##
+
+ // @272 '8' (11 pixels wide)
+ 0b00111111, 0b10000000, // #######
+ 0b01111111, 0b11000000, // #########
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11111111, 0b11100000, // ###########
+ 0b11111111, 0b11100000, // ###########
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b01111111, 0b11000000, // #########
+ 0b00111111, 0b10000000, // #######
+
+ // @304 '9' (11 pixels wide)
+ 0b00111111, 0b11000000, // ########
+ 0b01111111, 0b11100000, // ##########
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11100000, 0b11100000, // ### ###
+ 0b11111111, 0b11100000, // ###########
+ 0b01111111, 0b11100000, // ##########
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b00000000, 0b11100000, // ###
+ 0b01111111, 0b11000000, // #########
+ 0b11111111, 0b10000000, // #########
+};
+
+// Character descriptors for Digital-7 18pt
+// { [Char width in bits], [Char height in bits], [Offset into
+// digital7_18ptCharBitmaps in bytes] }
+const FONT_CHAR_INFO digital7_18ptDescriptors[] = {
+ {7, 16, 0}, // -
+ {3, 16, 16}, // .
+ {0, 0, 0}, // /
+ {11, 16, 32}, // 0
+ {3, 16, 64}, // 1
+ {11, 16, 80}, // 2
+ {10, 16, 112}, // 3
+ {11, 16, 144}, // 4
+ {11, 16, 176}, // 5
+ {11, 16, 208}, // 6
+ {11, 16, 240}, // 7
+ {11, 16, 272}, // 8
+ {11, 16, 304}, // 9
+};
+
+// Font information for Digital-7 18pt
+const FONT_INFO digital7_18ptFontInfo = {
+ 16, // Character height
+ '-', // Start character
+ '9', // End character
+ 2, // Width, in pixels, of space character
+ digital7_18ptDescriptors, // Character descriptor array
+ digital7_18ptBitmaps, // Character bitmap array
+};
diff --git a/src/main.cpp b/src/main.cpp
index 96198e4a..a26379fc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -52,7 +52,7 @@ So don't do it if you do not own a digital oscilloscope.
0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS)
1 ppsIRQ -> pps clock irq -> 1sec
2 gpsIRQ -> gps store data -> 300ms
-3 unused
+3 MatrixDisplayIRQ -> matrix mux cycle -> 0,5ms (MATRIX_DISPLAY_SCAN_US)
// Interrupt routines
@@ -85,7 +85,8 @@ uint8_t volatile channel = 0; // channel rotation counter
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
batt_voltage = 0; // globals for display
-hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL, *gpsIRQ = NULL;
+hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL, *matrixDisplayIRQ = NULL,
+ *gpsIRQ = NULL;
TaskHandle_t irqHandlerTask = NULL, ClockTask = NULL;
SemaphoreHandle_t I2Caccess;
@@ -265,20 +266,6 @@ void setup() {
esp_coex_prefer_t)ESP_COEX_PREFER_WIFI)); // configure Wifi/BT coexist lib
#endif
-// initialize button
-#ifdef HAS_BUTTON
- strcat_P(features, " BTN_");
-#ifdef BUTTON_PULLUP
- strcat_P(features, "PU");
- // install button interrupt (pullup mode)
- pinMode(HAS_BUTTON, INPUT_PULLUP);
-#else
- strcat_P(features, "PD");
- // install button interrupt (pulldown mode)
- pinMode(HAS_BUTTON, INPUT_PULLDOWN);
-#endif // BUTTON_PULLUP
-#endif // HAS_BUTTON
-
// initialize gps
#if (HAS_GPS)
strcat_P(features, " GPS");
@@ -323,6 +310,13 @@ void setup() {
init_display(PRODUCTNAME, PROGVERSION); // note: blocking call
#endif
+// initialize matrix display
+#ifdef HAS_MATRIX_DISPLAY
+ strcat_P(features, " LED_MATRIX");
+ MatrixDisplayIsOn = cfg.screenon;
+ init_matrix_display(PRODUCTNAME, PROGVERSION); // note: blocking call
+#endif
+
// show payload encoder
#if PAYLOAD_ENCODER == 1
strcat_P(features, " PLAIN");
@@ -364,9 +358,6 @@ void setup() {
esp_wifi_deinit();
#endif
- // show compiled features
- ESP_LOGI(TAG, "Features:%s", features);
-
// start state machine
ESP_LOGI(TAG, "Starting Interrupt Handler...");
xTaskCreatePinnedToCore(irqHandler, // task function
@@ -410,7 +401,28 @@ void setup() {
timerAlarmEnable(displayIRQ);
#endif
- // gps buffer read interrupt
+ // LED Matrix display interrupt
+#ifdef HAS_MATRIX_DISPLAY
+ // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
+ // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 3, count up
+ matrixDisplayIRQ = timerBegin(3, 80, true);
+ timerAttachInterrupt(matrixDisplayIRQ, &MatrixDisplayIRQ, true);
+ timerAlarmWrite(matrixDisplayIRQ, MATRIX_DISPLAY_SCAN_US, true);
+ timerAlarmEnable(matrixDisplayIRQ);
+#endif
+
+ // initialize button
+#ifdef HAS_BUTTON
+ strcat_P(features, " BTN_");
+#ifdef BUTTON_PULLUP
+ strcat_P(features, "PU");
+#else
+ strcat_P(features, "PD");
+#endif // BUTTON_PULLUP
+ button_init(HAS_BUTTON);
+#endif // HAS_BUTTON
+
+ // gps buffer read interrupt
#if (HAS_GPS)
gpsIRQ = timerBegin(2, 80, true);
timerAttachInterrupt(gpsIRQ, &GpsIRQ, true);
@@ -422,15 +434,6 @@ void setup() {
sendcycler.attach(SENDCYCLE * 2, sendcycle);
housekeeper.attach(HOMECYCLE, housekeeping);
-// button interrupt
-#ifdef HAS_BUTTON
-#ifdef BUTTON_PULLUP
- attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
-#else
- attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
-#endif
-#endif // HAS_BUTTON
-
#if (TIME_SYNC_INTERVAL)
#if (!(TIME_SYNC_LORAWAN) && !(TIME_SYNC_LORASERVER) && !defined HAS_GPS && \
@@ -453,6 +456,9 @@ void setup() {
#endif // TIME_SYNC_INTERVAL
+ // show compiled features
+ ESP_LOGI(TAG, "Features:%s", features);
+
} // setup()
void loop() {
diff --git a/src/paxcounter.conf b/src/paxcounter.conf
index f042d2cf..f4ec3bfb 100644
--- a/src/paxcounter.conf
+++ b/src/paxcounter.conf
@@ -110,3 +110,18 @@
// LMIC settings
// -> in src/lmic_config.h
+
+// LED Matrix display settings. Pin numbers work fine for Wemos Lolin32 board (all used pins are on 1 side of the board)
+// Note: LED Matrix will only show number of found devices, no other information will be shown for now
+//#define HAS_MATRIX_DISPLAY 1 // Uncomment to enable LED matrix display output
+#define MATRIX_DISPLAY_SCAN_US 500 // Matrix display scan rate in microseconds (1ms is about 'acceptable')
+#define LED_MATRIX_LATCHPIN 13 // Connects to LAT pin on display
+#define LED_MATRIX_CLOCKPIN 32 // Connects to CLK pin on display
+#define LED_MATRIX_EN_74138 12 // Connects to OE pin on display
+#define LED_MATRIX_LA_74138 14 // Connects to LA pin on display
+#define LED_MATRIX_LB_74138 27 // Connects to LB pin on display
+#define LED_MATRIX_LC_74138 25 // Connects to LC pin on display
+#define LED_MATRIX_LD_74138 26 // Connects to LD pin on display
+#define LED_MATRIX_DATA_R1 33 // Connects to R1 pin on display
+#define LED_MATRIX_WIDTH 64 // Width in pixels (LEDs) of your display
+#define LED_MATRIX_HEIGHT 16 // Height in pixels (LEDs ) of your display
\ No newline at end of file