#define MODEL_C5 0xC5 // Heltec Lora32 v3, 433 MHz
#define MODEL_CA 0xCA // Heltec Lora32 v3, 868 MHz
+ // https://resource.heltec.cn/download/Mesh_Node_T114/Datasheet.pdf
+ #define PRODUCT_HELTEC_T114 0xC2 // Heltec Mesh Node T114
+ #define BOARD_HELTEC_T114 0x3C
+ #define MODEL_C6 0xC6 // Heltec Mesh Node T114, 470-510 MHz (HT-n5262-LF)
+ #define MODEL_C7 0xC7 // Heltec Mesh Node T114, 863-928 MHz (HT-n5262-HF)
+
#define PRODUCT_RAK4631 0x10
#define BOARD_RAK4631 0x51
#define MODEL_11 0x11 // RAK4631, 433 Mhz
const int pin_led_tx = LED_GREEN;
const int pin_tcxo_enable = -1;
+ #elif BOARD_MODEL == BOARD_HELTEC_T114
+ #define MODEM SX1262
+ #define HAS_EEPROM false
+ #define HAS_DISPLAY true
+ #define HAS_BLUETOOTH false
+ #define HAS_BLE true
+ #define HAS_CONSOLE false
+ #define HAS_PMU false
+ #define HAS_NP false
+ #define HAS_SD false
+ #define HAS_TCXO true
+ #define HAS_RF_SWITCH_RX_TX true
+ #define HAS_BUSY true
+ #define HAS_INPUT true
+ #define DIO2_AS_RF_SWITCH true
+ #define CONFIG_UART_BUFFER_SIZE 6144
+ #define CONFIG_QUEUE_SIZE 6144
+ #define CONFIG_QUEUE_MAX_LENGTH 200
+ #define EEPROM_SIZE 296
+ #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
+ #define BLE_MANUFACTURER "Heltec"
+ #define BLE_MODEL "HT-n5262"
+
+ // ADC
+ #define PIN_T114_ADC_EN 6
+
+ // External sensors
+ #define PIN_T114_VEXT_EN 21
+
+ // LED
+ #define LED_T114_GREEN 3
+ #define PIN_T114_LED 14
+
+ // SPI
+ #define PIN_T114_MOSI 22
+ #define PIN_T114_MISO 23
+ #define PIN_T114_SCK 19
+ #define PIN_T114_SS 24
+
+ // SX1262
+ #define PIN_T114_RST 25
+ #define PIN_T114_DIO1 20
+ #define PIN_T114_BUSY 17
+
+ // TFT
+ #define DISPLAY_SCALE 2
+ #define PIN_T114_TFT_MOSI 9
+ #define PIN_T114_TFT_MISO 11 // not connected
+ #define PIN_T114_TFT_SCK 8
+ #define PIN_T114_TFT_SS 11
+ #define PIN_T114_TFT_DC 12
+ #define PIN_T114_TFT_RST 2
+ #define PIN_T114_TFT_EN 3
+ #define PIN_T114_TFT_BLGT 15
+
+ // pins for buttons on Heltec T114
+ const int pin_btn_usr1 = 42;
+
+ // pins for sx1262 on Heltec T114
+ const int pin_rxen = -1;
+ const int pin_reset = PIN_T114_RST;
+ const int pin_cs = PIN_T114_SS;
+ const int pin_sclk = PIN_T114_SCK;
+ const int pin_mosi = PIN_T114_MOSI;
+ const int pin_miso = PIN_T114_MISO;
+ const int pin_busy = PIN_T114_BUSY;
+ const int pin_dio = PIN_T114_DIO1;
+ const int pin_led_rx = 35;
+ const int pin_led_tx = 35;
+ const int pin_tcxo_enable = -1;
+
+ // pins for ST7789 display on Heltec T114
+ const int DISPLAY_DC = PIN_T114_TFT_DC;
+ const int DISPLAY_CS = PIN_T114_TFT_SS;
+ const int DISPLAY_MISO = PIN_T114_TFT_MISO;
+ const int DISPLAY_MOSI = PIN_T114_TFT_MOSI;
+ const int DISPLAY_CLK = PIN_T114_TFT_SCK;
+ const int DISPLAY_BL_PIN = PIN_T114_TFT_BLGT;
+ const int DISPLAY_RST = PIN_T114_TFT_RST;
+
#else
#error An unsupported nRF board was selected. Cannot compile RNode firmware.
#endif
#endif
+ #ifndef DISPLAY_SCALE
+ #define DISPLAY_SCALE 1
+ #endif
+
#ifndef HAS_RF_SWITCH_RX_TX
const int pin_rxen = -1;
const int pin_txen = -1;
#if BOARD_MODEL == BOARD_TDECK
#include <Adafruit_ST7789.h>
+#elif BOARD_MODEL == BOARD_HELTEC_T114
+ #include "ST7789Spi.h"
+ #define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
#include <Adafruit_SH110X.h>
#else
Adafruit_ST7789 display = Adafruit_ST7789(DISPLAY_CS, DISPLAY_DC, -1);
#define SSD1306_WHITE ST77XX_WHITE
#define SSD1306_BLACK ST77XX_BLACK
+#elif BOARD_MODEL == BOARD_HELTEC_T114
+ ST7789Spi display(&SPI1, DISPLAY_RST, DISPLAY_DC, DISPLAY_CS);
+ #define SSD1306_WHITE ST77XX_WHITE
+ #define SSD1306_BLACK ST77XX_BLACK
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);
#define SSD1306_WHITE SH110X_WHITE
void update_area_positions() {
if (disp_mode == DISP_MODE_PORTRAIT) {
- p_ad_x = 0;
- p_ad_y = 0;
- p_as_x = 0;
- p_as_y = 64;
+ p_ad_x = 0 * DISPLAY_SCALE;
+ p_ad_y = 0 * DISPLAY_SCALE;
+ p_as_x = 0 * DISPLAY_SCALE;
+ p_as_y = 64 * DISPLAY_SCALE;
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
- p_ad_x = 0;
- p_ad_y = 0;
- p_as_x = 64;
- p_as_y = 0;
+ p_ad_x = 0 * DISPLAY_SCALE;
+ p_ad_y = 0 * DISPLAY_SCALE;
+ p_as_x = 64 * DISPLAY_SCALE;
+ p_as_y = 0 * DISPLAY_SCALE;
}
}
#if BOARD_MODEL == BOARD_TBEAM_S_V1
void set_contrast(Adafruit_SH1106G *display, uint8_t value) {
}
+#elif BOARD_MODEL == BOARD_HELTEC_T114
+ void set_contrast(ST7789Spi *display, uint8_t value) {
+ }
#elif BOARD_MODEL == BOARD_TDECK
void set_contrast(Adafruit_ST7789 *display, uint8_t value) {
static uint8_t level = 0;
delay(50);
digitalWrite(pin_display_en, HIGH);
Wire.begin(SDA_OLED, SCL_OLED);
+ #elif BOARD_MODEL == BOARD_HELTEC_T114
+
+ // enable vext (not required for screen to work, but is done in Heltec example)
+ digitalWrite(PIN_T114_VEXT_EN, HIGH);
+ pinMode(PIN_T114_VEXT_EN, OUTPUT);
+
+ // enable power to display
+ digitalWrite(PIN_T114_TFT_EN, LOW);
+ pinMode(PIN_T114_TFT_EN, OUTPUT);
+
+ // enable backlight led (display is always black without this)
+ digitalWrite(PIN_T114_TFT_BLGT, LOW);
+ pinMode(PIN_T114_TFT_BLGT, OUTPUT);
+
+ // enable adc (not required for screen to work, but is done in Heltec example)
+ digitalWrite(PIN_T114_ADC_EN, HIGH);
+ pinMode(PIN_T114_ADC_EN, OUTPUT);
+
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
Wire.begin(SDA_OLED, SCL_OLED);
#endif
#if BOARD_MODEL == BOARD_TDECK
display.init(240, 320);
display.setSPISpeed(80e6);
+ #elif BOARD_MODEL == BOARD_HELTEC_T114
+ display.init();
+ // set white as default pixel colour for Heltec T114
+ display.setRGB(COLOR565(0xFF, 0xFF, 0xFF));
if (false) {
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
if (!display.begin(display_address, true)) {
} else {
disp_mode = DISP_MODE_PORTRAIT;
}
+ #if BOARD_MODEL != BOARD_HELTEC_T114
display.setRotation(display_rotation);
+ #endif
} else {
#if BOARD_MODEL == BOARD_RNODE_NG_20
disp_mode = DISP_MODE_PORTRAIT;
#elif BOARD_MODEL == BOARD_HELTEC32_V3
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
+ #elif BOARD_MODEL == BOARD_HELTEC_T114
+ disp_mode = DISP_MODE_LANDSCAPE;
#elif BOARD_MODEL == BOARD_RAK4631
disp_mode = DISP_MODE_LANDSCAPE;
display.setRotation(0);
stat_area.cp437(true);
disp_area.cp437(true);
+
+ #if BOARD_MODEL != BOARD_HELTEC_T114
display.cp437(true);
+ #endif
#if HAS_EEPROM
#if MCU_VARIANT != MCU_NRF52
#endif
}
+// draws a line on the screen
+void drawLine(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour) {
+ #if BOARD_MODEL == BOARD_HELTEC_T114
+ if(colour == SSD1306_WHITE){
+ display.setColor(WHITE);
+ } else if(colour == SSD1306_BLACK) {
+ display.setColor(BLACK);
+ }
+ display.drawLine(x, y, width, height);
+ #else
+ display.drawLine(x, y, width, height, colour);
+ #endif
+}
+
+// draws a filled rectangle on the screen
+void fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour) {
+ #if BOARD_MODEL == BOARD_HELTEC_T114
+ if(colour == SSD1306_WHITE){
+ display.setColor(WHITE);
+ } else if(colour == SSD1306_BLACK) {
+ display.setColor(BLACK);
+ }
+ display.fillRect(x, y, width, height);
+ #else
+ display.fillRect(x, y, width, height, colour);
+ #endif
+}
+
+// draws a bitmap to the display and auto scales it based on the boards configured DISPLAY_SCALE
+void drawBitmap(int16_t startX, int16_t startY, const uint8_t* bitmap, int16_t bitmapWidth, int16_t bitmapHeight, uint16_t foregroundColour, uint16_t backgroundColour) {
+ for(int16_t row = 0; row < bitmapHeight; row++){
+ for(int16_t col = 0; col < bitmapWidth; col++){
+
+ // determine index and bitmask
+ int16_t index = row * ((bitmapWidth + 7) / 8) + (col / 8);
+ uint8_t bitmask = 1 << (7 - (col % 8));
+
+ // check if the current pixel is set in the bitmap
+ if(bitmap[index] & bitmask){
+ // draw a scaled rectangle for the foreground pixel
+ fillRect(startX + col * DISPLAY_SCALE, startY + row * DISPLAY_SCALE, DISPLAY_SCALE, DISPLAY_SCALE, foregroundColour);
+ } else {
+ // draw a scaled rectangle for the background pixel
+ fillRect(startX + col * DISPLAY_SCALE, startY + row * DISPLAY_SCALE, DISPLAY_SCALE, DISPLAY_SCALE, backgroundColour);
+ }
+
+ }
+ }
+}
+
void draw_cable_icon(int px, int py) {
if (cable_state == CABLE_STATE_DISCONNECTED) {
stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
draw_stat_area();
if (disp_mode == DISP_MODE_PORTRAIT) {
- display.drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
+ drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
- display.drawBitmap(p_as_x+2, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
- if (device_init_done && !disp_ext_fb) display.drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
+ drawBitmap(p_as_x+2, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
+ if (device_init_done && !disp_ext_fb) drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
}
} else {
if (firmware_update_mode) {
- display.drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
+ drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
} else if (console_active && device_init_done) {
- display.drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
+ drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
if (disp_mode == DISP_MODE_LANDSCAPE) {
- display.drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
+ drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
}
}
}
void update_disp_area() {
draw_disp_area();
- display.drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
+ drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
if (disp_mode == DISP_MODE_LANDSCAPE) {
if (device_init_done && !firmware_update_mode && !disp_ext_fb) {
- display.drawLine(0, 0, 0, 63, SSD1306_WHITE);
+ drawLine(0, 0, 0, 63, SSD1306_WHITE);
}
}
}
disp_area.drawBitmap(0, iy, rand_seg, 64, 1, SSD1306_WHITE, SSD1306_BLACK);
}
- display.drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
+ drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
if (disp_mode == DISP_MODE_PORTRAIT) {
- display.drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
+ drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
- display.drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
+ drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
}
}
set_contrast(&display, display_contrast);
}
- #if BOARD_MODEL != BOARD_TDECK
+ #if BOARD_MODEL == BOARD_HELTEC_T114
+ display.clear();
+ display.display();
+ #elif BOARD_MODEL != BOARD_TDECK
display.clearDisplay();
display.display();
#else
set_contrast(&display, display_contrast);
}
- #if BOARD_MODEL != BOARD_TDECK
+ #if BOARD_MODEL == BOARD_HELTEC_T114
+ display.clear();
+ #elif BOARD_MODEL != BOARD_TDECK
display.clearDisplay();
#endif