2026-07-25 20:37:32 +02:00
|
|
|
/*
|
2026-07-25 20:30:01 +02:00
|
|
|
* File: Afficheur.cpp
|
|
|
|
|
* Author: F4GOH
|
2026-07-25 20:37:32 +02:00
|
|
|
*
|
2026-07-25 20:30:01 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Afficheur.h"
|
|
|
|
|
|
|
|
|
|
// Constructeur de Afficheur
|
|
|
|
|
|
|
|
|
|
Afficheur::Afficheur()
|
|
|
|
|
{
|
|
|
|
|
tft = new Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
|
2026-07-25 20:37:32 +02:00
|
|
|
|
2026-07-25 20:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Afficheur::~Afficheur() {
|
|
|
|
|
// Rien à nettoyer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Afficheur::begin() {
|
|
|
|
|
// Initialisation I2C avec adresse 0x3C
|
2026-07-25 20:37:32 +02:00
|
|
|
Wire.begin();
|
|
|
|
|
|
|
|
|
|
if(!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C))
|
|
|
|
|
{
|
|
|
|
|
Serial.println("OLED non detecte");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Serial.println("OLED OK");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialisation rétroéclairage TFT
|
2026-07-25 20:30:01 +02:00
|
|
|
pinMode(TFT_BL, OUTPUT);
|
|
|
|
|
digitalWrite(TFT_BL, HIGH);
|
|
|
|
|
|
|
|
|
|
SPI.setSCK(TFT_SCK);
|
|
|
|
|
SPI.setTX(TFT_MOSI);
|
|
|
|
|
tft->init(172, 320);
|
|
|
|
|
tft->setRotation(1);
|
|
|
|
|
tft->setAddrWindow(34, 0, 172, 320);
|
|
|
|
|
tft->fillScreen(ST77XX_BLACK);
|
2026-07-25 20:37:32 +02:00
|
|
|
tft->setTextWrap(false);
|
|
|
|
|
oled.clearDisplay();
|
2026-07-25 20:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uint16_t Afficheur::lineColors[8] = {
|
|
|
|
|
ST77XX_YELLOW,
|
|
|
|
|
ST77XX_CYAN,
|
|
|
|
|
ST77XX_GREEN,
|
|
|
|
|
ST77XX_MAGENTA,
|
|
|
|
|
ST77XX_ORANGE,
|
|
|
|
|
ST77XX_WHITE,
|
|
|
|
|
ST77XX_RED,
|
|
|
|
|
ST77XX_BLUE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void Afficheur::timeDisplay(char* txt) {
|
|
|
|
|
tft->setTextSize(4);
|
|
|
|
|
tft->setTextColor(ST77XX_CYAN, ST77XX_BLACK);
|
|
|
|
|
|
|
|
|
|
const int width = 172;
|
|
|
|
|
const int height = 22;
|
|
|
|
|
|
|
|
|
|
// Efface uniquement la zone du haut
|
|
|
|
|
tft->fillRect(0, 0, width, height, ST77XX_BLACK);
|
|
|
|
|
|
|
|
|
|
// Petit padding
|
|
|
|
|
tft->setCursor(46, 0);
|
|
|
|
|
tft->print(txt);
|
2026-07-25 20:37:32 +02:00
|
|
|
|
|
|
|
|
oledPrint(txt,0,35,1);
|
2026-07-25 20:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Afficheur::modeDisplay(const char* txt) {
|
|
|
|
|
int16_t x, y;
|
|
|
|
|
uint16_t w, h;
|
|
|
|
|
|
|
|
|
|
tft->setTextSize(4);
|
|
|
|
|
tft->setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
|
|
|
|
|
|
|
|
|
|
tft->getTextBounds(txt, 0, 0, &x, &y, &w, &h);
|
|
|
|
|
|
|
|
|
|
const int width = 320;
|
|
|
|
|
const int height = 172;
|
|
|
|
|
|
|
|
|
|
// Centrage parfait en portrait
|
|
|
|
|
int cx = (width - w) / 2;
|
|
|
|
|
int cy = (height - h) / 2;
|
|
|
|
|
|
|
|
|
|
// Efface uniquement la zone centrale (évite de flinguer le reste)
|
|
|
|
|
int clearY = cy - 4;
|
|
|
|
|
int clearH = h + 8;
|
|
|
|
|
|
|
|
|
|
tft->fillRect(0, clearY, width, clearH, ST77XX_BLACK);
|
|
|
|
|
|
|
|
|
|
tft->setCursor(cx, cy);
|
|
|
|
|
tft->print(txt);
|
2026-07-25 20:37:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Calcul de la largeur approximative
|
|
|
|
|
int16_t x1, y1;
|
|
|
|
|
oled.getTextBounds(txt, 10, 0, &x1, &y1, &w, &h);
|
|
|
|
|
|
|
|
|
|
// centrage horizontal et vertical
|
|
|
|
|
int x0= (128 - w) / 2;
|
|
|
|
|
int y0= (64 - h) / 2;
|
|
|
|
|
oledPrint(txt,40,10,2);
|
2026-07-25 20:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Afficheur::modeEfface() {
|
|
|
|
|
const int width = 172;
|
|
|
|
|
// Zone centrale approximative (même logique que modeDisplay)
|
|
|
|
|
tft->fillRect(0, 120, width, 80, ST77XX_BLACK);
|
2026-07-25 20:37:32 +02:00
|
|
|
|
2026-07-25 20:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Afficheur::clearDisplay() {
|
|
|
|
|
tft->fillScreen(ST77XX_BLACK);
|
2026-07-25 20:37:32 +02:00
|
|
|
oled.fillRect(0, 0, 128, 64, SSD1306_BLACK);
|
2026-07-25 20:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Afficheur::configDisplay(config& cfg) {
|
|
|
|
|
char line[40];
|
|
|
|
|
|
|
|
|
|
// Efface uniquement la fenêtre définie
|
|
|
|
|
tft->fillScreen(ST77XX_BLACK);
|
|
|
|
|
|
|
|
|
|
tft->setTextSize(2);
|
|
|
|
|
|
|
|
|
|
const int x = 0; // relatif à la fenêtre
|
|
|
|
|
const int lineHeight = 22;
|
|
|
|
|
|
|
|
|
|
int y = 10;
|
|
|
|
|
|
|
|
|
|
const char * bandStr[7] = {"160m", "80m", "60m", "40m", "30m", "20m", "free frequency"};
|
|
|
|
|
// Ligne 1 : fréquence et offset
|
|
|
|
|
tft->setTextColor(lineColors[0], ST77XX_BLACK);
|
|
|
|
|
snprintf(line, sizeof(line), " f=%lu %ld band %s", cfg.freq, cfg.offset,bandStr[cfg.band]);
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(line);
|
|
|
|
|
y += lineHeight;
|
2026-07-25 20:37:32 +02:00
|
|
|
snprintf(line, sizeof(line), "f=%lu %ld %s", cfg.freq, cfg.offset,bandStr[cfg.band]);
|
|
|
|
|
oledPrint(line,0,0,1);
|
2026-07-25 20:30:01 +02:00
|
|
|
|
|
|
|
|
// Ligne 2
|
|
|
|
|
tft->setTextColor(lineColors[1], ST77XX_BLACK);
|
|
|
|
|
snprintf(line, sizeof(line), "dbm%u every %u minutes", cfg.dbm, cfg.minute);
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(line);
|
|
|
|
|
y += lineHeight;
|
2026-07-25 20:37:32 +02:00
|
|
|
oledPrint(line,0,8,1);
|
2026-07-25 20:30:01 +02:00
|
|
|
|
|
|
|
|
// Ligne 3
|
|
|
|
|
tft->setTextColor(lineColors[2], ST77XX_BLACK);
|
|
|
|
|
snprintf(line, sizeof(line), "gps baud %lu", cfg.baud);
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(line);
|
|
|
|
|
y += lineHeight;
|
2026-07-25 20:37:32 +02:00
|
|
|
snprintf(line, sizeof(line), "gps baud %lu wpm %u", cfg.baud,cfg.wpm);
|
|
|
|
|
oledPrint(line,0,16,1);
|
2026-07-25 20:30:01 +02:00
|
|
|
|
|
|
|
|
// Ligne 4
|
|
|
|
|
tft->setTextColor(lineColors[3], ST77XX_BLACK);
|
2026-07-25 20:37:32 +02:00
|
|
|
snprintf(line, sizeof(line), "loc %.4s", cfg.locator);
|
2026-07-25 20:30:01 +02:00
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(line);
|
|
|
|
|
y += lineHeight;
|
2026-07-25 20:37:32 +02:00
|
|
|
oledPrint(line,0,24,1);
|
2026-07-25 20:30:01 +02:00
|
|
|
|
|
|
|
|
// Ligne 5
|
2026-07-25 20:37:32 +02:00
|
|
|
const char* modeStr[] = { "WSPR", "RTTY", "FT8", "HELL", "CW", "IAMBIC", "ALL" };
|
2026-07-25 20:30:01 +02:00
|
|
|
tft->setTextColor(lineColors[4], ST77XX_BLACK);
|
|
|
|
|
snprintf(line, sizeof(line), "mode %s %s", modeStr[cfg.mode], cfg.call);
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(line);
|
|
|
|
|
y += lineHeight;
|
|
|
|
|
|
2026-07-25 20:37:32 +02:00
|
|
|
|
2026-07-25 20:30:01 +02:00
|
|
|
// Ligne 6
|
|
|
|
|
tft->setTextColor(lineColors[5], ST77XX_BLACK);
|
|
|
|
|
snprintf(line, sizeof(line), "wpm %u nmea %s",
|
|
|
|
|
cfg.wpm,
|
|
|
|
|
cfg.nmeaEnabled ? "on" : "off");
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(line);
|
|
|
|
|
y += lineHeight;
|
2026-07-25 20:37:32 +02:00
|
|
|
snprintf(line, sizeof(line), "nmea %s follow %s",
|
|
|
|
|
cfg.nmeaEnabled ? "on" : "off",
|
|
|
|
|
cfg.follow ? "on" : "off");
|
|
|
|
|
oledPrint(line,0,48,1);
|
|
|
|
|
|
2026-07-25 20:30:01 +02:00
|
|
|
// Ligne 7
|
|
|
|
|
tft->setTextColor(lineColors[6], ST77XX_BLACK);
|
|
|
|
|
snprintf(line, sizeof(line), "Iambic type %c follow %s",
|
|
|
|
|
cfg.bicmd,
|
|
|
|
|
cfg.follow ? "on" : "off");
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(line);
|
2026-07-25 20:37:32 +02:00
|
|
|
snprintf(line, sizeof(line), "Iambic type %c",
|
|
|
|
|
cfg.bicmd);
|
|
|
|
|
oledPrint(line,0,56,1);
|
2026-07-25 20:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Afficheur::printCharCW(char car) {
|
|
|
|
|
|
|
|
|
|
if (firstChar) {
|
|
|
|
|
// tft->fillScreen(ST77XX_BLACK);
|
|
|
|
|
tft->fillRect(
|
|
|
|
|
0,
|
|
|
|
|
CHAR_HEIGHT * 1, // début à la ligne 1
|
|
|
|
|
SCREEN_HEIGHT,
|
|
|
|
|
CHAR_HEIGHT * (MAX_LINES - 1), // hauteur des lignes 1 à 4
|
|
|
|
|
ST77XX_BLACK
|
|
|
|
|
);
|
2026-07-25 20:37:32 +02:00
|
|
|
|
2026-07-25 20:30:01 +02:00
|
|
|
tft->setTextSize(TEXT_SIZE);
|
|
|
|
|
tft->setTextWrap(false);
|
|
|
|
|
|
|
|
|
|
currentCol = 0;
|
|
|
|
|
currentLine = 1;
|
|
|
|
|
firstChar = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// retour ligne AVANT écriture
|
|
|
|
|
if (currentCol >= MAX_COLS) {
|
|
|
|
|
currentCol = 0;
|
|
|
|
|
currentLine++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// écran plein
|
|
|
|
|
if (currentLine >= MAX_LINES) {
|
|
|
|
|
//tft->fillScreen(ST77XX_BLACK);
|
2026-07-25 20:37:32 +02:00
|
|
|
|
2026-07-25 20:30:01 +02:00
|
|
|
tft->fillRect(
|
|
|
|
|
0,
|
|
|
|
|
CHAR_HEIGHT * 1, // début à la ligne 1
|
|
|
|
|
SCREEN_HEIGHT,
|
|
|
|
|
CHAR_HEIGHT * (MAX_LINES - 1), // hauteur des lignes 1 à 4
|
|
|
|
|
ST77XX_BLACK
|
|
|
|
|
);
|
2026-07-25 20:37:32 +02:00
|
|
|
|
2026-07-25 20:30:01 +02:00
|
|
|
currentLine = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int x = currentCol * CHAR_WIDTH;
|
|
|
|
|
int y = currentLine * CHAR_HEIGHT;
|
|
|
|
|
|
|
|
|
|
// 🔥 couleur selon la ligne
|
|
|
|
|
uint16_t color = lineColors[currentLine % (sizeof(lineColors) / sizeof(lineColors[0]))];
|
|
|
|
|
tft->setTextColor(color, ST77XX_BLACK);
|
|
|
|
|
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->write(car);
|
|
|
|
|
|
|
|
|
|
currentCol++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Afficheur::printFrequency(uint32_t freq) {
|
|
|
|
|
|
|
|
|
|
char buf[16];
|
|
|
|
|
snprintf(buf, sizeof(buf), "%lu", freq);
|
|
|
|
|
|
|
|
|
|
uint16_t color = lineColors[0];
|
|
|
|
|
|
|
|
|
|
tft->setTextSize(TEXT_SIZE);
|
|
|
|
|
tft->setTextWrap(false);
|
|
|
|
|
tft->setTextColor(color, ST77XX_BLACK);
|
|
|
|
|
|
|
|
|
|
// position ligne 0
|
|
|
|
|
int x = 20;
|
|
|
|
|
int y = 0;
|
|
|
|
|
|
|
|
|
|
tft->setCursor(x, y);
|
|
|
|
|
tft->print(buf);
|
2026-07-25 20:37:32 +02:00
|
|
|
oledPrint(buf,10,0,1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Afficheur::oledPrint(String txt, int x , int y , int Size)
|
|
|
|
|
{
|
|
|
|
|
//oled.clearDisplay();
|
|
|
|
|
// Calculer la largeur et la hauteur du texte précédent
|
|
|
|
|
int textWidth = txt.length() * 6 * Size; // Largeur approximative (6 pixels par caractère)
|
|
|
|
|
int textHeight = 8 * Size; // Hauteur approximative (8 pixels par taille)
|
|
|
|
|
oled.fillRect(x, y, textWidth, textHeight, SSD1306_BLACK);
|
|
|
|
|
oled.setTextSize(Size); // taille du texte
|
|
|
|
|
oled.setTextColor(SSD1306_WHITE); // Couleur du texte (blanc pour OLED)
|
|
|
|
|
oled.setCursor(x, y);
|
|
|
|
|
oled.println(txt);
|
|
|
|
|
oled.display();
|
|
|
|
|
|
|
|
|
|
// Effacer l'écran
|
|
|
|
|
//oled.clearDisplay();
|
|
|
|
|
|
|
|
|
|
}
|