/*
http://adafruit.github.io/Adafruit-GFX-Library/html/class_adafruit___g_f_x.html
https://github.com/adafruit/Adafruit-GFX-Library/blob/master/fontconvert/fontconvert.c
BITMAPS
>> https://openhardwarecoza.wordpress.com/2020/04/29/how-to-convert-bitmaps-to-uint_16t-byte-arrays-for-use-with-adafruitgfx-drawrgbbitmap-keywords-bitmap-to-c-rgb565-adafruitgfx/
>> https://dotmatrixtool.com/#
>> https://javl.github.io/image2cpp/
>> https://en.radzio.dxp.pl/bitmap_converter/
TAKTISCHE ZEICHEN
>> https://taktische-zeichen.dev/
>> https://github.com/phjardas/taktische-zeichen
>> https://taktische-zeichen.org/
*/
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeSansBold12pt7b.h>
#include <Fonts/Org_01.h>
// Piktogramme (16px by 16px, row major, big endian.)
const uint8_t pic_TMO[] =
{
0xc1, 0x83, 0xe1, 0x87, 0x71, 0x8e, 0x39, 0x9c, 0x1d, 0xb8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80
};
const uint8_t pic_clock[] =
{
0x03, 0xc0, 0x0c, 0x30, 0x30, 0x8c, 0x20, 0x84, 0x40, 0x82, 0x40, 0x82, 0x80, 0x81, 0x80, 0x81, 0x8f, 0x81, 0x80, 0x01, 0x40, 0x02, 0x40, 0x02, 0x20, 0x04, 0x30, 0x0c, 0x0c, 0x30, 0x03, 0xc0
};
// DEFINES
#define DEBUG 1
#define BLACK ILI9341_BLACK
#define WHITE ILI9341_WHITE
#define RED ILI9341_RED
#define BTN_PIN 5
#define TFT_DC 2
#define TFT_CS 15
Adafruit_ILI9341 display = Adafruit_ILI9341(TFT_CS, TFT_DC);
// GLOBALE VARIABLEN
// 296 x 128
// Display Einteilung
uint16_t widthTotal, heightTotal; // Absolute Abmessungen Display
uint16_t widthHalf, heightHalf; // Halbierte Display Breite/Höhe
uint16_t frameBorder = 2; // Randabstand zu den Mittellinien
uint16_t xMid; // X-Koordinate Vertikale Trennline
uint16_t yMid; // Y-Koordinate horizontale Trennline
// Einheit
char besatzung[] = "0 / 1 / 8 =";
char besatzungGes[] = " 9";
char ort[] = "Max";
char funk[] = " 2/44/1"; //Vorangestelltes Leerzeichen ist erforderlich
char mobile[] = "+491739755780";
char numberAGT[] = "4";
char einsatzZeit[] = "0404/14:35";
char TMO[] = "WOE F1";
char beschriftung[] = "HLF10";
// FUNKTIONEN DEKLARATION
void displayBorder();
boolean crew();
void testBorder();
boolean unitRadio();
boolean addInfo();
void setup()
{
// Serielle Schnittstelle starten
Serial.begin(9600);
while (!Serial)
{
; // Warte, bis die serielle Schnittstelle verbunden ist. Wird für native USBs benötigt.
}
Serial.println("SERIAL connection established");
display.begin();
display.setRotation(1);
// Berechnung Framepoints Display
widthTotal = 296;//display.width();
heightTotal = 128;//display.height();
widthHalf = widthTotal/2;
heightHalf = heightTotal/2;
xMid = widthHalf;
yMid = heightHalf;
// ANZEIGE
display.fillScreen(BLACK);
// Bereich Kärtchen auf schwarzem Hintergrund festlegen
display.fillRect(0, 0, widthTotal, heightTotal, WHITE);
taktischeFormation(RED, 2, 4);
displayBorder();
crew();
unitRadio();
addInfo();
Serial.println("Updating Display");
}
void loop()
{
Serial.println("FINISHED");
delay(1000);
}
boolean addInfo()
{
uint16_t symbolWidth = 16;
uint16_t symbolHeight = 16;
int16_t topleftx1, toplefty1;
uint16_t tw1, th1;
uint16_t cursorx, cursory;
uint16_t hspace = (heightHalf - frameBorder - symbolHeight - symbolHeight - symbolHeight) / 2;
// ------- LINKE SEITE -------
cursorx = xMid + frameBorder;
// Unterer Punkt - LINKS
cursory = heightTotal - symbolHeight;
display.fillRect(cursorx, cursory, symbolHeight, symbolWidth, RED);
display.setFont(&Org_01);
display.getTextBounds(einsatzZeit, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setCursor(cursorx + symbolWidth + frameBorder, cursory + (symbolHeight / 2) + (th1 / 2)); // Eigentlich sollte hier noch der y-Schriftversatz "toplefty1" berücksichtigt werden. Dieser wird jedoch für die Schriftart "Org_01" falsch berechnet!?!
display.setTextColor(BLACK);
display.print(mobile);
// Mittlerer Punkt - LINKS
cursory = cursory - symbolHeight - hspace;
display.fillRect(cursorx, cursory, symbolHeight, symbolWidth, RED);
display.setFont(&Org_01);
display.getTextBounds(einsatzZeit, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setCursor(cursorx + symbolWidth + frameBorder, cursory + (symbolHeight / 2) + (th1 / 2)); // Eigentlich sollte hier noch der y-Schriftversatz "toplefty1" berücksichtigt werden. Dieser wird jedoch für die Schriftart "Org_01" falsch berechnet!?!
display.setTextColor(BLACK);
display.print(numberAGT);
// Oberer Punkt - LINKS
cursory = cursory - symbolHeight - hspace;
display.drawBitmap (cursorx, cursory, pic_clock, symbolHeight, symbolHeight, BLACK);
display.drawRect(cursorx, cursory, symbolHeight, symbolWidth, BLACK);
display.setFont(&Org_01);
display.getTextBounds(einsatzZeit, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setCursor(cursorx + symbolWidth + frameBorder, cursory + (symbolHeight / 2) + (th1 / 2)); // Eigentlich sollte hier noch der y-Schriftversatz "toplefty1" berücksichtigt werden. Dieser wird jedoch für die Schriftart "Org_01" falsch berechnet!?!
display.setTextColor(BLACK);
display.print(einsatzZeit);
// ------- RECHTE SEITE -------
cursorx = xMid + (widthHalf / 2);
// Unterer Punkt - RECHTS
cursory = heightTotal - symbolHeight;
//display.fillRect(cursorx, cursory, symbolHeight, symbolWidth, RED);
display.setFont(&Org_01);
display.getTextBounds(einsatzZeit, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setCursor(cursorx + symbolWidth + frameBorder, cursory + (symbolHeight / 2) + (th1 / 2)); // Eigentlich sollte hier noch der y-Schriftversatz "toplefty1" berücksichtigt werden. Dieser wird jedoch für die Schriftart "Org_01" falsch berechnet!?!
display.setTextColor(BLACK);
//display.print(numberAGT);
// Mittlerer Punkt - RECHTS
cursory = cursory - symbolHeight - hspace;
display.fillRect(cursorx, cursory, symbolHeight, symbolWidth, RED);
display.setFont(&Org_01);
display.getTextBounds(einsatzZeit, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setCursor(cursorx + symbolWidth + frameBorder, cursory + (symbolHeight / 2) + (th1 / 2)); // Eigentlich sollte hier noch der y-Schriftversatz "toplefty1" berücksichtigt werden. Dieser wird jedoch für die Schriftart "Org_01" falsch berechnet!?!
display.setTextColor(BLACK);
display.print(numberAGT);
// Oberer Punkt - RECHTS
cursory = cursory - symbolHeight - hspace;
display.drawBitmap (cursorx, cursory, pic_TMO, symbolHeight, symbolHeight, BLACK);
display.drawRect(cursorx, cursory, symbolHeight, symbolWidth, BLACK);
display.setFont(&Org_01);
display.getTextBounds(einsatzZeit, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setCursor(cursorx + symbolWidth + frameBorder, cursory + (symbolHeight / 2) + (th1 / 2)); // Eigentlich sollte hier noch der y-Schriftversatz "toplefty1" berücksichtigt werden. Dieser wird jedoch für die Schriftart "Org_01" falsch berechnet!?!
display.setTextColor(BLACK);
display.print(TMO);
return 1;
}
void displayBorder()
{
// Horizontale Trennlinie
display.drawFastHLine(xMid, yMid, widthHalf, BLACK);
// Vertikale Trennlinie
display.drawFastVLine(xMid, 0, heightTotal, BLACK);
}
void taktischeFormation(uint16_t color, uint8_t mobility, uint8_t formation)
{
// Grundrechteck Einheit im Verhältnis 5/3
uint16_t unitWidth = widthHalf - frameBorder;
uint16_t unitHeigth = unitWidth / 5 * 3;
// Nullpunkt Einheit (oben links)
uint16_t unitYZero = ((heightTotal - unitHeigth) / 2) + 1;
// Randstärke
uint8_t border = 2;
// Untergrund schwarz Kasten für Rand
display.fillRect(0, unitYZero, unitWidth, unitHeigth, BLACK);
// Rechteck in Farbe der Einheit
display.fillRect(border, unitYZero + border, unitWidth - border - border, unitHeigth - border - border, color);
// ----- ZEICHEN BRANDBEKÄMPFUNG ------
uint16_t x1 = unitWidth - border - ((unitHeigth - border - border) / 2) - 1;
uint16_t y1 = unitYZero + (unitHeigth / 2);
uint16_t x2 = unitWidth - border -1;
uint16_t y2 = unitYZero + border;
uint16_t x3 = x2;
uint16_t y3 = unitYZero + unitHeigth - border - 1;
// Dreieck Schwarz
display.fillTriangle(x1, y1, x2, y2, x3, y3, BLACK);
// Dreieck Rot
display.fillTriangle(x1 + border + border, y1, x2, y2 + border + border, x3, y3 - border - border, RED);
// Strich horizontal Schwarz
display.fillRect(border, y1 - border, unitWidth - border - border, border + border, BLACK);
// ----- FORMATION ------
/*
1 = Taktische Formation (taktische Einheit / taktischer Verband) Dienststelle
2 = Befehlsstelle, Führungsstelle (im Einsatz)
3 = Gebäude
4 = Fahrzeug
...
*/
int hoehe = 0;
int radius = 0;
if(formation == 4)
{
// ----- FAHRZEUG ABRUNDUNG -----
// Radius r eines Kreissegments mit Sehne s und Höhe H ergibt sich zu: r = (s^2 + 4h^2) / 8h
hoehe = unitHeigth / 6; // 1/5 der Höhe des Zeichens
radius = ((unitWidth * unitWidth) + (4* hoehe * hoehe)) / (8 * hoehe);
display.fillCircle((unitWidth / 2) - 1, hoehe + unitYZero - radius, radius, BLACK);
display.fillCircle((unitWidth / 2) - 1, hoehe + unitYZero - radius - border, radius, WHITE);
display.fillRect(unitWidth, 0, widthTotal - unitWidth, heightTotal, WHITE);
#ifdef DEBUG
Serial.println(">> DEBUG taktischeFormation");
Serial.print("Radius: ");
Serial.println(radius);
Serial.print("unitWidth: ");
Serial.println(unitWidth);
Serial.print("unitHeigth: ");
Serial.println(unitHeigth);
#endif
}
// ----- MOBILITÄT -----
/*
1 = Kraftfahrzeug, landgebunden
2 = Kraftfahrzeug, mehrspurig, geländegängig oder geländefähig
3 = Schienenfahrzeug
*/
uint16_t spacingWheel = unitWidth / 10;
uint16_t radiusWheel = unitHeigth / 9;
// Prüfung, ob Rad mit dem berechneten Radius noch auf das Display passt!
while ((unitYZero + unitHeigth + radiusWheel + radiusWheel) > heightTotal)
{
radiusWheel--;
#ifdef DEBUG
Serial.print("Reducing radiusWheel");
Serial.println(radiusWheel);
#endif
}
uint16_t yposWheel = unitYZero + unitHeigth + radiusWheel - 1;
for(int i = 0; i < border; i++)
{
if (mobility == 1 || mobility == 2 || mobility == 3)
{
display.drawCircle(spacingWheel + radiusWheel, yposWheel, radiusWheel - i, BLACK);
display.drawCircle(unitWidth - spacingWheel - radiusWheel, yposWheel, radiusWheel - i, BLACK);
}
if (mobility == 2)
{
display.drawCircle(unitWidth / 2, yposWheel, radiusWheel - i, BLACK);
}
if (mobility == 3)
{
display.drawCircle(spacingWheel + radiusWheel + radiusWheel + radiusWheel + border, yposWheel, radiusWheel - i, BLACK);
display.drawCircle(unitWidth - spacingWheel - radiusWheel - radiusWheel - radiusWheel - border, yposWheel, radiusWheel - i, BLACK);
}
}
#ifdef DEBUG
Serial.print("spacingWheel: ");
Serial.println(spacingWheel);
Serial.print("radiusWheel: ");
Serial.println(radiusWheel);
#endif
// ----- TAKTISCHE EINHEIT -----
/*
1 = Trupp
2 = Staffel
3 = Gruppe
4 = Zug
5 = Verband I
6 = Verband II
7 = Verband III
*/
uint8_t tacticleUnit = 3;
uint16_t radiusDot = (unitYZero - border - border) / 4;
if (tacticleUnit == 2)
{
display.fillCircle(unitWidth / 2, radiusDot + hoehe, radiusDot, BLACK);
}
if (tacticleUnit == 1 || tacticleUnit == 2 || tacticleUnit == 4)
{
display.fillCircle(unitWidth / 2, radiusDot + radiusDot + border + radiusDot + hoehe, radiusDot, BLACK);
}
if (tacticleUnit == 3)
{
display.fillCircle((unitWidth / 2) - border - radiusDot, radiusDot + radiusDot + border + radiusDot + hoehe, radiusDot, BLACK);
display.fillCircle((unitWidth / 2) + border + radiusDot, radiusDot + radiusDot + border + radiusDot + hoehe, radiusDot, BLACK);
}
if (tacticleUnit == 4)
{
display.fillCircle((unitWidth / 2) - radiusDot - radiusDot - border - border, radiusDot + radiusDot + border + radiusDot + hoehe, radiusDot, BLACK);
display.fillCircle((unitWidth / 2) + radiusDot + radiusDot + border + border, radiusDot + radiusDot + border + radiusDot + hoehe, radiusDot, BLACK);
}
if (tacticleUnit == 5 || tacticleUnit == 7)
{
display.fillRect(unitWidth / 2 - radiusDot, unitYZero - border - (4 * radiusDot) + hoehe, 2 * radiusDot, 4 * radiusDot, BLACK);
}
if (tacticleUnit == 6)
{
display.fillRect(unitWidth / 2 - radiusDot - radiusDot - border, unitYZero - border - (4 * radiusDot), 2 * radiusDot, 4 * radiusDot, BLACK);
display.fillRect(unitWidth / 2 + border, unitYZero - border - (4 * radiusDot) + hoehe, 2 * radiusDot, 4 * radiusDot, BLACK);
}
if (tacticleUnit == 7)
{
display.fillRect(unitWidth / 2 - radiusDot - radiusDot - radiusDot - border, unitYZero - border - (4 * radiusDot) + hoehe, 2 * radiusDot, 4 * radiusDot, BLACK);
display.fillRect(unitWidth / 2 + radiusDot + border, unitYZero - border - (4 * radiusDot) + hoehe, 2 * radiusDot, 4 * radiusDot, BLACK);
}
// ----- BESCHRIFTUNG -----
int16_t topleftx1, toplefty1;
uint16_t tw1, th1;
uint16_t cursorx, cursory;
display.setFont(&FreeSansBold9pt7b);
display.getTextBounds(beschriftung, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setCursor(border - topleftx1, unitYZero + border + hoehe - toplefty1);
display.setTextColor(WHITE);
display.print(beschriftung);
#ifdef DEBUG
display.drawRect(border, unitYZero + border + hoehe, tw1, th1, BLACK);
#endif
#ifdef DEBUG
Serial.print("topleftx1: ");
Serial.println(topleftx1);
Serial.print("toplefty1: ");
Serial.println(toplefty1);
Serial.print("tw1: ");
Serial.println(tw1);
Serial.print("th1: ");
Serial.println(th1);
#endif
}
boolean crew()
{
int16_t topleftx1, toplefty1, topleftx2, toplefty2;
uint16_t tw1, th1, tw2, th2;
uint16_t cursorx, cursory;
uint8_t fit = 0;
const GFXfont *fontA, *fontB;
fontA = &FreeSans12pt7b;
fontB = &FreeSansBold12pt7b;
do{
display.setFont(fontA);
display.getTextBounds(besatzung, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setFont(fontB);
display.getTextBounds(besatzungGes, 0, 0, &topleftx2, &toplefty2, &tw2, &th2);
#ifdef DEBUG
Serial.println(">> DEBUG crew");
Serial.print("topleftx1: ");
Serial.println(topleftx1);
Serial.print("toplefty1: ");
Serial.println(toplefty1);
Serial.print("tw1: ");
Serial.println(tw1);
Serial.print("th1: ");
Serial.println(th1);
Serial.print("topleftx2: ");
Serial.println(topleftx2);
Serial.print("toplefty2: ");
Serial.println(toplefty2);
Serial.print("tw2: ");
Serial.println(tw2);
Serial.print("th2: ");
Serial.println(th2);
#endif
// Hier Prüfung ob tw1 + tw2 > als Breite Bildschirm,...
// >> Falls ja, reduziere Schriftgröße und führe obige Berechnung erneut durch!
if ((tw1 + tw2) > (widthHalf - frameBorder))
{
if (fit == 0)
{
fontA = &FreeSans9pt7b;
fontB = &FreeSansBold9pt7b;
fit = 2;
}
else if (fit == 2)
{
// Hier muss noch eine kleinere Schrift eingefügt werden!!!
//fontA = &FreeSans9pt7b;
//fontB = &FreeSansBold9pt7b;
fit = 3;
}
else if (fit == 3)
{
return 0;
}
Serial.println("crew - Passt nicht");
}
else
{
fit = 1;
}
}
while(fit != 1);
// Berechnung zum Ausmitteln der Schrift
cursorx = xMid + frameBorder + ((widthHalf - frameBorder) / 2) - ((tw1 + tw2) / 2) - topleftx1;
#ifdef DEBUG
display.drawRect(cursorx + topleftx1, yMid - frameBorder + toplefty1 , tw1 + tw2, th1, RED);
#endif
// Print Besatzung
display.setCursor(cursorx, yMid - frameBorder);
display.setTextColor(BLACK);
display.setFont(fontA);
display.print(besatzung);
// Print Summe der Besatzung
display.setFont(fontB);
// Korrektur X-versatz Schriftanfang
display.setCursor(display.getCursorX() - topleftx2 - 1, display.getCursorY()); // -1 bei Cursor X-Position, da Cursor nach dem Schreibbefehl automatisch +1 weitergesetzt wird
display.print(besatzungGes);
return 1;
}
boolean unitRadio()
{
int16_t topleftx1, toplefty1, topleftx2, toplefty2;
uint16_t tw1, th1, tw2, th2;
uint16_t cursorx, cursory;
uint8_t fit = 0;
const GFXfont *fontA, *fontB;
fontA = &FreeSans12pt7b;
fontB = &FreeSansBold12pt7b;
display.setFont(fontA);
display.getTextBounds(ort, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
display.setFont(fontB);
display.getTextBounds(funk, 0, 0, &topleftx2, &toplefty2, &tw2, &th2);
// Hier Prüfung ob tw1 + tw2 > als Breite Bildschirm,...
// >> Falls ja, reduziere Schriftgröße für Ort und stelle in zwei Zeilen dar!
if ((tw1 + tw2) > (widthHalf - frameBorder))
{
display.setFont(&FreeSans9pt7b);
display.getTextBounds(ort, 0, 0, &topleftx1, &toplefty1, &tw1, &th1);
if (tw1 > (widthHalf - frameBorder))
{
//Problem... weiter Schriftgröße reduzieren....
Serial.println("unitRadio - Passt nicht");
}
// Berechnung zum Ausmitteln der Schrift für Ort
cursorx = xMid + frameBorder + ((widthHalf - frameBorder) / 2) - (tw1 / 2) - topleftx1;
#ifdef DEBUG
display.drawRect(cursorx + topleftx1, 0, tw1, th1, RED);
#endif
display.setCursor(cursorx, -toplefty1);
display.setTextColor(BLACK);
display.setFont(&FreeSans9pt7b);
display.print(ort);
// Berechnung zum Ausmitteln der Schrift für Funk
display.setFont(fontB);
display.getTextBounds(&funk[1], 0, 0, &topleftx2, &toplefty2, &tw2, &th2); // Zeiger auf das zweite Speicherelement des Funkrufnamens (Löschen des initialen Leerzeichen)
cursorx = xMid + frameBorder + ((widthHalf - frameBorder) / 2) - (tw2 / 2) - topleftx2;
#ifdef DEBUG
display.drawRect(cursorx + topleftx2, th1 + frameBorder + frameBorder, tw2, th2, RED);
#endif
display.setCursor(cursorx, th1 - toplefty2 + frameBorder + frameBorder);
display.setTextColor(BLACK);
display.print(&funk[1]); // Zeiger auf das zweite Speicherelement des Funkrufnamens (Löschen des initialen Leerzeichen)
#ifdef DEBUG
Serial.println(">> DEBUG unitRadio");
Serial.print("topleftx1: ");
Serial.println(topleftx1);
Serial.print("toplefty1: ");
Serial.println(toplefty1);
Serial.print("tw1: ");
Serial.println(tw1);
Serial.print("th1: ");
Serial.println(th1);
Serial.print("topleftx2: ");
Serial.println(topleftx2);
Serial.print("toplefty2: ");
Serial.println(toplefty2);
Serial.print("tw2: ");
Serial.println(tw2);
Serial.print("th2: ");
Serial.println(th2);
#endif
return 1;
}
// Berechnung zum Ausmitteln der Schrift
cursorx = xMid + frameBorder + ((widthHalf - frameBorder) / 2) - ((tw1 + tw2) / 2) - topleftx1;
#ifdef DEBUG
display.drawRect(cursorx + topleftx1, 0, tw1 + tw2, th1, RED);
#endif
display.setCursor(cursorx, -toplefty1);
display.setTextColor(BLACK);
display.setFont(fontA);
display.print(ort);
display.setFont(fontB);
// Korrektur X-versatz Schriftanfang
display.setCursor(display.getCursorX() - topleftx2, display.getCursorY()); // -1 bei Cursor X-Position, da Cursor nach dem Schreibbefehl automatisch +1 weitergesetzt wird
display.print(funk);
#ifdef DEBUG
Serial.println(">> DEBUG unitRadio");
Serial.print("topleftx1: ");
Serial.println(topleftx1);
Serial.print("toplefty1: ");
Serial.println(toplefty1);
Serial.print("tw1: ");
Serial.println(tw1);
Serial.print("th1: ");
Serial.println(th1);
Serial.print("topleftx2: ");
Serial.println(topleftx2);
Serial.print("toplefty2: ");
Serial.println(toplefty2);
Serial.print("tw2: ");
Serial.println(tw2);
Serial.print("th2: ");
Serial.println(th2);
#endif
return 1;
}