PFD (Primary Flight Display) pour Flightgear - ESP32

Horizon artificiel +Compas, Altitude, Vitesse, réglages autopilot, ILS pour Flightgear, simulateur de vol Open Source. Puissance ESP32.
Cliquez sur une image ci-dessous pour visualiser l'album. Certaines sont commentées

1 Un aperçu en vidéo


Ceci est un test de la rapidité d'affichage avec des données calculées par des fonctions sinus... La vidéo quant-à-elle est prise en vitesse normale (!)

En réalité l'ESP32 se connecte au programme de simulation de vol FlightGear par liaison série USB. L'affichage devient alors plus calme et surtout réaliste.

2 Vue d'ensemble de cette réalisation :

L'intégration dans un boîtier maison (imprimé en 3D) est prévu, avec peut être d'autres instruments de bord.

3 Le schéma

A noter que les ports GPIO 34 et 35 ne sont pas pourvus de résistances de rappel à VCC (Pull-up) internes dans l'ESP32, d'où l'ajout des deux résistances externes de 10k.
La saisie des paramètres pour l'autopilot se fait avec deux classiques encodeurs rotatifs. Les quatre capas de 10nF sont en cms à souder au au plus près des encodeurs (hors implantation du board donc).

Il ne reste plus beaucoup de broches libres sur le module ESP32 !

4 Le programme pour l'ESP32 à compiler avec l'IDE Arduino

CODE SOURCE en C++
  1. /*
  2. PFD.ino - Primary Flight Display pour Flightgear et ESP32 - version Afficheur TFT 480x320
  3.  
  4. par Silicium628
  5.  
  6. Ce logiciel est libre et gratuit sous licence GNU GPL
  7.  
  8. */
  9.  
  10. /**---------------------------------------------------------------------------------------
  11. Pour les #includes issus de l'univers Arduino (que je ne fournis pas), il faut voir au cas par cas.
  12. (drivers d'affichage en particulier)
  13.  
  14. ---------------------------------------------------------------------------------------
  15. De petites images à placer sur la SDcard centrées sur les aérodromes proviennent de OpenStreetMap
  16. OpenStreetMap® est un ensemble de données ouvertes,
  17. disponibles sous la licence libre Open Data Commons Open Database License (ODbL)
  18. accordée par la Fondation OpenStreetMap (OSMF).
  19.  
  20. Voir ce lien pour plus de détails :
  21. https://www.openstreetmap.org/copyright
  22. --------------------------------------------------------------------------------------**/
  23.  
  24. /*=====================================================================================================
  25. CONCERNANT L'AFFICHAGE TFT : connexion :
  26.  
  27. ( Pensez à configurer le fichier User_Setup.h de la bibliothèque ~/Arduino/libraries/TFT_eSPI/ )
  28.  
  29. les lignes qui suivent ne sont q'un commentaire pour vous indiquer la config à utiliser
  30. placée ici, elle ne sont pas fonctionnelles
  31. Il FAUT modifier le fichier User_Setup.h installé par le système Arduino dans ~/Arduino/libraries/TFT_eSPI/
  32.  
  33. // ESP32 pins used for the parallel interface TFT
  34. #define TFT_CS 27 // Chip select control pin
  35. #define TFT_DC 14 // Data Command control pin - must use a pin in the range 0-31
  36. #define TFT_RST 26 // Reset pin
  37.  
  38. #define TFT_WR 12 // Write strobe control pin - must use a pin in the range 0-31
  39. #define TFT_RD 13
  40.  
  41. #define TFT_D0 16 // Must use pins in the range 0-31 for the data bus
  42. #define TFT_D1 4 // so a single register write sets/clears all bits
  43. #define TFT_D2 2 // 23
  44. #define TFT_D3 22
  45. #define TFT_D4 21
  46. #define TFT_D5 15 // 19
  47. #define TFT_D6 25 // 18
  48. #define TFT_D7 17
  49. =====================================================================================================
  50.  
  51. Notes :
  52.  
  53. - Nous choisissons Nav1 pour le VOR et Nav2 pour l'ILS
  54. - Si les data de FG ne sont pas reçues, il faut vérifier que le PFD est bien connecté sur le port USB0 (et pas USB1 ou autre...)
  55. */
  56.  
  57. String version="17.1"; // fonction Autoland + Wifi Dialogue ND
  58.  
  59. // la fonction Autoland() utilise le glide pour la descente et non plus une altitude calculée théorique
  60. // v15.2 modif du fichier hardware4.xml (nav-distance)
  61. // v15.3 revu autoland - possibilité de poser auto si localizer seul (aérodrome non équipé de glide de glide). modifs gestion voyants
  62. // v15.6 nombreuses modifs dans tous les fichiers, dont fichier FG_data.h
  63. // v16.0 prise en charge du module "SW" (boutons poussoirs) par WiFi
  64. // v16.2 prise en charge des 2 nouveaux boutons (target_speed) + le fichier "hardware4.xml" a été modifié en conséquence
  65.  
  66. // le numéro de version doit être identique à celui du ND (Navigation Display)
  67.  
  68.  
  69. /** un peu de théorie : ****************************
  70.  
  71. ALTITUDE vs HAUTEUR
  72.  
  73. Une hauteur est la distance verticale entre un aéronef et la surface qu'il survole (terre ou eau).
  74.  
  75. Pour exprimer une hauteur, il est défini les hauteurs AGL (Above Ground Level) ou ASFC (Above Surface).
  76. Il s'agit de la hauteur entre l'avion et le sol juste en dessous de sa position. Elle suit donc le relief.
  77.  
  78. Pour exprimer une hauteur au dessus de l'aérodrome, il est défini la hauteur AAL (Above Aerodrome Level).
  79. Il s'agit de la hauteur entre l'avion et le point de référence de l'aérodrome comme s'il était en dessous de la
  80. position de l'appareil (même s'il n'y est pas). Cette hauteur ne suit pas le relief.
  81.  
  82. source : https://aeroclub-narbonne.com/download/2017/04/BASE_ALT.pdf
  83. IVAO TM © ELH FLA septembre 2014
  84. je conseille de lire et relire l'ensemble de ce PDF.
  85.  
  86. *****************************************************/
  87.  
  88.  
  89. #include "PFD.h"
  90. #include <stdint.h>
  91. #include <TFT_eSPI.h> // Hardware-specific library
  92. #include "Free_Fonts.h"
  93.  
  94. #include "FS.h"
  95. #include "SD.h"
  96. #include "SPI.h"
  97.  
  98. #include "FG_data.h"
  99.  
  100. #include <WiFi.h>
  101. #include "ESPAsyncWebServer.h"
  102.  
  103.  
  104. const char* ssid = "PFD_srv";
  105. const char* password = "72r4TsJ28";
  106.  
  107. AsyncWebServer server(80); // Create AsyncWebServer object on port 80
  108.  
  109. String argument_recu1;
  110. String argument_recu2;
  111.  
  112. // TFT_eSPI TFT = TFT_eSPI(); // Configurer le fichier User_Setup.h de la bibliothèque TFT_eSPI au préalable
  113.  
  114. TFT_eSprite SPR_E = TFT_eSprite(&TFT480); // Declare Sprite object "SPR_11" with pointer to "TFT" object
  115. TFT_eSprite SPR_N = TFT_eSprite(&TFT480);
  116. TFT_eSprite SPR_O = TFT_eSprite(&TFT480);
  117. TFT_eSprite SPR_S = TFT_eSprite(&TFT480);
  118.  
  119. VOYANT voyant_L; // Localizer
  120. VOYANT voyant_G; // Glide
  121.  
  122.  
  123. //uint16_t s_width = TFT480.Get_Display_Width();
  124. //uint16_t s_heigh = TFT480.Get_Display_Height();
  125.  
  126. int16_t Ax_actu, Ay_actu;
  127. int16_t Bx_actu, By_actu;
  128.  
  129.  
  130. // COULEURS RGB565
  131. // Outil de sélection -> http://www.barth-dev.de/online/rgb565-color-picker/
  132.  
  133. #define NOIR 0x0000
  134. #define ROUGE 0xF800
  135. #define ROSE 0xFBDD
  136. #define ORANGE 0xFBC0
  137. #define JAUNE 0xFFE0
  138. #define JAUNE_PALE 0xF7F4
  139. #define VERT 0x07E0
  140. #define VERT_FONCE 0x02E2
  141. #define OLIVE 0x05A3
  142. #define CYAN 0x07FF
  143. #define BLEU_CLAIR 0x455F
  144. #define AZUR 0x1BF9
  145. #define BLEU 0x001F
  146. #define MAGENTA 0xF81F
  147. #define VIOLET1 0x781A
  148. #define VIOLET2 0xECBE
  149. #define GRIS_TRES_CLAIR 0xDEFB
  150. #define GRIS_CLAIR 0xA534
  151. #define GRIS 0x8410
  152. #define GRIS_FONCE 0x5ACB
  153. #define GRIS_TRES_FONCE 0x2124
  154.  
  155. #define GRIS_AF 0x51C5 // 0x3985
  156. #define BLANC 0xFFFF
  157.  
  158.  
  159. // AVIONIQUE : Horizon Artificiel (HA):
  160.  
  161. #define HA_CIEL 0x33FE
  162. #define HA_SOL 0xAA81 //0xDB60
  163.  
  164. //position et dimensions de l'horizon artificiel
  165.  
  166. #define HA_x0 210
  167. #define HA_y0 130
  168. #define HA_w 120 // demi largeur
  169. #define HA_h 100 // demi hauteur
  170.  
  171. #define x_autopilot 320
  172.  
  173. // Width and height of sprite
  174. #define SPR_W 14
  175. #define SPR_H 14
  176.  
  177.  
  178. /*
  179. #define taille1 100000 //480*320*2
  180. uint8_t data_ecran[taille1];
  181. */
  182.  
  183. uint32_t memo_micros = 0;
  184. uint32_t temps_ecoule;
  185. uint16_t nb_secondes=0;
  186.  
  187. String parametre; //garde en mémoire les datéess reçues par USB entre les passages dans la fonction "void acquisitions()"
  188.  
  189. uint8_t landing_light1=0;
  190. uint8_t landing_light2=0;
  191.  
  192. float roulis;
  193. float tangage;
  194.  
  195.  
  196. float altitude_GPS_float;
  197. int32_t altitude_GPS; // accepte les valeurs négatives (par exemple si QNH mal réglé avant décollage)
  198. int32_t hauteur_AAL; // (Above Aerodrome Level)
  199.  
  200. #define ASL 0
  201. #define AAL 1
  202.  
  203. uint8_t mode_affi_hauteur = ASL;
  204.  
  205. int32_t gnd_elv;
  206. int32_t vitesse;
  207. int32_t memo_vitesse;
  208. int16_t target_speed =160; // consigne de vitesse pour l'autopilot
  209. int16_t dV;
  210. int16_t acceleration;
  211. int16_t vspeed; // vitesse verticale
  212.  
  213. int16_t cap; // en degrés d'angle; direction actuelle du nez de l'avion
  214.  
  215. int16_t hdg1 = 150; // en degrés d'angle; consigne cap = Heading (HDG) Bug
  216. int16_t memo_hdg1;
  217. uint8_t refresh_hdg=0;
  218. uint8_t traiter_SW=0;
  219.  
  220. int16_t asel1 = 30; // consigne altitude 30 -> 3000ft
  221.  
  222. float rudder=0;
  223. uint8_t view_number=0;
  224.  
  225. char var_array[5]; // 4 char + zero terminal - pour envoi par WiFi
  226.  
  227. // pour VOR (sur Nav1 libellé "nav" dans FG)
  228. int32_t vor_dst; // en mètres
  229. uint32_t vor_frq;
  230. float vor_actual; // 0..35900
  231. uint16_t vor_actual_deg; // 0..359
  232.  
  233. // pour ILS (sur Nav2 libellé "nav[1]" dans FG)
  234. int32_t ils_dst;
  235. float ils_nm;
  236. uint32_t ils_frq;
  237. float ils_loc; // angle de déviation (erreur / axe de la piste) dans le plan horizontal
  238. float ils_glide; // angle de descente (pente) vue depuis la balise
  239. float ils_radial; // orientation de la piste
  240. float ils_actual; // direction de l'avion du de la piste
  241. float ils_actual_deg; // 0..359
  242.  
  243. int16_t loc=0; // localizer
  244. int16_t memo_loc=0;
  245.  
  246. int16_t gld=0; // glide
  247. int16_t memo_gld=0;
  248.  
  249. int16_t num_bali=0;
  250.  
  251. uint8_t SDcardOk=0;
  252. uint16_t data_ok;
  253. uint8_t gs_ok=0;
  254. uint8_t QNH_ok=0;
  255.  
  256. uint8_t premier_passage =1;
  257. uint8_t au_sol=1;
  258. uint8_t attente_data=1;
  259.  
  260. uint8_t autoland=0;
  261.  
  262. //uint8_t take_off_ok =0; // passe à 1 si altitude atteinte = 3000ft
  263.  
  264.  
  265. float memo_R2;
  266. int16_t memo_y0;
  267.  
  268. const int bouton1 = 36; // attention: le GPIO 36 n'a pas de R de pullup interne, il faut en câbler une (10k) au +3V3
  269. bool bouton1_etat;
  270. bool memo_bouton1_etat;
  271.  
  272. const int bouton2 = 39; // attention: le GPIO 39 n'a pas de R de pullup interne, il faut en câbler une (10k) au +3V3
  273. bool bouton2_etat;
  274. bool memo_bouton2_etat;
  275.  
  276. String switches; // boutons connectés au 3eme ESP32 (SW), reçus par WiFi
  277. uint16_t v_switches=0;
  278. uint16_t memo_v_switches=0;
  279.  
  280. String switches_ND; // boutons connectés au 2eme ESP32 (ND), reçus par WiFi
  281. uint16_t v_switches_ND=0;
  282. uint16_t memo_v_switches_ND=0;
  283.  
  284.  
  285. String potar1;
  286. int8_t v_potar1=0; // peut être négatif
  287.  
  288. // deux encodeurs rotatifs pas à pas
  289. const int rot1a = 32; // GPIO32 -> câbler une R au +3V3
  290. const int rot1b = 33; // GPIO33 -> câbler une R au +3V3
  291.  
  292. const int rot2a = 35; // GPIO35 -> câbler une R au +3V3
  293. const int rot2b = 34; // GPIO34 -> câbler une R au +3V3
  294.  
  295.  
  296. //const int led1 = 25; // GPIO15
  297.  
  298.  
  299. #define TEMPO 5 // tempo anti-rebond pour l'acquisition des encodeurs rotatifs
  300. volatile uint32_t timer1 = 0;
  301. volatile uint32_t timer2 = 0;
  302.  
  303. uint16_t compteur1;
  304.  
  305. // TFT480.setTextColor(TFT_BLACK, TFT_WHITE);
  306. // TFT480.drawLine(x0, y0, x1, y1, TFT_BLACK);
  307. // TFT480.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_GREEN);
  308. // TFT480.drawRect(5, 3, 230, 119, TFT_BLACK);
  309. // TFT480.fillRect(5, 3, 230, 119, TFT_WHITE);
  310.  
  311.  
  312. void RAZ_variables()
  313. {
  314. roulis=0;
  315. tangage=0;
  316. altitude_GPS=0;
  317. gnd_elv=0;
  318. vitesse=0;
  319. vspeed=0;
  320. cap=0;
  321. memo_hdg1=0;
  322. vor_dst=0;
  323. vor_actual=0;
  324. vor_actual_deg=0;
  325. ils_dst=0;
  326. ils_loc=0;
  327. ils_glide=0;
  328. loc=0;
  329. memo_loc=0;
  330. gld=0;
  331. memo_gld=0;
  332. }
  333.  
  334.  
  335.  
  336. /** ***********************************************************************************
  337. IMAGE.bmp
  338. ***************************************************************************************/
  339.  
  340. /**
  341. Rappel et décryptage de la fonction Color_To_565 : (elle se trouve dans le fichier LCDWIKI_KBV.cpp)
  342.  
  343. //Pass 8-bit (each) R,G,B, get back 16-bit packed color
  344.  
  345. uint16_t Color_To_565(uint8_t r, uint8_t g, uint8_t b)
  346. {
  347. return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
  348. }
  349.  
  350. 0xF8 = 11111000
  351. 0xFC = 11111100
  352.  
  353. (r & 0xF8) -> 5 bit de gauche de r (on ignore donc les 3 bits de poids faible)
  354. (g & 0xFC) -> 6 bit de gauche de g (on ignore donc les 2 bits de poids faible)
  355. (b & 0xF8) -> 5 bit de gauche de b (on ignore donc les 3 bits de poids faible)
  356.  
  357. rrrrr---
  358. gggggg--
  359. bbbbb---
  360.  
  361. après les décallages on obtient les 16 bits suivants:
  362.  
  363. rrrrr---========
  364.   gggggg--===
  365.   ===bbbbb
  366.  
  367. soit après le ou :
  368.  
  369. rrrrrggggggbbbbb
  370.  
  371. calcul de la Fonction inverse :
  372. RGB565_to_888
  373. **/
  374.  
  375.  
  376. void RGB565_to_888(uint16_t color565, uint8_t *R, uint8_t *G, uint8_t *B)
  377. {
  378. *R=(color565 & 0xFFFFF800) >> 8;
  379. *G=(color565 & 0x7E0) >> 3;
  380. *B=(color565 & 0x1F) << 3 ;
  381. }
  382.  
  383.  
  384.  
  385. /** -----------------------------------------------------------------------------------
  386. CAPTURE D'ECRAN vers SDcard
  387. /** ----------------------------------------------------------------------------------- */
  388.  
  389. void write_TFT_on_SDcard() // enregistre le fichier .bmp
  390. {
  391.  
  392. //TFT480.setTextColor(VERT, NOIR);
  393. //TFT480.drawString("CP", 450, 300);
  394.  
  395. if (SDcardOk==0) {return;}
  396.  
  397. String s1;
  398. uint16_t ys=200;
  399. TFT480.setFreeFont(FF1);
  400. TFT480.setTextColor(JAUNE, NOIR);
  401.  
  402. uint16_t x, y;
  403. uint16_t color565;
  404. uint16_t bmp_color;
  405. uint8_t R, G, B;
  406.  
  407. if( ! SD.exists("/bmp/capture2.bmp"))
  408. {
  409. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  410. TFT480.setTextColor(ROUGE, NOIR);
  411. TFT480.drawString("NO /bmp/capture2.bmp !", 100, ys);
  412. delay(300);
  413. TFT480.fillRect(100, ys, 220, 20, NOIR); // efface
  414. return;
  415. }
  416.  
  417.  
  418. File File1 = SD.open("/bmp/capture2.bmp", FILE_WRITE); // ouverture du fichier binaire (vierge) en écriture
  419. if (File1)
  420. {
  421. /*
  422. Les images en couleurs réelles BMP888 utilisent 24 bits par pixel:
  423. Il faut 3 octets pour coder chaque pixel, en respectant l'ordre de l'alternance bleu, vert et rouge.
  424. */
  425. uint16_t bmp_offset = 138;
  426. File1.seek(bmp_offset);
  427.  
  428.  
  429. TFT480.setTextColor(VERT, NOIR);;
  430.  
  431. for (y=320; y>0; y--)
  432. {
  433. for (x=0; x<480; x++)
  434. {
  435. color565=TFT480.readPixel(x, y);
  436.  
  437. RGB565_to_888(color565, &R, &G, &B);
  438.  
  439. File1.write(B); //G
  440. File1.write(G); //R
  441. File1.write(R); //B
  442. }
  443.  
  444. s1=(String) (y/10);
  445. TFT480.fillRect(450, 300, 20, 20, NOIR);
  446. TFT480.drawString(s1, 450, 300);// affi compte à rebour
  447. }
  448.  
  449. File1.close(); // referme le fichier
  450.  
  451. TFT480.fillRect(450, 300, 20, 20, NOIR); // efface le compte à rebour
  452. }
  453. }
  454.  
  455. /** ----------------------------------------------------------------------------------- */
  456.  
  457.  
  458.  
  459.  
  460. void Draw_arc_elliptique(uint16_t x0, uint16_t y0, int16_t dx, int16_t dy, float alpha1, float alpha2, uint16_t couleur) // alpha1 et alpha2 en radians
  461. {
  462. /*
  463. REMARQUES :
  464. -cette fonction permet également de dessiner un arc de cercle (si dx=dy), voire le cercle complet
  465. - dx et dy sont du type int (et pas uint) et peuvent êtres négafifs, ou nuls.
  466. -alpha1 et alpha2 sont les angles (en radians) des caps des extrémités de l'arc
  467. */
  468. uint16_t n;
  469. float i;
  470. float x,y;
  471.  
  472. i=alpha1;
  473. while(i<alpha2)
  474. {
  475. x=x0+dx*cos(i);
  476. y=y0+dy*cos(i+M_PI/2.0);
  477. TFT480.drawPixel(x,y, couleur);
  478. i+=0.01; // radians
  479. }
  480. }
  481.  
  482.  
  483. void affi_rayon1(uint16_t x0, uint16_t y0, uint16_t rayon, double angle, float pourcent, uint16_t couleur_i, bool gras)
  484. {
  485. // trace une portion de rayon de cercle depuis 100%...à pourcent du rayon du cercle
  486. // angle en radians - sens trigo
  487. float x1, x2;
  488. float y1, y2;
  489.  
  490. x1=x0+rayon* cos(angle);
  491. y1=y0-rayon* sin(angle);
  492.  
  493. x2=x0+pourcent*rayon* cos(angle);
  494. y2=y0-pourcent*rayon* sin(angle);
  495.  
  496. TFT480.drawLine(x1, y1, x2, y2, couleur_i);
  497. if (gras)
  498. {
  499. TFT480.drawLine(x1, y1-1, x2, y2-1, couleur_i);
  500. TFT480.drawLine(x1, y1+1, x2, y2+1, couleur_i);
  501. }
  502. }
  503.  
  504.  
  505.  
  506. void affi_rayon2(uint16_t x0, uint16_t y0, float r1, float r2, float angle_i, uint16_t couleur_i, bool gras)
  507. {
  508. // trace une portion de rayon de cercle entre les distances r1 et r2 du centre
  509. // angle_i en degrés décimaux - sens trigo
  510.  
  511. float angle =angle_i/57.3; // (57.3 ~ 180/pi)
  512. int16_t x1, x2;
  513. int16_t y1, y2;
  514.  
  515. x1=x0+int16_t(r1* cos(angle));
  516. y1=y0-int16_t(r1* sin(angle));
  517.  
  518. x2=x0+int16_t(r2* cos(angle));
  519. y2=y0-int16_t(r2* sin(angle));
  520.  
  521. if ((x1>0) && (x2>0) && (y1>0) && (y2>0) && (x1<480) && (x2<480) && (y1<320) && (y2<320) )
  522. {
  523. TFT480.drawLine(x1, y1, x2, y2, couleur_i);
  524.  
  525. if (gras)
  526. {
  527. TFT480.drawLine(x1, y1-1, x2, y2-1, couleur_i);
  528. TFT480.drawLine(x1, y1+1, x2, y2+1, couleur_i);
  529. }
  530. }
  531.  
  532. //TFT480.fillCircle(x2, y2, 2, ROUGE);
  533. }
  534.  
  535.  
  536.  
  537.  
  538. void affi_tiret_H(uint16_t x0, uint16_t y0, uint16_t r, double angle_i, uint16_t couleur_i)
  539. {
  540. // trace un tiret perpendiculaire à un rayon de cercle de rayon r
  541. // angle_i en degrés décimaux
  542.  
  543. float angle =angle_i/57.3; // (57.3 ~ 180/pi)
  544. float x1, x2;
  545. float y1, y2;
  546.  
  547. x1=x0+(r)* cos(angle-1);
  548. y1=y0-(r)* sin(angle-1);
  549.  
  550. x2=x0+(r)* cos(angle+1);
  551. y2=y0-(r)* sin(angle+1);
  552.  
  553. TFT480.drawLine(x1, y1, x2, y2, couleur_i);
  554. }
  555.  
  556.  
  557.  
  558. void affi_pointe(uint16_t x0, uint16_t y0, uint16_t r, double angle_i, uint16_t couleur_i)
  559. {
  560. // trace une pointe de flèche sur un cercle de rayon r
  561. // angle_i en degrés décimaux - sens trigo
  562.  
  563. float angle =angle_i/57.3; // (57.3 ~ 180/pi)
  564. int16_t x1, x2, x3;
  565. int16_t y1, y2, y3;
  566.  
  567. x1=x0+r* cos(angle); // pointe
  568. y1=y0-r* sin(angle); // pointe
  569.  
  570. x2=x0+(r-7)* cos(angle-0.1); // base A
  571. y2=y0-(r-7)* sin(angle-0.1); // base A
  572.  
  573. x3=x0+(r-7)* cos(angle+0.1); // base B
  574. y3=y0-(r-7)* sin(angle+0.1); // base B
  575.  
  576. TFT480.fillTriangle(x1, y1, x2, y2, x3, y3, couleur_i);
  577. }
  578.  
  579.  
  580. void affi_rectangle_incline(uint16_t x0, uint16_t y0, uint16_t r, double angle_i, uint16_t couleur_i)
  581. {
  582. //rectangle inscrit dans le cerce de rayon r
  583. // angle_i en degrés décimaux - sens trigo
  584.  
  585. float angle =angle_i/57.3; // (57.3 ~ 180/pi)
  586. int16_t x1, x2, x3, x4;
  587. int16_t y1, y2, y3, y4;
  588. float d_alpha=0.08; // détermine la largeur du rectangle
  589.  
  590. // point 1
  591. x1=x0+r*cos(angle-d_alpha);
  592. y1=y0+r*sin(angle-d_alpha);
  593. // point 2
  594. x2=x0+r*cos(angle+d_alpha);
  595. y2=y0+r*sin(angle+d_alpha);
  596. // point 3
  597. x3=x0+r*cos(M_PI + angle-d_alpha);
  598. y3=y0+r*sin(M_PI + angle-d_alpha);
  599. // point 4
  600. x4=x0+r*cos(M_PI + angle+d_alpha);
  601. y4=y0+r*sin(M_PI + angle+d_alpha);
  602.  
  603. TFT480.drawLine(x1, y1, x2, y2, couleur_i);
  604. TFT480.drawLine(x2, y2, x3, y3, couleur_i);
  605. TFT480.drawLine(x3, y3, x4, y4, couleur_i);
  606. TFT480.drawLine(x4, y4, x1, y1, couleur_i);
  607.  
  608. }
  609.  
  610.  
  611.  
  612. void affi_indexH(uint16_t x, uint16_t y, int8_t sens, uint16_t couleur)
  613. {
  614. // petite pointe de flèche horizontale
  615. // sens = +1 ou -1 pour orienter la pointe vers la droite ou vers la gauche
  616.  
  617. TFT480.fillTriangle(x, y-4, x, y+4, x+8*sens, y, couleur);
  618. }
  619.  
  620.  
  621.  
  622. void affi_indexV(uint16_t x, uint16_t y, int8_t sens, uint16_t couleur)
  623. {
  624. // petite pointe de flèche verticale
  625. // sens = +1 ou -1 pour orienter la pointe vers le haut ou vers le bas
  626.  
  627. TFT480.fillTriangle(x-4, y, x+4, y, x, y+8*sens, couleur);
  628. }
  629.  
  630.  
  631.  
  632. float degTOrad(float angle)
  633. {
  634. return (angle * M_PI / 180.0);
  635. }
  636.  
  637.  
  638.  
  639. void init_affi_HA()
  640. {
  641. TFT480.fillRect(HA_x0-HA_w, HA_y0-HA_h-1, 2*HA_w, HA_h+1, HA_CIEL);
  642. TFT480.fillRect(HA_x0-HA_w, HA_y0-HA_h + HA_h, 2*HA_w, HA_h, HA_SOL);
  643.  
  644. }
  645.  
  646.  
  647.  
  648.  
  649. void dessine_avion()
  650. {
  651. // aile gauche
  652. TFT480.fillRect(HA_x0-102, HA_y0-3, 60, 10, BLANC); //H contour en blanc
  653. TFT480.fillRect(HA_x0-42, HA_y0-3, 10, 19, BLANC); //V
  654.  
  655. TFT480.fillRect(HA_x0-100, HA_y0-1, 60, 5, NOIR); //H
  656. TFT480.fillRect(HA_x0-40, HA_y0-1, 5, 15, NOIR); //V
  657.  
  658.  
  659. // aile droite
  660. TFT480.fillRect(HA_x0+28, HA_y0-3, 64, 10, BLANC); //H contour en blanc
  661. TFT480.fillRect(HA_x0+28, HA_y0-3, 10, 19, BLANC); //V
  662.  
  663. TFT480.fillRect(HA_x0+30, HA_y0-1, 60, 5, NOIR); //H
  664. TFT480.fillRect(HA_x0+30, HA_y0-1, 5, 15, NOIR); //V
  665.  
  666. //carré blanc au centre
  667.  
  668. TFT480.fillRect(HA_x0-4, HA_y0-3, 8, 2, BLANC);
  669. TFT480.fillRect(HA_x0-4, HA_y0-3, 2, 8, BLANC);
  670.  
  671. TFT480.fillRect(HA_x0-4, HA_y0+3, 10, 2, BLANC);
  672. TFT480.fillRect(HA_x0+4, HA_y0-3, 2, 8, BLANC);
  673.  
  674. //affi_dst_NAV();
  675.  
  676. }
  677.  
  678.  
  679.  
  680. void lign_sep(uint16_t Ax, uint16_t Ay, uint16_t Bx, uint16_t By)
  681. {
  682. // actualise la ligne de séparation ciel-sol
  683.  
  684. TFT480.drawLine(Ax, Ay-1, Bx, By-1, HA_CIEL);
  685. TFT480.drawLine(Ax, Ay, Bx, By, BLANC);
  686. TFT480.drawLine(Ax, Ay+1, Bx, By+1, HA_SOL);
  687. }
  688.  
  689.  
  690.  
  691. void arrondissement_coins()
  692. {
  693.  
  694. // fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color);
  695.  
  696. //HG
  697. TFT480.fillTriangle(
  698. HA_x0-HA_w, HA_y0-HA_h-1,
  699. HA_x0-HA_w, HA_y0-HA_h+20,
  700. HA_x0-HA_w+20, HA_y0-HA_h-1,
  701. NOIR);
  702.  
  703.  
  704. //----------------------------------------------
  705. //HD
  706. TFT480.fillTriangle(
  707. HA_x0+HA_w, HA_y0-HA_h-1,
  708. HA_x0+HA_w, HA_y0-HA_h+20,
  709. HA_x0+HA_w-20, HA_y0-HA_h-1,
  710. NOIR);
  711.  
  712.  
  713.  
  714. //----------------------------------------------
  715. //BG
  716. TFT480.fillTriangle(
  717. HA_x0-HA_w, HA_y0+HA_h+1,
  718. HA_x0-HA_w, HA_y0+HA_h-20,
  719. HA_x0-HA_w+20, HA_y0+HA_h+1,
  720. NOIR);
  721.  
  722. //----------------------------------------------
  723. //BD
  724. TFT480.fillTriangle(
  725. HA_x0+HA_w, HA_y0+HA_h+1,
  726. HA_x0+HA_w, HA_y0+HA_h-20,
  727. HA_x0+HA_w-20, HA_y0+HA_h+1,
  728. NOIR);
  729.  
  730. }
  731.  
  732.  
  733.  
  734. void affi_HA() // Horizon Artificiel
  735. {
  736. String s1;
  737.  
  738. ////String s1=(String) roulis;
  739. ////TFT480.drawString(s1, 400, 20);
  740.  
  741.  
  742. // pivot
  743. int16_t x0=0;
  744. int16_t y0=0;
  745.  
  746. //points d'intersection avec le bord du carré
  747. int16_t Ax, Ay; // sur le bord gauche
  748. int16_t Bx, By; // sur le bord droit
  749. // Le dessin consistera à tracer des segments colorés entre les points A et B
  750.  
  751.  
  752. // roulis -> [-90..+90]
  753.  
  754. // normalisation de la valeur R2 -> toujours >0
  755. float R2 = -1*roulis;
  756. if (R2<0) {R2+=360;} // ce qui est un angle identique, de valeur positive (sens trigo)
  757.  
  758. // le pivot reste centré horizontalement mais se déplace verticalement en fonction du tangage
  759. y0 += 2*tangage;
  760.  
  761. //calcul & memorisation de ces deux facteurs, ce qui évitera 2 calculs de tangente à chaque passage dan la fonction
  762. float tgt_moins = tan(degTOrad(90-R2));
  763. float tgt_plus = tan(degTOrad(90+R2));
  764.  
  765. //-----------------------------------------------------------------------------
  766. // CALCUL COTE DROIT (point B)
  767.  
  768. // calcul du point B d'intersection
  769. Bx=HA_w;
  770. By=y0 + HA_w*tan(degTOrad(R2));
  771.  
  772. //test si le point d'intersection se trouve plus haut que le haut du carré :
  773.  
  774. if(By>HA_h)
  775. {
  776. By=HA_h;
  777. Bx = x0 + (HA_h-y0)*tgt_moins;
  778. }
  779.  
  780. if(By< -HA_h)
  781. {
  782. By= -HA_h;
  783. Bx = x0 + (HA_h+y0)*tgt_plus;
  784. }
  785. //-----------------------------------------------------------------------------
  786. // CALCUL COTE GAUCHE (point A)
  787.  
  788. Ax=-HA_w;
  789. Ay=y0 - HA_w*tan(degTOrad(R2));
  790.  
  791. if(Ay> HA_h)
  792. {
  793. Ay= HA_h;
  794. Ax = x0 + (HA_h-y0)*tgt_moins;
  795. }
  796.  
  797. if(Ay< -HA_h)
  798. {
  799. Ay= -HA_h;
  800. Ax = x0 + (HA_h+y0)*tgt_plus;
  801. }
  802.  
  803.  
  804. //-----------------------------------------------------------------------------
  805. // positionnement de l'ensemble sur l'écran
  806.  
  807. Ax += HA_x0;
  808. Ay += HA_y0;
  809.  
  810. Bx += HA_x0;
  811. By += HA_y0;
  812.  
  813. // pour éviter un tracé hors cadre au premier passage :
  814. if (premier_passage == 1)
  815. {
  816. Ax_actu = Ax;
  817. Ay_actu = Ay;
  818.  
  819. Bx_actu = Bx;
  820. By_actu = By;
  821. premier_passage=0;
  822. }
  823.  
  824.  
  825. //-----------------------------------------------------------------------------
  826. // ligne "verticale" d'inclinaison (tangage)
  827.  
  828. affi_rayon2(HA_x0, HA_y0, 85, -memo_y0, 90-memo_R2, HA_CIEL, false); // efface partie supérieure
  829. affi_rayon2(HA_x0, HA_y0, 85, -y0, 90-R2, BLANC, false); // retrace ligne partie supérieure
  830.  
  831. affi_rayon2(HA_x0, HA_y0, -85,-memo_y0, 90-memo_R2, HA_SOL, false); // efface partie inférieure
  832. affi_rayon2(HA_x0, HA_y0, -85,-y0, 90-R2, VERT, false); // retrace ligne partie inférieure
  833.  
  834. affi_pointe(HA_x0, HA_y0, 85, 90-memo_R2, HA_CIEL); // efface
  835. affi_pointe(HA_x0, HA_y0, 85, 90-R2, BLANC); // retrace
  836.  
  837.  
  838. affi_glide();
  839. affi_localizer();
  840.  
  841. // graduation fixe
  842. TFT480.setFreeFont(FF1);
  843. TFT480.setTextColor(BLANC, GRIS_AF);
  844. TFT480.drawString("30", HA_x0-70, HA_y0-98);
  845. TFT480.drawString("60", HA_x0-120, HA_y0-55);
  846.  
  847. TFT480.drawString("30", HA_x0+60, HA_y0-98);
  848. TFT480.drawString("60", HA_x0+100, HA_y0-55);
  849.  
  850. //-----------------------------------------------------------------------------
  851. // animation de la ligne de séparation horizontale
  852.  
  853. while ((Bx_actu != Bx) || (By_actu != By) || (Ax_actu != Ax) || (Ay_actu != Ay))
  854. {
  855. // déplacements successifs de 1 pixel de chaque extrémités de la ligne
  856.  
  857. //TFT480.drawLine(Bx, By, x2, y2, BLANC);
  858.  
  859. if (Bx_actu < Bx) { Bx_actu++; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  860. if (Bx_actu > Bx) { Bx_actu--; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  861.  
  862. if (Ax_actu < Ax) { Ax_actu++; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  863. if (Ax_actu > Ax) { Ax_actu--; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  864.  
  865. if (By_actu < By) { By_actu++; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  866. if (By_actu > By) { By_actu--; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  867.  
  868. if (Ay_actu < Ay) { Ay_actu++; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  869. if (Ay_actu > Ay) { Ay_actu--; lign_sep(Ax_actu, Ay_actu, Bx_actu, By_actu); }
  870.  
  871. }
  872.  
  873.  
  874. // graduation roulis qui se déplace angulairement avec la ligne de tangage
  875. for (int8_t n=0; n<4; n++)
  876. {
  877. Draw_arc_elliptique(HA_x0, HA_y0, 20*n, 20*n, degTOrad(80-memo_R2+n), degTOrad(100-memo_R2-n), HA_CIEL); // efface bas
  878. Draw_arc_elliptique(HA_x0, HA_y0, 20*n, 20*n, degTOrad(80-R2+n), degTOrad(100-R2-n), BLANC); // trace bas
  879.  
  880. Draw_arc_elliptique(HA_x0, HA_y0, 20*n, 20*n, degTOrad(260-memo_R2+n), degTOrad(280-memo_R2-n), HA_SOL); // efface haut
  881. Draw_arc_elliptique(HA_x0, HA_y0, 20*n, 20*n, degTOrad(260-R2+n), degTOrad(280-R2-n), BLANC); // trace haut
  882. }
  883.  
  884. memo_R2 = R2;
  885. memo_y0 = y0;
  886.  
  887.  
  888.  
  889.  
  890. //-----------------------------------------------------------------------------
  891. arrondissement_coins();
  892.  
  893. //affi_frq_NAV1();
  894. affi_dst_NAV1();
  895. affi_dst_NAV2();
  896.  
  897. if(autoland == 1)
  898. {
  899. TFT480.setTextColor(NOIR, VERT);
  900. TFT480.setFreeFont(FF1);
  901. TFT480.drawString("AUTOLAND", HA_x0-40, HA_y0+80);
  902.  
  903. }
  904.  
  905. // affi_alti_NAV2();
  906. }
  907.  
  908.  
  909.  
  910. void affi_acceleration()
  911. {
  912. // POUR TEST **********
  913. ////String s2= (String) acceleration;
  914. ////TFT480.fillRect(100, 50, 200, 20, TFT_BLACK);
  915. ////TFT480.setFreeFont(FF5);
  916. ////TFT480.setTextColor(BLANC, NOIR);
  917. ////TFT480.drawString("Acceleration=", 100, 50);
  918. ////TFT480.drawString(s2, 250, 50);
  919. // ********************
  920.  
  921. //barres verticales colorées juste à droite de la vitesse indiquant sa variation
  922. uint16_t x0=60;
  923. uint16_t Y_zero=162;
  924.  
  925. int16_t dy=0;
  926.  
  927. //"fleche" haute
  928. TFT480.fillRect(x0, 40, 8, Y_zero, GRIS_TRES_FONCE); // efface haut
  929. if (acceleration > 1)
  930. {
  931. dy= acceleration;
  932.  
  933. TFT480.fillRect(x0, Y_zero-dy, 8, dy, VERT); // fleche
  934. }
  935.  
  936.  
  937. //"fleche" basse
  938. TFT480.fillRect(x0, Y_zero, 8, 150, GRIS_TRES_FONCE); // efface bas
  939. if (acceleration < -1)
  940. {
  941. dy= -acceleration;
  942.  
  943. TFT480.fillRect(x0, Y_zero, 8, dy, JAUNE); // fleche
  944. }
  945.  
  946. TFT480.fillRect(x0, Y_zero, 10, 2, BLANC); // tiret horizontal blanc
  947.  
  948. TFT480.fillRect(x0, 310, 8, 20, NOIR);
  949.  
  950. }
  951.  
  952.  
  953. void bride(int16_t *valeur)
  954. {
  955. int16_t y_min =40;
  956. int16_t y_max =310;
  957. if (*valeur<y_min) {*valeur=y_min;}
  958. if (*valeur>y_max) {*valeur=y_max;}
  959. }
  960.  
  961.  
  962. void affi_switches()
  963. {
  964. TFT480.setTextFont(1);
  965. TFT480.setTextColor(GRIS);
  966.  
  967. TFT480.fillRect(440, 0, 30, 10, NOIR); // efface le nombre précédemment affiché
  968. TFT480.drawString(switches, 440, 0);
  969.  
  970. TFT480.fillRect(440, 10, 30, 10, NOIR); // efface le nombre précédemment affiché
  971. TFT480.drawString(switches_ND, 440, 10);
  972.  
  973.  
  974. }
  975.  
  976.  
  977. void affi_potars()
  978. {
  979. TFT480.fillRect(440, 20, 30, 10, NOIR); // efface le nombre précédemment affiché
  980. TFT480.setTextColor(ORANGE);
  981. TFT480.drawString(potar1, 440, 20);
  982. }
  983.  
  984.  
  985.  
  986. void affi_vitesse()
  987. {
  988. uint16_t x1;
  989. String s1;
  990.  
  991. int16_t y_min =40;
  992. int16_t y_max =300;
  993.  
  994. TFT480.setTextColor(BLANC); // Background is not defined so it is transparent
  995.  
  996. //---------------------------------------------------------------------------------------
  997. //bande verticale multicolore
  998.  
  999. #define vitesse_sol 40
  1000. int16_t vitesse_mini1 =90;
  1001. int16_t vitesse_mini2 =130;
  1002. int16_t vitesse_maxi1 =200;
  1003. int16_t vitesse_maxi2 =280;
  1004.  
  1005.  
  1006.  
  1007. //calcul de la position des limites entre les différentes couleurs verticales
  1008.  
  1009. int16_t d1, d2, d3, d4, d5;
  1010.  
  1011. d1=(int16_t)(100 + 3.2*((vitesse - vitesse_sol)));
  1012. d2=(int16_t)(100 + 3.2*((vitesse - vitesse_mini1)));
  1013. d3=(int16_t)(100 + 3.2*((vitesse - vitesse_mini2)));
  1014. d4=(int16_t)(100 + 3.2*((vitesse - vitesse_maxi1)));
  1015. d5=(int16_t)(100 + 3.2*((vitesse - vitesse_maxi2)));
  1016.  
  1017. bride(&d1);
  1018. bride(&d2);
  1019. bride(&d3);
  1020. bride(&d4);
  1021. bride(&d5);
  1022.  
  1023. int16_t h1, h2, h3, h4, h5;
  1024.  
  1025. h1 = y_max-(int16_t)d1;
  1026. h2 = d1-d2;
  1027. h3 = d2-d3;
  1028. h4 = d3-d4;
  1029. h5 = d4-d5;
  1030.  
  1031. TFT480.fillRect(50, 40, 6, (int16_t)d5, ORANGE);
  1032. TFT480.fillRect(50, d5, 6, h5, JAUNE);
  1033. TFT480.fillRect(50, d4, 6, h4, VERT);
  1034. TFT480.fillRect(50, d3, 6, h3, ORANGE);
  1035. TFT480.fillRect(50, d2, 6, h2, ROUGE);
  1036. TFT480.fillRect(50, d1, 6, 300-(int16_t)d1, GRIS);
  1037.  
  1038. TFT480.fillRect(50, 300, 6, 20, NOIR);
  1039.  
  1040. //---------------------------------------------------------------------------------------
  1041. //échelle verticale graduée glissante
  1042.  
  1043. uint16_t y0;
  1044.  
  1045. int16_t vit1;
  1046. float d6;
  1047.  
  1048. TFT480.setFreeFont(FF1);
  1049.  
  1050. y0=3.2*(vitesse%10);
  1051.  
  1052. TFT480.fillRect(0, y_min, 50, y_max-30, GRIS_AF); // bande verticale à gauche
  1053. for(int n=0; n<10; n++)
  1054. {
  1055. d6 =2+y0+32.0*n; // 24 pixels verticalement entre chaque trait -> 10*24 = 240px (hauteur de l'affiur)
  1056. {
  1057. if ( (d6>y_min) && (d6<y_max-10) && (vit1>=0) && (vit1<1000) )
  1058. {
  1059. TFT480.fillRect(45, (int16_t)d6, 10, 2, BLANC); // petits tirets horizontaux
  1060. }
  1061.  
  1062. vit1 = vitesse -10*(n-5);
  1063. vit1 /= 10;
  1064. vit1 *= 10;
  1065. s1=(String) vit1;
  1066.  
  1067. if ( (d6>y_min) && (d6<y_max-10) && (vit1>=0) && (vit1<1000) )
  1068. {
  1069. TFT480.setTextColor(BLANC, GRIS_AF);
  1070. //TFT480.drawString(" ", 9, d6);
  1071. x1=0;
  1072. if(vit1<100){x1=7;} // pour affichage centré
  1073. if(vit1<10){x1=14;}
  1074. if (vit1>=10)
  1075. {
  1076. TFT480.drawString(s1, x1, (uint16_t)d6-5); // Graduation (tous les 20kts)
  1077. }
  1078. }
  1079. }
  1080. }
  1081. TFT480.fillRect(0, 38, 68, 2, NOIR); // efface ; BLEU pour test
  1082.  
  1083. //---------------------------------------------------------------------------------------
  1084. // affichage de la valeur principale
  1085.  
  1086. uint16_t VP_y0 = 150;
  1087.  
  1088. TFT480.setTextColor(BLANC, NOIR);
  1089. TFT480.setFreeFont(FF18);
  1090. s1=(String)vitesse;
  1091.  
  1092. TFT480.fillRect(3, VP_y0, 42, 26, NOIR); // efface le nombre précédemment affiché (pour le cas où on passe de trois à deux chiffres)
  1093.  
  1094. if ((vitesse>=0) && (vitesse <1000))
  1095. {
  1096. x1=3;
  1097. if(vitesse<100){x1=10;} // pour affichage centré
  1098. if(vitesse<10){x1=20;}
  1099. TFT480.drawString(s1, x1, VP_y0+3); // affi le nombre
  1100. } // affi en gros à mi-hauteur de l'écran
  1101. else
  1102. { TFT480.fillRect(3, VP_y0, 42, 26, GRIS); }
  1103.  
  1104. TFT480.drawRoundRect(1, VP_y0-1, 45, 28, 5, BLANC); // encadrement de la valeur centrale affichée
  1105.  
  1106. TFT480.fillTriangle(45, VP_y0+7, 45, VP_y0+17, 55, VP_y0+12, NOIR); // petit triangle (curseur) noir
  1107. }
  1108.  
  1109.  
  1110.  
  1111. void affi_asel()
  1112. {
  1113. // consigne ALTITUDE de l'autopilot
  1114. // ( chiffres en rose en haut à droite )
  1115.  
  1116. if(asel1 >=0)
  1117. {
  1118. String s2 =(String)(asel1*100);
  1119. TFT480.setTextColor(ROSE, NOIR);
  1120. TFT480.setFreeFont(FF5);
  1121. uint16_t x1 =340;;
  1122. TFT480.fillRect(x1+7, 0, 70, 20, NOIR); // efface
  1123. if(asel1<10000){x1+=7;}
  1124. if(asel1<1000){x1+=7;}
  1125. if(asel1<100){x1+=7;} // pour affichage centré
  1126. if(asel1<10){x1+=7;}
  1127.  
  1128. TFT480.drawString(s2, x1, 5);
  1129. }
  1130. }
  1131.  
  1132.  
  1133. void affi_target_speed()
  1134. {
  1135. // consigne de vitesse de l'autopilot
  1136. // ( chiffres en rose en haut à gauche )
  1137.  
  1138. String s2 =(String)(target_speed);
  1139. TFT480.setTextColor(ROSE, NOIR);
  1140. TFT480.setFreeFont(FF5);
  1141. uint16_t x1=0;
  1142. TFT480.fillRect(x1+7, 20, 60, 15, NOIR); // efface
  1143. if(asel1<10000){x1+=7;}
  1144. if(asel1<1000){x1+=7;}
  1145. if(asel1<100){x1+=7;} // pour affichage centré
  1146. if(asel1<10){x1+=7;}
  1147.  
  1148. TFT480.drawString(s2, x1, 20);
  1149. }
  1150.  
  1151.  
  1152.  
  1153.  
  1154. void affi_vt_verticale()
  1155. {
  1156. // affichage analogique sur la droite de l'écran
  1157.  
  1158. uint16_t x0=435;
  1159. uint16_t y0=165;
  1160.  
  1161. float y1;
  1162.  
  1163. uint16_t x1;
  1164. String s1;
  1165.  
  1166. TFT480.fillRect(x0, y0-90, 45, 180, GRIS_AF); // barre grise
  1167. TFT480.fillRect(x0, y0, 25, 2, BLEU_CLAIR); // centre
  1168.  
  1169. // ------------------------
  1170. // graduations sur un arc vertical
  1171. TFT480.setFreeFont(FF1);
  1172.  
  1173. TFT480.setTextColor(BLANC, NOIR);
  1174. TFT480.drawString("ft/mn", x0-8, y0+125);
  1175.  
  1176.  
  1177. TFT480.setTextColor(BLANC, GRIS_AF);
  1178.  
  1179.  
  1180.  
  1181. float angle;
  1182. for(uint8_t n=0; n<7; n++ )
  1183. {
  1184. angle =135+ n*15; // 1 tiret tous les 15 degrés
  1185. affi_rayon1(HA_x0+340, y0, 110, degTOrad(angle), 0.9, BLANC, false); // tirets de graduation
  1186. }
  1187.  
  1188.  
  1189. TFT480.drawString("3", x0+9, y0-90);
  1190. TFT480.drawString("2", x0-3, y0-65);
  1191. TFT480.drawString("1", x0-8, y0-35);
  1192. TFT480.drawString("0", x0-3, y0-5 + 0);
  1193. TFT480.drawString("1", x0-8, y0+25);
  1194. TFT480.drawString("2", x0-3, y0+50);
  1195. TFT480.drawString("3", x0+9, y0+75);
  1196.  
  1197. // ------------------------
  1198. // aiguille à droite de l'écran
  1199. float angle2;
  1200.  
  1201. TFT480.setFreeFont(FF1);
  1202. s1=(String) (vspeed*60);
  1203.  
  1204. angle2 = 180.0 - vspeed *0.92;
  1205.  
  1206. TFT480.fillRect(x0-10, y0-110, 55, 15, GRIS_TRES_FONCE); // efface haut
  1207. TFT480.fillRect(x0-10, y0+105, 55, 15, GRIS_TRES_FONCE); // efface bas
  1208.  
  1209. if ((vspeed > -50) && (vspeed < 50))
  1210. {
  1211. affi_rayon1(HA_x0+330, y0, 100, degTOrad(angle2), 0.7, JAUNE, true);
  1212.  
  1213. TFT480.setTextColor(JAUNE, NOIR);
  1214. }
  1215. else if (vspeed > 50)
  1216. {
  1217. affi_rayon1(HA_x0+330, y0, 110, degTOrad(132), 0.7, JAUNE, true);
  1218. TFT480.setTextColor(JAUNE, NOIR);
  1219.  
  1220. TFT480.drawString(s1, x0-10, y0-110);
  1221. }
  1222. else if (vspeed < -50)
  1223. {
  1224. affi_rayon1(HA_x0+330, y0, 110, degTOrad(228), 0.7, JAUNE, true);
  1225. TFT480.setTextColor(JAUNE, NOIR);
  1226.  
  1227. TFT480.drawString(s1, x0-10, y0+105);
  1228. }
  1229.  
  1230.  
  1231. // affichage digital de la valeur
  1232.  
  1233.  
  1234. /*
  1235. // = vitesse ascensionnelle, sous forme de barres verticales vertes, à droite, près de l'echelle d'altitude
  1236. uint16_t x0=405;
  1237. uint16_t y0=40;
  1238.  
  1239. int16_t dy=0;
  1240.  
  1241. //fleche haute
  1242. TFT480.fillRect(x0, 0, 10, 140, GRIS_FONCE); // efface haut
  1243. if (vspeed > 1)
  1244. {
  1245. dy= vspeed;
  1246.  
  1247. TFT480.fillRect(x0, y0+100-dy, 10, dy, VERT); // fleche
  1248. }
  1249.  
  1250.  
  1251. //fleche basse
  1252. TFT480.fillRect(x0, y0+150, 10, 135, GRIS_FONCE); // efface bas
  1253. if (vspeed < -1)
  1254. {
  1255. dy= -vspeed;
  1256.  
  1257. TFT480.fillRect(x0, y0+150, 10, dy, VERT); // fleche
  1258. }
  1259. */
  1260.  
  1261. }
  1262.  
  1263.  
  1264.  
  1265.  
  1266. void affi_cap()
  1267. {
  1268. // cercle tournant de CAP gradué en bas au centre de l'écran
  1269. // Les lettres 'N' 'S' 'E' 'O' pour Nord Sud Est Ouset sont initialisées sous forme de sprites dans la fonction setup()
  1270.  
  1271. uint16_t x02 = 200;
  1272. uint16_t y02 = 350;
  1273. float angle; // en radians
  1274. //float cap_RD; // en radians (le cap fourni par FG étant en degrés d'angle)
  1275. uint16_t x_spr;
  1276. uint16_t y_spr;
  1277.  
  1278. uint16_t x_hdg;
  1279. uint16_t y_hdg;
  1280.  
  1281. uint8_t R =70;
  1282. uint8_t R2 =R-6;
  1283. /**
  1284. 360° =2 pi rad
  1285. 1° = 2 pi/360 rad = pi/180 rad
  1286. **/
  1287.  
  1288. TFT480.fillCircle(x02,y02, R, GRIS_AF);
  1289.  
  1290. for(uint8_t n=0; n<24; n++ )
  1291. {
  1292. angle = cap+15 + n*15; // 1 tiret tous les 15 degrés
  1293. affi_rayon1(x02, y02, (R-5), degTOrad(angle), 0.9, BLANC, false); // tirets de graduation
  1294. }
  1295. x_hdg = x02 + R2*cos(degTOrad(hdg1-90-cap));
  1296. y_hdg = y02 + R2*sin(degTOrad(hdg1-90-cap));
  1297.  
  1298. TFT480.drawLine(x02, y02, x_hdg, y_hdg, VERT);
  1299. TFT480.drawCircle(x_hdg, y_hdg, 5, VERT); // rond vert sur le cercle = consigne de cap de l'autopilot
  1300.  
  1301. x_spr = x02+R2 * cos(degTOrad(angle));
  1302. y_spr = y02-R2 * sin(degTOrad(angle));
  1303. TFT480.setPivot(x_spr, y_spr);
  1304. SPR_E.pushRotated(-cap+90, TFT_BLACK); // Plot rotated Sprite, black = transparent
  1305.  
  1306. x_spr = x02+R2* cos(degTOrad(angle+90));
  1307. y_spr = y02-R2 * sin(degTOrad(angle+90));
  1308. TFT480.setPivot(x_spr, y_spr);
  1309. SPR_N.pushRotated(-cap, TFT_BLACK);
  1310.  
  1311. x_spr = x02+R2 * cos(degTOrad(angle+180));
  1312. y_spr = y02-R2 * sin(degTOrad(angle+180));
  1313. TFT480.setPivot(x_spr, y_spr);
  1314. SPR_O.pushRotated(-cap-90, TFT_BLACK);
  1315.  
  1316. x_spr = x02+R2 * cos(degTOrad(angle-90));
  1317. y_spr = y02-R2 * sin(degTOrad(angle-90));
  1318. TFT480.setPivot(x_spr, y_spr);
  1319. SPR_S.pushRotated(-cap, TFT_BLACK);
  1320.  
  1321.  
  1322. // petite "maison" dans le cercle (valeur du cap)
  1323.  
  1324. #define a 180 // x général
  1325. #define b a+20
  1326. #define c b+20
  1327. #define d 288 // y général
  1328. #define e d+10
  1329. #define f e+20
  1330.  
  1331. TFT480.drawLine(a, f, c, f, BLANC); // sol
  1332. TFT480.drawLine(a, f, a, e, BLANC); // mur de gauche
  1333. TFT480.drawLine(c, f, c, e, BLANC); // mur de droite
  1334. TFT480.drawLine(a, e, b, d, BLANC); // toit pente gauche
  1335. TFT480.drawLine(c, e, b, d, BLANC); // toit pente droite
  1336.  
  1337.  
  1338. // affi la valeur
  1339. String s1;
  1340. uint16_t x0 = a+2;
  1341. uint16_t y0 = e;
  1342.  
  1343. uint16_t x1= x0;
  1344. if(cap<100){x1+=5;} // pour affichage centré
  1345. if(cap<10){x1+=5;}
  1346.  
  1347. s1=(String) cap;
  1348.  
  1349. TFT480.fillRect(x0, y0, 35, 20, NOIR); // efface le nombre précédemment affiché
  1350. TFT480.setTextColor(BLANC, NOIR);
  1351. TFT480.setFreeFont(FM9);
  1352. TFT480.drawString(s1, x1, y0);
  1353.  
  1354.  
  1355. }
  1356.  
  1357.  
  1358.  
  1359. void affi_hauteur()
  1360. {
  1361. /**
  1362. Pour exprimer une hauteur au dessus de l'aérodrome, il est définie la hauteur AAL (Above Aerodrome Level).Il
  1363. s'agit de la hauteur entre l'avion et le point de référence de l'aérodrome comme s'il était en dessous de la
  1364. position de l'appareil (même s'il n'y est pas). Cette hauteur ne suit pas le relief.
  1365. On la calculera ici en retranchant [l'altitude de l'aéroport sélectionné] à [l'altitude GPS].
  1366.  
  1367. En conséquense, il faut impérativement penser à sélectionner dans le module SD le bon aérodrome, celui d'où l'on décolle,
  1368. puis en cas de voyage, celui où l'on va se poser (se qui renseignera son altitude) sinon l'affichage sera faux.
  1369.  
  1370. par exemple si l'on choisit "Montpellier" en étant à Clermont-Ferrand, l'erreur sera de 1089 ft
  1371.  
  1372. Les altitudes des aérodromes sont enregistées ici dans le fichier FG_data.h
  1373. */
  1374.  
  1375. String s1;
  1376. uint16_t x0 =365;
  1377. //---------------------------------------------------------------------------------------
  1378. //échelle verticale graduée glissante
  1379.  
  1380. uint16_t x1;
  1381. uint16_t y0;
  1382. uint16_t hauteur;
  1383. int16_t alt1;
  1384. float d5;
  1385.  
  1386. if (mode_affi_hauteur == AAL) {hauteur = hauteur_AAL;}
  1387. if (mode_affi_hauteur == ASL) {hauteur = altitude_GPS;}
  1388.  
  1389. TFT480.setFreeFont(FF1);
  1390.  
  1391.  
  1392. y0=3.2*(hauteur_AAL%10);
  1393.  
  1394. TFT480.fillRect(x0, 20, 60, 319, GRIS_AF); //efface bande verticale à droite
  1395.  
  1396.  
  1397. for(int n=0; n<10; n++)
  1398. {
  1399. d5 =0+y0+32.0*n; // pixels verticalement entre chaque trait -> 10*24 = 240px (hauteur de l'affi)
  1400. {
  1401. if (d5>=20) // marge en haut
  1402. {
  1403. TFT480.fillRect(x0, (int16_t)d5+5, 5, 2, BLANC); // petits tirets horizontaux
  1404.  
  1405. alt1 = hauteur -10*(n-5);
  1406. alt1 /= 10;
  1407. alt1 *= 10;
  1408. s1=(String) alt1;
  1409.  
  1410. if(alt1>=0)
  1411. {
  1412. TFT480.setTextColor(BLANC, GRIS_AF);
  1413. //TFT480.drawString(" ", 9, d5);
  1414. x1=x0;
  1415. if(alt1<10000){x1+=7;} // pour affichage centré
  1416. if(alt1<1000){x1+=7;}
  1417. if(alt1<100){x1+=7;}
  1418. if(alt1<10){x1+=7;}
  1419. TFT480.drawString(s1, x1, (uint16_t)d5); // Graduation (tous les 20kts)
  1420. }
  1421. }
  1422. }
  1423. }
  1424.  
  1425.  
  1426. //---------------------------------------------------------------------------------------
  1427. // affichage de la valeur principale
  1428.  
  1429. uint16_t x2;
  1430. uint16_t y0b = 155;
  1431. TFT480.fillRect(x0-20, y0b, 80, 25, NOIR); // efface le nombre précédemment affiché
  1432. TFT480.setTextColor(BLANC, NOIR);
  1433. TFT480.setFreeFont(FF18);
  1434.  
  1435. if ((1) && (hauteur < 60000))
  1436. {
  1437. s1=(String) hauteur;
  1438. }
  1439. else {s1="----";}
  1440. x2=x0-20;
  1441. if(hauteur<10000){x2+=10;} // pour affichage centré
  1442. if(hauteur<1000){x2+=10;}
  1443. if(hauteur<100){x2+=10;}
  1444. if(hauteur<10){x2+=10;}
  1445.  
  1446. if(hauteur<0)
  1447. {
  1448. TFT480.setTextColor(ROUGE);
  1449. x2=x0-20; // si valeur négative affichée avec signe "-"
  1450. }
  1451.  
  1452.  
  1453. TFT480.drawString(s1, x2, y0b);
  1454. uint16_t couleur1=GRIS;
  1455. if (mode_affi_hauteur == ASL) {couleur1=BLEU;}
  1456. if (mode_affi_hauteur == AAL) {couleur1=VERT;}
  1457.  
  1458. TFT480.drawRoundRect(x0-20, y0b-3, 75, 28, 5, couleur1); // encadrement de la valeur centrale affichée
  1459.  
  1460. }
  1461.  
  1462.  
  1463. void affi_frq_NAV1()
  1464. {
  1465. String s1;
  1466. uint16_t x0=120;
  1467. uint16_t y0=234;
  1468. float f1;
  1469.  
  1470. f1 = vor_frq/1000.0;
  1471. s1= String(f1, 2);
  1472.  
  1473. TFT480.fillRect(x0, y0, 55, 18, NOIR); // efface
  1474. TFT480.setFreeFont(FM9);
  1475. TFT480.setTextColor(VERT, NOIR);
  1476. TFT480.drawString(s1, x0, y0);
  1477. TFT480.drawString("MHz", x0+70, y0);
  1478. }
  1479.  
  1480.  
  1481. void affi_dst_NAV1()
  1482. {
  1483.  
  1484. if (vor_dst<0) {vor_dst=0;}
  1485. String s1;
  1486. uint16_t x0=180;
  1487. uint16_t y0=236;
  1488. // rappel: 1 mile marin (NM nautical mile) = 1852m
  1489. float vor__nm = (float)vor_dst / 1852.0;
  1490. //Serial.println(vor__nm);
  1491.  
  1492. TFT480.setTextColor(JAUNE, NOIR);
  1493. TFT480.drawString("Nv1", x0-40, y0);
  1494. TFT480.setTextColor(BLANC, NOIR);
  1495.  
  1496. uint8_t nb_decimales =1;
  1497. if (vor__nm >99) {nb_decimales=0;}
  1498.  
  1499. s1 = String( vor__nm, nb_decimales);
  1500. TFT480.fillRect(x0, y0, 52, 18, NOIR); // efface
  1501. TFT480.setFreeFont(FM9);
  1502. TFT480.drawString(s1, x0, y0);
  1503. TFT480.drawRoundRect(x0, y0-2, 50, 18, 5, GRIS_FONCE); // encadrement de la valeur affichée
  1504.  
  1505. TFT480.drawString("NM", x0+55, y0);
  1506. }
  1507.  
  1508.  
  1509. void affi_radial_NAV1()
  1510. {
  1511.  
  1512. if (vor_actual<0) {vor_actual=0;}
  1513. String s;
  1514. uint16_t x0=260;
  1515. uint16_t y0=236;
  1516.  
  1517. int16_t alpha1 = vor_actual/100.0;
  1518.  
  1519. int16_t alpha2 = alpha1 + 180;
  1520. if (alpha2>360) {alpha2 -= 360;}
  1521.  
  1522. if (alpha1 == 360) {alpha1 =0;}
  1523. if (alpha2 == 360) {alpha2 =0;}
  1524.  
  1525.  
  1526. //affichage numérique de l'angle
  1527. TFT480.setTextColor(VERT, NOIR);
  1528. //s = String (alpha1 , 0); // 0 décimales
  1529. s = (String) alpha1;
  1530. TFT480.fillRect(x0, y0, 50, 18, NOIR); // efface
  1531. TFT480.setFreeFont(FM9);
  1532. TFT480.drawString(s, x0+5, y0);
  1533. TFT480.drawRoundRect(x0, y0-2, 40, 18, 5, GRIS_FONCE); // encadrement de la valeur affichée
  1534. TFT480.drawCircle(x0+46, y0, 2, JAUNE); // caractère 'degré'
  1535.  
  1536. //affichage numérique de l'angle opposé
  1537. x0+=50;
  1538. TFT480.setTextColor(VERT, NOIR);
  1539. //s = String (alpha2 , 0); // 0 décimales
  1540. s = (String) alpha2;
  1541. TFT480.fillRect(x0, y0, 50, 18, NOIR); // efface
  1542. TFT480.setFreeFont(FM9);
  1543. TFT480.drawString(s, x0+5, y0);
  1544. TFT480.drawRoundRect(x0, y0-2, 40, 18, 5, GRIS_FONCE); // encadrement de la valeur affichée
  1545. TFT480.drawCircle(x0+46, y0, 2, JAUNE);
  1546.  
  1547.  
  1548. }
  1549.  
  1550.  
  1551. void affi_dst_NAV2()
  1552. {
  1553.  
  1554. if (ils_dst<0) {ils_dst=0;}
  1555. String s1;
  1556. uint16_t x0=180;
  1557. uint16_t y0=255;
  1558. float nav_nm;
  1559. // rappel: 1 mile marin (NM nautical mile) = 1852m
  1560. //ils_nm = (float)ils_dst / 1852.0;
  1561. //if (ils_nm >99) {ils_nm=0;}
  1562.  
  1563. TFT480.setTextColor(JAUNE, NOIR);
  1564. TFT480.drawString("Nv2", x0-40, y0);
  1565. TFT480.drawString("NM", x0+55, y0);
  1566.  
  1567. TFT480.setTextColor(BLANC, NOIR);
  1568. s1 = String( ils_nm, 1); // 1 -> 0 décimale
  1569. TFT480.fillRect(x0, y0, 52, 18, NOIR); // efface
  1570. TFT480.setFreeFont(FM9);
  1571. TFT480.drawString(s1, x0, y0);
  1572. TFT480.drawRoundRect(x0, y0-2, 50, 18, 5, GRIS_FONCE); // encadrement de la valeur affichée
  1573.  
  1574. }
  1575.  
  1576.  
  1577. void affi_radial_NAV2()
  1578. {
  1579.  
  1580. if (ils_radial<0) {ils_radial=0;}
  1581. String s1;
  1582. uint16_t x0=260;
  1583. uint16_t y0=255;
  1584.  
  1585. //affichage numérique
  1586. TFT480.setTextColor(BLEU_CLAIR, NOIR);
  1587. s1 = String (ils_radial/100, 0); // 0 décimales
  1588. TFT480.fillRect(x0, y0, 50, 18, NOIR); // efface
  1589. TFT480.setFreeFont(FM9);
  1590. TFT480.drawString(s1, x0+5, y0);
  1591. TFT480.drawRoundRect(x0, y0-2, 40, 18, 5, GRIS_FONCE); // encadrement de la valeur affichée
  1592. TFT480.drawCircle(x0+46, y0, 2, JAUNE);
  1593. }
  1594.  
  1595.  
  1596. void affi_alti_NAV2()
  1597. {
  1598. // hauteur (en ft) conseillée pour l'approche IFR à la distance en nautiques (NM) de la balise Nav2
  1599. String s1;
  1600. uint16_t x=425;
  1601. uint16_t y=5;
  1602.  
  1603. float nav_nm;
  1604. float hauteur; // attention: ne pas confondre hauteur (au dessus du sol) et altitude (au dessus du niveau de la mer)
  1605. nav_nm = (float)ils_dst / 1852.0;
  1606. hauteur = 300.0*nav_nm;
  1607.  
  1608. s1 = String( hauteur, 0); // 0 -> 0 décimale
  1609. TFT480.fillRect(x, y, 55, 18, NOIR); // efface
  1610.  
  1611. if (gs_ok != 0) //attention: la valeur différente de 0 n'est pas forcément =1. (variable gérée par FG) donc ne pas écrire "==1"
  1612. {
  1613. TFT480.setTextColor(VERT, NOIR);
  1614. TFT480.setFreeFont(FF1);
  1615. //TFT480.setFreeFont(FM9);
  1616. //TFT480.setFreeFont(FS9);
  1617. //TFT480.setFreeFont(FF5);
  1618. TFT480.drawString(s1, x, y);
  1619. }
  1620. }
  1621.  
  1622.  
  1623.  
  1624. void affi_indicateurs()
  1625. {
  1626.  
  1627. TFT480.setFreeFont(FSS9);
  1628.  
  1629. /*
  1630. TFT480.drawString("CLB | IAS |", 100, 0, 1);
  1631.  
  1632. TFT480.setTextColor(AZUR, NOIR);
  1633. TFT480.drawString("ALT", 210, 0, 1);
  1634.  
  1635. TFT480.setTextColor(VERT, NOIR);
  1636. TFT480.drawString(" |", 245, 0, 1);
  1637.  
  1638. TFT480.setTextColor(AZUR, NOIR);
  1639. TFT480.drawString("HDG", 260, 0, 1);
  1640.  
  1641. TFT480.setTextColor(VERT, NOIR);
  1642. TFT480.drawString(" |", 300, 0, 1);
  1643. */
  1644.  
  1645. //if (gs_ok != 0) { TFT480.setTextColor(VERT, NOIR); } else { TFT480.setTextColor(GRIS_FONCE, NOIR); }
  1646. //TFT480.drawString("ILS", 110, 0);
  1647.  
  1648. }
  1649.  
  1650.  
  1651. void affi_Airport()
  1652. {
  1653. uint16_t n;
  1654. float v1;
  1655. String s1;
  1656.  
  1657.  
  1658. TFT480.fillRect(255, 280, 108, 20, NOIR); // efface - BLEU pour test
  1659. TFT480.setTextFont(1);
  1660.  
  1661. TFT480.setTextColor(BLEU_CLAIR, NOIR);
  1662. s1= liste_bali[num_bali].ID_OACI;
  1663. TFT480.drawString(s1, 255, 280);
  1664.  
  1665. s1= (String)liste_bali[num_bali].altitude;
  1666. s1 +=" ft";
  1667. TFT480.setTextColor(VIOLET2, NOIR);
  1668. TFT480.drawString(s1, 300, 280);
  1669.  
  1670. TFT480.fillRect(270, 300, 60, 30, NOIR); // efface - GRIS pour test
  1671. s1= liste_bali[num_bali].nom;
  1672. TFT480.setTextColor(BLEU_CLAIR, NOIR);
  1673. TFT480.drawString(s1, 255, 290);
  1674.  
  1675. TFT480.setTextColor(VERT, NOIR);
  1676.  
  1677. v1= liste_bali[num_bali].frq_VOR/100.0;
  1678. s1 = String(v1, 2);
  1679. TFT480.drawString(s1, 270, 300);
  1680.  
  1681. v1= liste_bali[num_bali].frq_ILS/100.0;
  1682. s1 = String(v1, 2);
  1683. TFT480.drawString(s1, 270, 310);
  1684.  
  1685. }
  1686.  
  1687.  
  1688. void affi_mode_affi_hauteur()
  1689. {
  1690. if (mode_affi_hauteur == AAL)
  1691. {
  1692. TFT480.setFreeFont(FF1);
  1693. TFT480.setTextColor(VERT, GRIS_AF); // Autolanding en cours, ok
  1694. TFT480.drawString("AAL", 290, 0);
  1695. }
  1696. if (mode_affi_hauteur == ASL)
  1697. {
  1698. TFT480.setFreeFont(FF1);
  1699. TFT480.setTextColor(BLEU_CLAIR, GRIS_AF); // Autolanding en cours, ok
  1700. TFT480.drawString("ASL", 290, 0);
  1701. }
  1702. }
  1703.  
  1704.  
  1705.  
  1706. void auto_landing()
  1707. {
  1708. /**
  1709.  voir: https://en.wikipedia.org/wiki/Autoland
  1710.  
  1711.  Atterrissage automatique
  1712.  CAPTURE l'avion et le POSE !
  1713.  vitesse conseillée : 160kts max
  1714.  distance conseillée : entre 20 et 10 nautiques
  1715.  hauteur conseillée : 3000ft (= niveau 30)
  1716.  
  1717.  à ceci près que l'autopilot se déconnecte automatiquement (par FlightGear) sous 100ft de hauteur
  1718.  ( Donc garder le manche en main pour le touché final, en surveillant la vitesse et le pitch
  1719.  parce que si le trim de profondeur est mal réglé, à la déconnexion de l'autopilot c'est le plongeon près du sol = crash !
  1720.  avec ma manette Thrustmaster et le Citation X, je n'arrive pas à régler le trim !! )
  1721.  
  1722. **/
  1723. String s1;
  1724.  
  1725. TFT480.setFreeFont(FSS9);
  1726.  
  1727. TFT480.setTextColor(GRIS_FONCE, NOIR);
  1728. TFT480.fillRect(80, 0, 120, 16, NOIR); // JAUNE pour test. efface 1/2 le bandeau d'information en haut
  1729.  
  1730. voyant_L.couleur_caract = BLANC;
  1731. voyant_L.affiche(GRIS_TRES_FONCE);
  1732.  
  1733. voyant_G.couleur_caract = BLANC;
  1734. voyant_G.affiche(GRIS_TRES_FONCE);
  1735.  
  1736.  
  1737. //float ils_nm =(float)ils_dst / 1852.0;
  1738.  
  1739. float delta_LOC = ils_loc / 1000.0; //localizer (en azimut); remarque: |delta_LOC| jamais > 10, reste bloqué à 10...
  1740. float G1 = ils_glide/1000.0;
  1741. // G1 = angle (vertical) sous lequel l'avion est vu depuis la balise ILS
  1742. // G1 = +3.00 si angle = 3° = ok
  1743. // si G1>3.0 -> avion trop haut, au dessus du plan de descente -> il faut descendre
  1744. // si G1<3.0 -> avion trop bas, au dessus du plan de descente -> il ne faut plus descendre
  1745. float delta_GS = 3.0 - G1;
  1746.  
  1747.  
  1748. uint8_t type_balise = liste_bali[num_bali].typ; // pour test si la piste est équipée d'un glide
  1749.  
  1750. /**
  1751. rappel: codage des Types de balises : (voir fichier FG_data.ino)
  1752.  
  1753. _LOC LOCALIZER
  1754. _DME DISTANCE MEASURING EQUIPMENT
  1755. _GS GLIDE SYSTEM
  1756. _NDB Non-directional beacon (Balise non directionnelle)
  1757.  
  1758. **/
  1759.  
  1760. //-------------------------------------------------------------------------------------------------------
  1761. // gestion des voyants (quelle que soit la position du switch autoland)
  1762.  
  1763. if(au_sol == 0) // c,a,d si l'avion est en vol, pour éviter d'allumer les voyants ILS dès le départ
  1764. {
  1765. if( ((type_balise & _LOC) !=0) && (delta_LOC > -9.5) && (delta_LOC < +9.5) )
  1766. {
  1767. voyant_L.couleur_caract = BLANC;
  1768. voyant_L.affiche(VERT_FONCE);
  1769. }
  1770. else
  1771. {
  1772. voyant_L.couleur_caract = BLANC;
  1773. voyant_L.affiche(GRIS_FONCE);
  1774. }
  1775.  
  1776.  
  1777.  
  1778. if(((type_balise & _GS) !=0) && (delta_GS > -3.0) && (delta_GS < +3.0) )
  1779. {
  1780. voyant_G.couleur_caract = BLANC;
  1781. voyant_G.affiche(VERT_FONCE);
  1782. }
  1783. else
  1784. {
  1785. voyant_G.couleur_caract = BLANC;
  1786. voyant_G.affiche(GRIS_FONCE);
  1787. }
  1788.  
  1789. // affichage numérique des valeurs delta_LOC (localizer) et delta_GS (glide)
  1790. TFT480.setTextFont(1);
  1791.  
  1792. uint16_t couleur1=VERT;
  1793. if ((delta_LOC== 10.0) || (delta_LOC== -10.0)) {couleur1=GRIS;} // si bloqué en butée (hors du faisceau donc)
  1794. s1 = "LOC:";
  1795. s1+= String(delta_LOC,2);
  1796. TFT480.setTextColor(couleur1, NOIR);
  1797. TFT480.drawString(s1, 225, 0);
  1798.  
  1799. uint16_t couleur2=ROSE;
  1800. if ((delta_GS<= -5.0) || (delta_GS > 5.0)) {couleur2=GRIS;} // si trop écarté du pla de descente à 3°
  1801. s1 = "GLD:";
  1802. s1+= String(delta_GS,2);
  1803. TFT480.setTextColor(couleur2, NOIR);
  1804. TFT480.drawString(s1, 225, 8);
  1805. }
  1806.  
  1807. //-------------------------------------------------------------------------------------------------------
  1808. // (si autoland engagé (par le bouton 'ILS' du module SW), sinon on ne fait rien de plus)
  1809.  
  1810. if ( (autoland != 0) && (((type_balise & _LOC) !=0) || ((type_balise & _GS) !=0)) )
  1811. {
  1812. //TFT480.setTextColor(BLANC); TFT480.setFreeFont(FF1);
  1813. //TFT480.drawString("autoLanding", HA_x0-60, HA_y0+60);
  1814.  
  1815. TFT480.setTextColor(BLANC, NOIR);
  1816. TFT480.drawString("ILS", 110, 0);
  1817.  
  1818. // azimut (localizer)
  1819. if((delta_LOC > -9.5) && (delta_LOC < +9.5) )
  1820. {
  1821. voyant_L.couleur_caract = NOIR;
  1822. voyant_L.affiche(VERT);
  1823. }
  1824. else
  1825. {
  1826. voyant_L.couleur_caract = BLANC;
  1827. voyant_L.affiche(ROUGE);
  1828. }
  1829.  
  1830. if((delta_GS > -3.0) && (delta_GS < 3.0) )
  1831. {
  1832. voyant_G.couleur_caract = NOIR;
  1833. voyant_G.affiche(VERT);
  1834. }
  1835. else
  1836. {
  1837. voyant_G.couleur_caract = BLANC;
  1838. voyant_G.affiche(ROUGE);
  1839. }
  1840.  
  1841.  
  1842. if ((gs_ok != 0) && (hauteur_AAL < 5000) && (ils_nm < 30.0))
  1843. {
  1844. //glide effectif (capture) seulement si l'avion est suffisamment proche de la balise et suffisamment bas
  1845.  
  1846. TFT480.setTextColor(VERT, NOIR);
  1847. TFT480.drawString("ALTI", 110, 0);
  1848. if(delta_GS < 0) // on force à descendre mais jamais à remonter (on reste alors en palier)
  1849. {
  1850. asel1 = (uint16_t)((hauteur_AAL/100.0) + 1.3 * delta_GS);
  1851. }
  1852. }
  1853.  
  1854.  
  1855. if ( ((type_balise & _GS) == 0) && (hauteur_AAL < 5000) && (ils_nm < 30.0) )
  1856. {
  1857. // on passe ici si PAS de glide
  1858. // affichage de l'altitude conseillée pour approche sans glide;
  1859. // la descente se fait alors en fonction de la distance.
  1860. // toutefois le cap reste automatique
  1861.  
  1862. float alti1 = 3.0*ils_nm + gnd_elv/100.0; // altitude avion doit être = hauteur avion (souhaitée) + altitude terrain (réelle)
  1863. //correction en conséquence de la consigne d'altitude du pilote auto
  1864. if (alti1 < asel1) //empêche de (re)monter lors de la capture ILS, reste en palier le cas échéant
  1865. {
  1866. asel1 = alti1;
  1867. }
  1868.  
  1869.  
  1870. float alti2 = alti1*100;
  1871. String s1 = String(alti2,0);
  1872. TFT480.setTextColor(BLEU_CLAIR, NOIR);
  1873. TFT480.drawString(s1, 300, 0);
  1874.  
  1875.  
  1876.  
  1877. }
  1878.  
  1879. if(((type_balise & _LOC) != 0) && (delta_LOC > -9.5) && (delta_LOC < 9.5)) //localizer; remarque: |delta_LOC| jamais > 10
  1880. {
  1881. // ici l'avion est dans un angle serré (9.5° max) vu de la balise mais pas forcément bien orienté (cap)
  1882. voyant_L.affiche(VERT);
  1883. TFT480.setFreeFont(FF1);
  1884.  
  1885. TFT480.setTextColor(VERT, NOIR); // Autolanding en cours, ok
  1886. TFT480.drawString("LOC", 160, 0);
  1887.  
  1888. hdg1 = (uint16_t)((ils_radial/100.0) + 2.0 * delta_LOC); //corrige la consigne de cap de l'autopilot pour rejoindre puis rester dans l'axe de la piste2
  1889.  
  1890. }
  1891. else
  1892. {
  1893. // indique conditions Autolanding non remplies
  1894. TFT480.setFreeFont(FF1);
  1895. TFT480.setTextColor(GRIS, NOIR);
  1896. TFT480.drawString("APP", 150, 0);
  1897. //TFT480.drawRect(HA_x0-60, HA_y0+85, 100,20, HA_SOL); // efface le "capture ok"
  1898. }
  1899. }
  1900. //-------------------------------------------------------------------------------------------------------
  1901.  
  1902.  
  1903. }
  1904.  
  1905.  
  1906.  
  1907. void affi_localizer()
  1908. {
  1909. //ILS dans le plan horizontal ; affiche l'erreur de position par rapport à l'axe de la piste
  1910.  
  1911. uint16_t y1 = HA_y0-HA_h-14;
  1912.  
  1913. // ils_loc = -10 *1000 .. +10 *1000
  1914. // l'affichage doit se faire en HA_x0 +/- HA_w
  1915. // 10000/HA_w = 10000/120 = 83
  1916.  
  1917. uint16_t couleur1 = ROSE;
  1918. loc = HA_x0 + ils_loc / 83;
  1919. if ( loc < (HA_x0-HA_w+5)) {loc = HA_x0-HA_w+5; couleur1 = GRIS;}
  1920. if ( loc > (HA_x0+HA_w-5)) {loc= HA_x0+HA_w-5; couleur1 = GRIS;}
  1921.  
  1922.  
  1923. TFT480.fillRect(HA_x0-HA_w, y1, 2*HA_w, 9, GRIS_TRES_FONCE);
  1924. TFT480.drawLine(HA_x0, y1-5, HA_x0, y1+5, BLANC);
  1925.  
  1926. affi_indexV(loc, y1, 1, couleur1); // petit triangle rose en haut, se déplaçant horizontalement
  1927.  
  1928. memo_loc=loc;
  1929. }
  1930.  
  1931.  
  1932.  
  1933. void affi_glide() // Nav2
  1934. {
  1935. /*
  1936.  "Glide Path-pente" = ILS dans le plan vertical
  1937.  trace des index horizontaux sur les bords de l'HA
  1938.  
  1939.  Remarque : dans FG toutes les pistes ne sont pas équipées d'un faisceau ILS GLIDE dans les deux sens d'approche...
  1940.  L'affichage de la carte (interne ou externe dans le navigateur) permet de visualiser les faisceaux en question si existants.
  1941.  par exemple, dans FG et pour LFMT, seule l'approche par le sud (par la mer) est équipée
  1942.  
  1943.  D'autre part, il faut avoir réglé le récepteur NAV2 sur la bonne fréquence.
  1944.  Voir le pannel F12 de FD ainsi que les cartes d'aéroport.
  1945.  Ce réglage est fait automatiquement par le second instrument "ND" connecté en WiFi, lors de la sélection d'un aérodrome
  1946.  
  1947.  On peut aussi lancer FG avec les options suivantes dans FGo! (par exemple):
  1948. --vor_=114.45 (pour le VOR)
  1949. --ils_=305:108.55 (pour l'ILS de LFMT piste 31R)
  1950. */
  1951.  
  1952. uint16_t x1 = 75;
  1953. uint16_t x2 = 332;
  1954.  
  1955. gld = HA_y0 - 50*(3.0-ils_glide/1000.0);
  1956.  
  1957.  
  1958. TFT480.fillRect(x1, 30, 9, 2*HA_h, GRIS_TRES_FONCE); // efface
  1959. TFT480.fillRect(x2, 30, 9, 2*HA_h, GRIS_TRES_FONCE); // efface
  1960.  
  1961. TFT480.drawRect(x1, HA_y0, 12, 5, BLANC);
  1962. TFT480.drawRect(x2, HA_y0, 12, 5, BLANC);
  1963.  
  1964. uint16_t couleur1 = ROSE;
  1965. if ( gld < (HA_y0-HA_h+5)) {gld = HA_y0-HA_h+5; couleur1 = GRIS;}
  1966. if ( gld > (HA_y0+HA_h-5)) {gld = HA_y0+HA_h-5; couleur1 = GRIS;}
  1967.  
  1968. affi_indexH(x1, gld, 1, couleur1);
  1969. affi_indexH(x2+8, gld, -1, couleur1);
  1970.  
  1971. memo_gld=gld;
  1972. }
  1973.  
  1974.  
  1975.  
  1976. void trace_arc_gradu()
  1977. {
  1978. //arc gradué en haut au centre, indiquant la valeur de l'inclinaison
  1979.  
  1980. float angle;
  1981. //Draw_arc_elliptique(HA_x0, 120, 120, 80, 0.6, 2.6, BLANC);
  1982.  
  1983.  
  1984. for(uint8_t n=0; n<9; n++ )
  1985. {
  1986. angle =30+ n*15; // 1 tiret tous les 15 degrés
  1987. float pourcent = 0.9;
  1988. if (((n+2)%2) == 0) {pourcent = 0.8;}
  1989.  
  1990. affi_rayon1(HA_x0, HA_y0+10, 110, degTOrad(angle), pourcent, BLANC, false); // tirets de graduation
  1991. }
  1992. }
  1993.  
  1994.  
  1995.  
  1996. void rotation1()
  1997. {
  1998. // consigne de cap
  1999. // acquisition de l'encodeur pas à pas (1)
  2000. if ( millis() - TEMPO >= timer1 )
  2001. {
  2002. timer1 = millis();
  2003. bool etat = digitalRead(rot1b);
  2004. if(etat == 0) { hdg1+=1;} else { hdg1-=1;}
  2005. if (hdg1<0){hdg1=355;}
  2006.  
  2007. if (hdg1>359){hdg1=0;}
  2008. }
  2009. }
  2010.  
  2011.  
  2012.  
  2013. void rotation2()
  2014. {
  2015. // consigne d'altitude
  2016. // acquisition de l'encodeur pas à pas (2)
  2017. if ( millis() - TEMPO >= timer2 )
  2018. {
  2019. timer2 = millis();
  2020. bool etat = digitalRead(rot2b);
  2021. if(etat == 0) { asel1+=1; } else { asel1-=1; }
  2022. if (asel1<1){asel1=1;} // 100 pieds -> 30m
  2023. if (asel1>600){asel1=600;}
  2024. }
  2025. }
  2026.  
  2027.  
  2028.  
  2029. void init_SDcard()
  2030. {
  2031. String s1;
  2032.  
  2033. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  2034. TFT480.setTextColor(BLANC, NOIR);
  2035. TFT480.setFreeFont(FF1);
  2036.  
  2037. uint16_t y=0;
  2038.  
  2039. TFT480.drawString("PRIMARY FLIGHT DISPLAY", 0, y);
  2040. y+=20;
  2041.  
  2042. s1="version " + version;
  2043. TFT480.drawString(s1, 0, y);
  2044.  
  2045. y+=40;
  2046. TFT480.setTextColor(VERT, NOIR);
  2047. TFT480.drawString("Init SDcard", 0, y);
  2048. y+=20;
  2049.  
  2050.  
  2051. if(!SD.begin())
  2052. {
  2053. TFT480.drawString("Card Mount Failed", 0, y);
  2054. delay (2000);
  2055. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  2056. return;
  2057. }
  2058.  
  2059.  
  2060. uint8_t cardType = SD.cardType();
  2061.  
  2062. if(cardType == CARD_NONE)
  2063. {
  2064. TFT480.drawString("No SDcard", 0, y);
  2065. delay (2000);
  2066. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  2067. return;
  2068. }
  2069.  
  2070. SDcardOk=1;
  2071.  
  2072. TFT480.drawString("SDcard Type: ", 0, y);
  2073. if(cardType == CARD_SD) {TFT480.drawString("SDSC", 150, y);}
  2074. else if(cardType == CARD_SDHC) {TFT480.drawString("SDHC", 150, y);}
  2075.  
  2076. y+=20;
  2077.  
  2078. uint32_t cardSize = SD.cardSize() / (1024 * 1024);
  2079. s1=(String)cardSize + " GB";
  2080. TFT480.drawString("SDcard size: ", 0, y);
  2081. TFT480.drawString(s1, 150, y);
  2082.  
  2083. // listDir(SD, "/", 0);
  2084.  
  2085. //Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
  2086. //Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
  2087.  
  2088. delay (1000);
  2089. TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
  2090.  
  2091. }
  2092.  
  2093.  
  2094. void init_sprites()
  2095. {
  2096. // sprites représentant les lettres 'N' 'S' 'E' 'O' qui seront affichées sur un cercle, inclinées donc.
  2097.  
  2098. SPR_E.setFreeFont(FF1);
  2099. SPR_E.setTextColor(JAUNE);
  2100. SPR_E.createSprite(SPR_W, SPR_H);
  2101. SPR_E.setPivot(SPR_W/2, SPR_H/2); // Set pivot relative to top left corner of Sprite
  2102. SPR_E.fillSprite(GRIS_TRES_FONCE);
  2103. SPR_E.drawString("E", 2, 1 );
  2104.  
  2105. SPR_N.setFreeFont(FF1);
  2106. SPR_N.setTextColor(JAUNE);
  2107. SPR_N.createSprite(SPR_W, SPR_H);
  2108. SPR_N.setPivot(SPR_W/2, SPR_H/2);
  2109. SPR_N.fillSprite(GRIS_TRES_FONCE);
  2110. SPR_N.drawString("N", 2, 1 );
  2111.  
  2112. SPR_O.setFreeFont(FF1);
  2113. SPR_O.setTextColor(JAUNE);
  2114. SPR_O.createSprite(SPR_W, SPR_H);
  2115. SPR_O.setPivot(SPR_W/2, SPR_H/2);
  2116. SPR_O.fillSprite(GRIS_TRES_FONCE);
  2117. SPR_O.drawString("W", 2, 1 );
  2118.  
  2119. SPR_S.setFreeFont(FF1);
  2120. SPR_S.setTextColor(JAUNE);
  2121. SPR_S.createSprite(SPR_W, SPR_H);
  2122. SPR_S.setPivot(SPR_W/2, SPR_H/2);
  2123. SPR_S.fillSprite(GRIS_TRES_FONCE);
  2124. SPR_S.drawString("S", 2, 1 );
  2125. }
  2126.  
  2127.  
  2128. void int_to_array(uint16_t valeur_i)
  2129. {
  2130. // prépare la chaine de caract à zéro terminal pour l'envoi
  2131. String s1= (String) valeur_i;
  2132. var_array[0]=s1[0];
  2133. var_array[1]=s1[1];
  2134. var_array[2]=s1[2];
  2135. var_array[3]=s1[3];
  2136. var_array[4]=0; // zéro terminal -> chaine C
  2137. }
  2138.  
  2139.  
  2140.  
  2141. void setup()
  2142. {
  2143. Serial.begin(19200); // 19200
  2144.  
  2145.  
  2146. WiFi.persistent(false);
  2147. WiFi.softAP(ssid, password); // ok, ça marche, crée un réseau. mode privé
  2148. IPAddress IP = WiFi.softAPIP();
  2149.  
  2150.  
  2151. server.on("/switch", HTTP_GET, [](AsyncWebServerRequest *request) // lecture des boutons de l'ESP(3)
  2152. {
  2153. // attention: ce code est appelé par une interruption WiFi qui intervient hors timing. Donc pas d'affichage ici !!
  2154. //size_t n=request->params(); // get arguments count
  2155.  
  2156. argument_recu1 = request->arg("sw1"); // reception de l'argument n°1 de la requête
  2157. switches=argument_recu1;
  2158. v_switches=switches.toInt();
  2159. traiter_SW=1; //positionne ce drapeau afin que le traitement se fasse dans le timming général, pas ici !
  2160.  
  2161. int_to_array(0);
  2162.  
  2163. argument_recu2 = request->arg("pot1"); // reception de l'argument n°2 de la requête
  2164. potar1=argument_recu2; // = "0".."255"
  2165. v_potar1 = -128 + potar1.toInt();
  2166. rudder = (float)v_potar1 / 500.0; // 500.0 détermine la sensibilité de la gouverne de direction
  2167.  
  2168. //cet array because la fonction "request->send_P()" n'accèpte pas directement le string
  2169. //rappel :
  2170. //void send_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr);
  2171. //void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr);
  2172.  
  2173. request->send_P(200, "text/plain", var_array); // envoie comme réponse au client
  2174. });
  2175.  
  2176.  
  2177. server.on("/hdg", HTTP_GET, [](AsyncWebServerRequest *request) // consigne de cap
  2178. {
  2179. // attention: ce code est appelé par une interruption WiFi qui intervient hors timing. Donc pas d'affichage ici !!
  2180. //size_t n=request->params(); // get arguments count
  2181.  
  2182. argument_recu1 = request->arg("a1"); // reception de l'argument n°1 de la requête
  2183. num_bali=argument_recu1.toInt();
  2184.  
  2185. argument_recu2 = request->arg("swND");
  2186. traiter_SW=1; //positionne ce drapeau afin que le traitement se fasse dans le timming général, pas ici !
  2187.  
  2188. v_switches_ND = argument_recu2.toInt();
  2189. switches_ND = String(v_switches_ND);
  2190.  
  2191.  
  2192. int_to_array(hdg1);
  2193.  
  2194. //cet array because la fonction "request->send_P()" n'accèpte pas directement le string
  2195. //rappel :
  2196. //void send_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr);
  2197. //void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr);
  2198.  
  2199. request->send_P(200, "text/plain", var_array); // envoie hdg1 comme réponse au client
  2200. });
  2201.  
  2202. // réponses aux requêtes :
  2203. // VOIR la fonction "void interroge_WiFi()" dans le code du ND (l'affichage de la carte...)
  2204. // pour la réception des données qui suivent
  2205. server.on("/cap", HTTP_GET, [](AsyncWebServerRequest *request)
  2206. {
  2207. int_to_array(cap); // prépare la chaine de caract à zéro terminal pour l'envoi
  2208. request->send_P(200, "text/plain", var_array); // envoie réponse au client
  2209. });
  2210.  
  2211. server.on("/vor", HTTP_GET, [](AsyncWebServerRequest *request)
  2212. {
  2213. int_to_array(vor_actual_deg); // vor_actual_deg
  2214. request->send_P(200, "text/plain", var_array); // envoie réponse au client
  2215. });
  2216.  
  2217. server.on("/ILSactual", HTTP_GET, [](AsyncWebServerRequest *request)
  2218. {
  2219. int_to_array(ils_actual_deg); // ils_actual_deg
  2220. request->send_P(200, "text/plain", var_array); // envoie réponse au client
  2221. });
  2222.  
  2223. server.on("/VORnm", HTTP_GET, [](AsyncWebServerRequest *request) //vor_dst
  2224. {
  2225. uint16_t vor__nm10 = (uint16_t) (vor_dst / 185.2);
  2226.  
  2227. int_to_array(vor__nm10);
  2228. request->send_P(200, "text/plain", var_array); // envoie réponse au client
  2229. });
  2230.  
  2231. server.on("/ILSnm", HTTP_GET, [](AsyncWebServerRequest *request) //ils_dst, pour placer avion sur la carte
  2232. {
  2233. uint16_t ils_nm10 = (uint16_t) (ils_dst / 185.2);
  2234.  
  2235. int_to_array(ils_nm10);
  2236. request->send_P(200, "text/plain", var_array); // envoie réponse au client
  2237. });
  2238.  
  2239. server.begin();
  2240.  
  2241. /*
  2242. // ************* BLUETOOTH *************
  2243. SerialBT.begin("PFD_BT01"); //Bluetooth device name
  2244. //Serial.println("The device started, now you can pair it with bluetooth!");
  2245. // *************************************
  2246. */
  2247. pinMode(bouton1, INPUT);
  2248. pinMode(bouton2, INPUT);
  2249.  
  2250. //pinMode(led1, OUTPUT);
  2251.  
  2252. pinMode(rot1a, INPUT_PULLUP);
  2253. pinMode(rot1b, INPUT_PULLUP);
  2254. pinMode(rot2a, INPUT_PULLUP);
  2255. pinMode(rot2b, INPUT_PULLUP);
  2256.  
  2257.  
  2258. attachInterrupt(rot1a, rotation1, RISING);
  2259. attachInterrupt(rot2a, rotation2, RISING);
  2260.  
  2261. TFT480.init();
  2262. TFT480.setRotation(3); // 0..3 à voir, suivant disposition de l'afficheur et sa disposition
  2263. TFT480.fillScreen(TFT_BLACK);
  2264.  
  2265. init_SDcard();
  2266.  
  2267. init_sprites();
  2268.  
  2269. delay(100);
  2270.  
  2271.  
  2272.  
  2273. TFT480.setTextColor(NOIR, BLANC);
  2274.  
  2275. //TFT480.setFreeFont(FF19);
  2276.  
  2277. init_affi_HA();
  2278.  
  2279. delay(100);
  2280.  
  2281.  
  2282. //TFT480.fillRect(48, 0, 6, 100, 0xFFE0);
  2283.  
  2284. // TFT480.fillRect(0, 0, 479, 30, NOIR);
  2285. TFT480.setTextColor(BLANC, NOIR);
  2286. TFT480.setFreeFont(FF19);
  2287. String s1 = "PFD v";
  2288. s1+= version;
  2289. // TFT480.drawString(s1, 70, 3);
  2290.  
  2291.  
  2292. Ay_actu=120;
  2293. By_actu=120;
  2294.  
  2295. altitude_GPS =0;
  2296. vitesse =0;
  2297. roulis =0;
  2298. tangage =0;
  2299. cap=0;
  2300. vspeed=0; // vitesse verticale
  2301.  
  2302. vor_frq=123500;
  2303. ils_frq=108000;
  2304.  
  2305. vor_dst=1852*102; // 102km
  2306. vor_actual_deg=45;
  2307. vor_actual=45.0 * 100.0;
  2308. ils_dst=20000; // 20km
  2309. // affichages();
  2310.  
  2311. bouton1_etat = digitalRead(bouton1);
  2312. memo_bouton1_etat = bouton1_etat;
  2313.  
  2314. bouton2_etat = digitalRead(bouton2);
  2315. memo_bouton2_etat = bouton2_etat;
  2316. if (bouton2_etat==0)
  2317. {
  2318. mode_affi_hauteur = AAL;
  2319. affi_mode_affi_hauteur();
  2320. }
  2321. if (bouton2_etat==1)
  2322. {
  2323. mode_affi_hauteur = ASL;
  2324. affi_mode_affi_hauteur();
  2325. }
  2326.  
  2327. init_FG_bali();
  2328.  
  2329. init_affi_autopilot();
  2330. //affi_indicateurs();
  2331. //affi_frq_NAV1();
  2332.  
  2333. affi_dst_NAV1();
  2334. affi_radial_NAV1();
  2335.  
  2336. affi_dst_NAV2();
  2337. affi_radial_NAV2();
  2338.  
  2339. affi_Airport();
  2340.  
  2341. voyant_L.init(0,0,30,20);
  2342. voyant_L.caract ='L';
  2343.  
  2344.  
  2345. voyant_G.init(35,0,30,20);
  2346. voyant_G.caract ='G';
  2347.  
  2348. }
  2349.  
  2350.  
  2351. //uint16_t L=0;
  2352. //uint16_t C=0;
  2353. //uint16_t x, y;
  2354.  
  2355. //uint16_t i1 = 0;
  2356.  
  2357. uint8_t p1;
  2358.  
  2359. int32_t number = 0;
  2360.  
  2361.  
  2362. String s1;
  2363. String s2;
  2364.  
  2365.  
  2366. void acquisitions()
  2367. {
  2368. // cette fonction reçoit les données de Flightgear par la liaison USB, voir le fichier "hardware4.xml" pour le protocole
  2369. // Remarque : les données des autres modules (ND et SW) sont reçues par WiFi,
  2370. // voir les sous-fonctions ("server.on(...)") dans la fonction setup()
  2371.  
  2372. char buf[50];
  2373. TFT480.setFreeFont(FM9);
  2374. TFT480.setTextColor(VERT, NOIR);
  2375.  
  2376. if(Serial.available() > 14) // 14
  2377. {
  2378. parametre="";
  2379. s1="";
  2380. char octet_in;
  2381.  
  2382. while(octet_in != '=')
  2383. {
  2384. octet_in = Serial.read();
  2385. if(octet_in != '=') {parametre += octet_in; }
  2386. }
  2387. while(octet_in != '\n')
  2388. {
  2389. octet_in = Serial.read();
  2390. if(octet_in != '\n') {s1 += octet_in; }
  2391. }
  2392.  
  2393. if(parametre == "alti" )
  2394. {
  2395. // ALTITUDE GPS (et pas 'altimetre', volontairement, voir le fichier hardware4.xml)
  2396. // voir la ligne '<node>/instrumentation/gps/indicated-altitude-ft</node>'
  2397. // marre des QFE, QNH, AGL, ASFC, AMSL, STD...
  2398. // j'ai joué avec tout ça, mais finalement je décide d'utiliser le GPS,
  2399. // ce qui est contraire aux recommandations aéronautiques,
  2400. // sans doute parce que le jour où le GPS mondial viendrait à tomber en panne, c'est 275643 avions qui se crasheraient !
  2401. // mais ici on est dans FlightGear, on ne risque rien !
  2402.  
  2403. s1.toCharArray(buf, 50);
  2404.  
  2405. int32_t valeur = atol(buf);
  2406. altitude_GPS_float = (float)valeur / 1000.0;
  2407. altitude_GPS = valeur/1000; // integer
  2408. hauteur_AAL = altitude_GPS - liste_bali[num_bali].altitude;
  2409.  
  2410. data_ok |= 1; // positionne bit0
  2411. }
  2412.  
  2413. if(parametre == "gnd_elv" )
  2414. {
  2415. s1.toCharArray(buf, 50);
  2416. gnd_elv = atol(buf);
  2417. if (gnd_elv <0) {gnd_elv =0;}
  2418. data_ok |= 2; // positionne bit1
  2419. }
  2420.  
  2421. if(parametre == "speed" )
  2422. {
  2423. s1.toCharArray(buf, 50);
  2424. vitesse = atol(buf);
  2425. data_ok |= 4; // positionne bit2
  2426. }
  2427.  
  2428. if(parametre == "pitch" )
  2429. {
  2430. //char buf[50];
  2431. s1.toCharArray(buf, 50);
  2432. tangage = atol(buf);
  2433. data_ok |= 8; // positionne bit3
  2434. }
  2435.  
  2436. if(parametre == "roll" )
  2437. {
  2438. s1.toCharArray(buf, 50);
  2439. roulis = atol(buf);
  2440. data_ok |= 16; // positionne bit4
  2441. }
  2442.  
  2443.  
  2444.  
  2445. if(parametre == "heading" ) // /orientation/heading-deg = cap actuel de l'avion ; ne pas confondre avec HDG bug !
  2446. {
  2447. s1.toCharArray(buf, 50);
  2448. cap = atol(buf);
  2449. data_ok |= 32; // positionne bit5
  2450. }
  2451.  
  2452.  
  2453. if(parametre == "vspeed" )
  2454. {
  2455. s1.toCharArray(buf, 50);
  2456. vspeed = atol(buf);
  2457. data_ok |= 64; // positionne bit6
  2458. }
  2459.  
  2460.  
  2461. if(parametre == "vor_frq" )
  2462. {
  2463. s1.toCharArray(buf, 50);
  2464. vor_frq = atol(buf);
  2465. data_ok |= 128; // positionne bit7
  2466. }
  2467.  
  2468.  
  2469. if(parametre == "vor_dst" )
  2470. {
  2471. s1.toCharArray(buf, 50);
  2472. vor_dst = atol(buf); // en mètres
  2473. data_ok |= 256; // positionne bit8
  2474. }
  2475.  
  2476.  
  2477. if(parametre == "ils_dst" )
  2478. {
  2479. s1.toCharArray(buf, 50);
  2480. ils_dst = atol(buf);
  2481. ils_nm = (float)ils_dst / 1852.0;
  2482. data_ok |= 512; // positionne bit9
  2483. }
  2484.  
  2485.  
  2486. if(parametre == "ils_loc" )
  2487. {
  2488. // erreur d'angle (/ à l'axe de la piste) dans le plan horizontal sous lequel l'antenne ILS au sol voit l'avion; Doit être 0°
  2489. // en fait varie dans la plage [-10.0 .. +10.0] avec un facteur 1000 écrit dans "hardvare4.xml"
  2490. s1.toCharArray(buf, 50);
  2491.  
  2492. ils_loc = atol(buf); // = 1000* [-10.0 .. +10.0] c.a.d = [-10000 .. +10000];
  2493. //Attention : |ils_loc| jamais > 10, même si l'angle réel est bien plus grand, de l'ordre de 90° !!
  2494.  
  2495. data_ok |= 1024; // positionne bit10
  2496. }
  2497.  
  2498.  
  2499. if(parametre == "ils_glide" )
  2500. {
  2501. //angle dans le plan vertical sous lequel l'antenne au sol (ILS GLIDE) voit l'avion; Doit être de 3° en finale
  2502. //c'est l'inclinaison du plan de descente effectif
  2503. s1.toCharArray(buf, 50);
  2504. ils_glide = atol(buf);
  2505. data_ok |= 2048; // positionne bit11
  2506. }
  2507.  
  2508.  
  2509. if(parametre == "gs_ok" )
  2510. {
  2511. // indique si le signal ILS est reçu
  2512. // un test en vol permet de voir que le signal décroche au delà de 27.2 nautiques soit 50km de distance
  2513. s1.toCharArray(buf, 50);
  2514. gs_ok = atol(buf);
  2515. data_ok |= 4096; // positionne bit12
  2516. }
  2517.  
  2518.  
  2519. if(parametre == "vor_actual" )
  2520. {
  2521. //angle dans le plan horizontal sous lequel la station (VOR) voit l'avion
  2522. s1.toCharArray(buf, 50);
  2523. vor_actual = atol(buf);
  2524. vor_actual_deg = vor_actual/100;
  2525. data_ok |= 8192; // positionne bit13
  2526. }
  2527.  
  2528.  
  2529. if(parametre == "ils_radial" )
  2530. {
  2531. //angle dans le plan horizontal sous lequel l'antenne au sol (LOC) voit l'avion
  2532. s1.toCharArray(buf, 50);
  2533. ils_radial = atol(buf);
  2534. data_ok |= 16384; // positionne bit14
  2535. }
  2536.  
  2537.  
  2538. if(parametre == "ils_actual" )
  2539. {
  2540. //angle dans le plan horizontal sous lequel l'antenne au sol (LOC) voit l'avion
  2541. s1.toCharArray(buf, 50);
  2542. ils_actual = atol(buf);
  2543. ils_actual_deg = ils_actual/100;
  2544. data_ok |= 32768; // positionne bit15
  2545. }
  2546.  
  2547. }
  2548.  
  2549. delay(3); // 3 important sinon ne recevra pas la totalité des données (qui se fait en plusieurs passes)
  2550.  
  2551. // pour test
  2552. ////TFT480.drawString("data= ", 90, 40);
  2553. ////s2= (String) data_ok;
  2554. ////TFT480.fillRect(140, 40, 50, 30, TFT_BLACK);
  2555. ////TFT480.drawString(s2, 150, 40);
  2556.  
  2557. }
  2558.  
  2559.  
  2560.  
  2561. void data_out()
  2562. {
  2563. // destination FlightGear par la liaison série USB ; voir le fichier "hardware4.xml" pour le protocole
  2564.  
  2565. Serial.print(hdg1); // consigne de Cap -> autopilot
  2566. Serial.print(',');
  2567.  
  2568. Serial.print(asel1); // consigne d'altitude -> autopilot
  2569. Serial.print(',');
  2570.  
  2571. float v1 = liste_bali[num_bali].frq_VOR/100.0;
  2572. Serial.print(v1); // écrit la fréquence VOR dans Nav1
  2573. Serial.print(',');
  2574.  
  2575. float v2 = liste_bali[num_bali].frq_ILS/100.0;
  2576. Serial.print(v2); // écrit la fréquence ILS dans Nav2
  2577. Serial.print(',');
  2578.  
  2579. uint16_t v3 = landing_light1;
  2580. Serial.print(v3);
  2581. Serial.print(',');
  2582.  
  2583. uint16_t v4 = landing_light2;
  2584. Serial.print(v4);
  2585. Serial.print(',');
  2586.  
  2587. uint16_t v5 = target_speed;
  2588. Serial.print(v5); // écrit la consigne de vitesse (target_speed)
  2589. Serial.print(',');
  2590.  
  2591. uint16_t v6 = 200; // 50 ft ce qui permet de poser en mode autopilot ! (on peut toujours désengager l'autopilot manuellement !)
  2592. Serial.print(v6); // écrit l'altitude minimum d'engagement du pilote auto de Flightgear (par défaut = 300)
  2593. Serial.print(',');
  2594.  
  2595.  
  2596. float v7 = rudder;
  2597. Serial.print(v7);
  2598. Serial.print(',');
  2599.  
  2600. uint8_t v8 = view_number;
  2601. Serial.print(v8);
  2602. Serial.print('\n');
  2603.  
  2604. }
  2605.  
  2606.  
  2607.  
  2608. void affichages()
  2609. {
  2610. if (roulis < -45) {roulis = -45;}
  2611. if (roulis > 45) {roulis = 45;}
  2612.  
  2613. if (tangage < -30) {tangage = -30;}
  2614. if (tangage > 30) {tangage = 30;}
  2615.  
  2616. affi_HA();
  2617. affi_vitesse();
  2618. affi_hauteur();
  2619. trace_arc_gradu();
  2620. affi_cap();
  2621. affi_vt_verticale();
  2622. affi_acceleration();
  2623. affi_autopilot();
  2624. affi_asel();
  2625. dessine_avion();
  2626. affi_indicateurs();
  2627. affi_switches();
  2628. affi_potars();
  2629. affi_radial_NAV1();
  2630. affi_radial_NAV2();
  2631. affi_Airport();
  2632. }
  2633.  
  2634.  
  2635. void affi_nop()
  2636. {
  2637. for(int8_t dy=-2; dy<3; dy++)
  2638. {
  2639. TFT480.drawLine(HA_x0-HA_w, HA_y0-HA_h +dy, HA_x0 +HA_w, HA_y0 +HA_h +dy, ROUGE);
  2640. TFT480.drawLine(HA_x0-HA_w, HA_y0+HA_h +dy, HA_x0 +HA_w, HA_y0 -HA_h +dy, ROUGE);
  2641. }
  2642.  
  2643. //TFT480.fillRect(0, 0, 239, 30, NOIR);
  2644. TFT480.setTextColor(BLANC, ROUGE);
  2645. TFT480.setFreeFont(FF18);
  2646. TFT480.drawString("No Data", HA_x0-40, HA_y0+30);
  2647. }
  2648.  
  2649.  
  2650.  
  2651.  
  2652. void init_affi_autopilot()
  2653. {
  2654.  
  2655. TFT480.setFreeFont(FF1);
  2656. TFT480.setTextColor(JAUNE, GRIS_AF);
  2657.  
  2658. // ALT
  2659.  
  2660. //TFT480.drawString("ALT", x_autopilot, 260, 1);
  2661. //TFT480.drawRoundRect(x_autopilot-4, 255, 45, 42, 5, BLANC);
  2662. }
  2663.  
  2664.  
  2665.  
  2666. void affi_autopilot()
  2667. {
  2668. // dans le petit cercle en bas à gauche :
  2669. // affiche HDG (flèche jaune), piste (rectangle bleu), VOR (Nav1, ligne verte)
  2670.  
  2671. uint16_t x0=70; // 70
  2672. uint16_t y0=248; // 255
  2673.  
  2674. TFT480.setFreeFont(FF1);
  2675.  
  2676. TFT480.fillRect(x0, y0+2, 70, 80, NOIR); // efface
  2677.  
  2678. TFT480.setTextColor(JAUNE, NOIR);
  2679. TFT480.drawString("HDG", x0, y0-18);
  2680. //TFT480.drawRoundRect(x0-4, 255, 45, 42, 5, BLANC);
  2681.  
  2682. TFT480.drawCircle(x0+35, y0+34, 30, BLANC);
  2683.  
  2684. String s1 =(String)hdg1;
  2685. TFT480.setTextColor(BLANC, NOIR);
  2686.  
  2687. TFT480.drawString(s1, x0+18, y0+35);
  2688.  
  2689. TFT480.setTextColor(BLANC, NOIR);
  2690. TFT480.drawString("N", x0+30, y0-5);
  2691.  
  2692. TFT480.setTextColor(BLANC, NOIR);
  2693. TFT480.drawString("S", x0+30, y0+60);
  2694.  
  2695. TFT480.setTextColor(BLANC, NOIR);
  2696. TFT480.drawString("E", x0+60, y0+27);
  2697. TFT480.drawString("W", x0, y0+27);
  2698.  
  2699. uint16_t x1,y1;
  2700.  
  2701.  
  2702. // flèche jaune = règlage HDG de l'autopilot
  2703. float angle1 = 90-hdg1;
  2704. affi_rayon2(x0+35, y0+34, 0, 30, angle1, JAUNE, 0); // tige de la flèche
  2705. affi_pointe(x0+35, y0+34, 30, angle1, JAUNE); // pointe triangulaire en bout de flèche
  2706.  
  2707. // rectangle bleu, très fin -> orientation ('radial') de l'axe de la piste
  2708. float angle2 = 90+ils_radial/100.0;
  2709. affi_rectangle_incline(x0+35, y0+34, 35, angle2, BLEU_CLAIR);
  2710.  
  2711. // trait vert -> radial du VOR (dont la fréquence radio est réglée dans Nav1)
  2712. float angle3 = 90+vor_actual/100.0;
  2713. //affi_rectangle_incline(x0+35, y0+34, 35, angle3, ROUGE);
  2714. affi_rayon2(x0+35, y0+34, -28, 28, -angle3, VERT, 0);
  2715.  
  2716.  
  2717.  
  2718. // ALTITUDE
  2719.  
  2720. // ce paramétrage permet de régler la valeur de 0 à 200 (soit 0 à 20000 pieds soit 6000m environ)
  2721. //pour aller plus haut on peut toujours utiliser l'interface de FG (touche F11...)
  2722.  
  2723. /*
  2724. String s2 =(String)asel1;
  2725. TFT480.setTextColor(ROSE, NOIR);
  2726. TFT480.fillRect(x_autopilot, 280, 40, 15, NOIR); // efface
  2727. TFT480.drawString(s2, x_autopilot, 278);
  2728. */
  2729. affi_asel();
  2730. affi_target_speed();
  2731.  
  2732. data_out(); // ** à commenter le cas échéant pour libérer le port série lors de la mise au point **
  2733.  
  2734. }
  2735.  
  2736.  
  2737. void traitement_switches()
  2738. {
  2739. // les switches en question sont situés sur le SW (panel des boutons)
  2740. // leurs valeurs sont tranmises par WiFi
  2741. // voir leur réception ici dans la fonction "setup()"
  2742. traiter_SW =0;
  2743. if(v_switches != memo_v_switches)
  2744. {
  2745. memo_v_switches = v_switches;
  2746. if ((v_switches & 1)==1)
  2747. {
  2748. if (hdg1>30) {hdg1 -=30;} else {hdg1+=330;} // la barre à tribord 30° !
  2749. }
  2750.  
  2751. if ((v_switches & 2)==2)
  2752. {
  2753. if (hdg1<330) {hdg1 +=30;} else {hdg1-=330 ;} // la barre à babord 30° !
  2754. }
  2755.  
  2756. if ((v_switches & 4)==4)
  2757. {
  2758. if (asel1<600) {asel1 +=10;} // consigne d'altitude +1000ft
  2759. }
  2760.  
  2761. if ((v_switches & 8)==8)
  2762. {
  2763. if (asel1>10) {asel1 -=10;} // consigne d'altitude -1000ft
  2764. }
  2765.  
  2766. if ((v_switches & 16)==16)
  2767. {
  2768. if (target_speed<160) {target_speed +=5;} // consigne de vitesse
  2769. else if ((target_speed>=160) && (target_speed<600)) {target_speed +=20;}
  2770. }
  2771.  
  2772. if ((v_switches & 32)==32)
  2773. {
  2774. if ((target_speed>160) && (target_speed<600)) {target_speed -=20;}
  2775. else if ((target_speed<=160) && (target_speed>90)) {target_speed -=5;}
  2776. }
  2777.  
  2778. if ((v_switches & 64)==64)
  2779. {
  2780. // toggle autoland
  2781. switch (autoland)
  2782. {
  2783. case 0:
  2784. {
  2785. memo_hdg1 = hdg1; // mémorise le cap avant de passer la main à l'autoland
  2786. autoland=1;
  2787. }
  2788. break;
  2789. case 1:
  2790. {
  2791. // si, suite à un enclenchement non correct de l'autoland (sur un mauvais sens du localizer en particulier) le cap a été boulversé
  2792. // on le remet à sa valeur mémorisée. Evite de devoir tourner le bouton pendant une heure avec l'avion qui part à l'aventure !
  2793. hdg1 = memo_hdg1;
  2794. autoland=0;
  2795. init_affi_HA();
  2796. asel1=30;
  2797. voyant_L.affiche(GRIS_FONCE);
  2798. voyant_G.affiche(GRIS_FONCE);
  2799.  
  2800. }
  2801. break;
  2802. }
  2803. }
  2804.  
  2805. if ((v_switches & 128)==128)
  2806. // HDG SYNC
  2807. {
  2808. hdg1 = cap;
  2809. }
  2810.  
  2811. }
  2812.  
  2813. if(v_switches_ND != memo_v_switches_ND)
  2814. {
  2815. memo_v_switches_ND = v_switches_ND;
  2816. if ((v_switches_ND & 1)==1)
  2817. {
  2818. TFT480.fillCircle(465, 310, 5, BLEU_CLAIR);
  2819. landing_light1=1;
  2820. landing_light2=1;
  2821.  
  2822. }
  2823. else
  2824. {
  2825. TFT480.fillCircle(465, 310, 5, NOIR);
  2826. landing_light1=0;
  2827. landing_light2=0;
  2828. }
  2829. }
  2830. }
  2831.  
  2832.  
  2833.  
  2834.  
  2835.  
  2836. void toutes_les_10s()
  2837. {
  2838.  
  2839.  
  2840. }
  2841.  
  2842.  
  2843.  
  2844. void toutes_les_1s()
  2845. {
  2846. nb_secondes++;
  2847.  
  2848. //// size_t write(uint8_t c);
  2849. //// size_t write(const uint8_t *buffer, size_t size);
  2850.  
  2851. if(nb_secondes>10)
  2852. {
  2853. nb_secondes=0;
  2854. toutes_les_10s();
  2855. }
  2856.  
  2857. dV =10*(vitesse - memo_vitesse);
  2858. memo_vitesse = vitesse;
  2859.  
  2860. auto_landing(); // ne sera effectif que si la variable autoland !=0; toutefois la fonction est toujours appelée afin d'actualiser les affichages
  2861.  
  2862. }
  2863.  
  2864. /** ==================================================================
  2865.  variables à gérer obligatoirement */
  2866.  
  2867. uint8_t TEST_AFFI=0;// =0 pour un fonctionnement normal; =1 pour tester les affichages et la fluidité
  2868.  
  2869. //le nombre de ports GPIO libres étant atteint, on va utiiser un switch unique pour deux fonctions :
  2870. uint8_t fonction_bt1 = 1; // 0=saisie écran ; 1=allumage feux d'atterrissage (landing_light)
  2871.  
  2872. /** ================================================================== */
  2873.  
  2874. uint16_t t=0; // temps -> rebouclera si dépassement
  2875. void loop()
  2876. {
  2877. //if (SerialBT.available()) { Serial.write(SerialBT.read()); }
  2878.  
  2879. //le bouton connecté à CET ESP32-ci est partagé entre deux fonctions, voir ci-dessus "variables à gérer obligatoirement"
  2880. bouton1_etat = digitalRead(bouton1);
  2881.  
  2882. if (bouton1_etat != memo_bouton1_etat)
  2883. {
  2884. memo_bouton1_etat = bouton1_etat;
  2885. if (bouton1_etat==0)
  2886. {
  2887. TFT480.fillCircle(450, 310, 5, VERT);
  2888.  
  2889.  
  2890. if (fonction_bt1 == 0) {write_TFT_on_SDcard(); }
  2891. if (fonction_bt1 == 1)
  2892. {
  2893. if (view_number == 0) {view_number = 1;} else {view_number =0;}
  2894. }
  2895. }
  2896. if (bouton1_etat==1)
  2897. {
  2898. TFT480.fillCircle(450, 310, 5, NOIR);
  2899. if (fonction_bt1==1)
  2900. {
  2901. ;
  2902. }
  2903. }
  2904. }
  2905.  
  2906. bouton2_etat = digitalRead(bouton2);
  2907.  
  2908. if (bouton2_etat != memo_bouton2_etat)
  2909. {
  2910. memo_bouton2_etat = bouton2_etat;
  2911. if (bouton2_etat==0)
  2912. {
  2913. mode_affi_hauteur = AAL;
  2914. affi_mode_affi_hauteur();
  2915. }
  2916. if (bouton2_etat==1)
  2917. {
  2918. mode_affi_hauteur = ASL;
  2919. affi_mode_affi_hauteur();
  2920. }
  2921. }
  2922.  
  2923. if (traiter_SW ==1)
  2924. // le positionnement de ce drapeau se fait dans l'interruption WiFi "server.on("/switch"..."
  2925. // définie dans le setup()
  2926. // la commande, en amont, provient de l'ESP n°3 qui gère les switches
  2927. {
  2928. traiter_SW =0;
  2929. traitement_switches();
  2930. }
  2931.  
  2932.  
  2933. temps_ecoule = micros() - memo_micros;
  2934. if (temps_ecoule >= 1E6) // (>=) et pas strictement égal (==) parce qu'alors on rate l'instant en question
  2935. {
  2936. memo_micros = micros();
  2937. toutes_les_1s();
  2938. }
  2939.  
  2940. if (dV > acceleration) {acceleration++;}
  2941. if (dV < acceleration) {acceleration--;}
  2942.  
  2943.  
  2944. //---------------------------------------------------------------------------------------
  2945. if(TEST_AFFI==1) // pour test des affichages:
  2946. {
  2947.  
  2948. // les valeurs de ces paramètres peuvent être modifiées afin de tester tel ou tel point particulier
  2949.  
  2950. vitesse = 100 - 100*cos(t/200.0);
  2951. //vitesse = 100;
  2952.  
  2953. altitude_GPS = 1000 - 800*cos(t/400.0);
  2954. vspeed = 80*sin(t/100.0);
  2955.  
  2956. tangage =20.0*sin(t/87.0);
  2957. roulis = 35.0*sin(t/35.0);
  2958.  
  2959. //cap =180.0+180.0*sin(t/300.0);
  2960. //vor_dst=27780+27780*sin(t/500.0) ;// test 400 000 nautiques max = 15km
  2961.  
  2962. vor_actual_deg= 45;// 100*(180 + 180.0*sin(t/250.0));
  2963.  
  2964. ils_dst=27780+27780*sin(t/500.0) ;// test 400 000 nautiques max = 15km
  2965. ils_radial=304.0 *100.0;
  2966.  
  2967. ils_actual_deg+=1.0;
  2968. if (ils_actual_deg >359) {ils_actual_deg=0;}
  2969. cap = ils_actual_deg -90;
  2970. if (cap <0) {cap+=360;}
  2971.  
  2972. data_ok=65535;
  2973. ils_glide= (int16_t) (3000 + 2000*sin(t/77.0) ); // soit 5°... 4°
  2974. ils_loc = 10E+3*sin(t/63.0); // soit -10°... +10°
  2975. gs_ok=1;
  2976.  
  2977. affichages();
  2978.  
  2979. t++;
  2980.  
  2981. TFT480.setTextColor(JAUNE, BLEU);
  2982. TFT480.setFreeFont(FF1);
  2983. TFT480.drawString("mode TEST", 0, 0);
  2984.  
  2985.  
  2986. if (dV > acceleration) {acceleration++;}
  2987. if (dV < acceleration) {acceleration--;}
  2988. delay(20);
  2989.  
  2990. }
  2991.  
  2992. //---------------------------------------------------------------------------------------
  2993. else // FONCTIONNEMENT NORMAL
  2994. {
  2995. compteur1+=1;
  2996. if (compteur1 >= 100) // tous les 1000 passages dans la boucle
  2997. {
  2998. compteur1=0;
  2999. affi_autopilot();
  3000. }
  3001.  
  3002. acquisitions();
  3003.  
  3004.  
  3005. /** ----------------------------------------------
  3006.  pour tester si data_ok à bien la valeur attendue, c.a.d si toutes les acquisitions sont effectuées
  3007.  ce qui est le cas lorsque le dialogue avec le serveur de protocole FG est correctement programmé
  3008.  sachant que ce ne sont pas les pièges qui manquent !
  3009.  Les 6 lignes de code qui suivent peuvent faire gagner une journée...
  3010.  Il suffit d'analyser la valeur affichée en binaire pour voir les bits qui restent à 0 -> problèmes (à priori de libellés)
  3011.  Il doit y avoir une correspondance stricte entre les noms de variables ici et celles émises par le fichier hardware4.xml
  3012. */
  3013. ////TFT480.setFreeFont(FM9);
  3014. ////TFT480.setTextColor(VERT, NOIR);
  3015. ////TFT480.drawString("d_sum=", 0, 0);
  3016. ////s2= (String) data_ok;
  3017. ////TFT480.fillRect(70, 0, 50, 30, TFT_BLACK);
  3018. ////TFT480.drawString(s2, 70, 0);
  3019. /** ---------------------------------------------- **/
  3020.  
  3021. if (data_ok == 65535)
  3022. // 32767 = 1+2+4+8+16+32+64+128+256+512+1024+2048+4096+8192+16384+32768 = 0b 11111111 11111111 = (2^16)-1 voir fonction "acquisitions()"
  3023. {
  3024. TFT480.fillCircle(435, 310, 5, VERT);
  3025. if (attente_data == 1)
  3026. {
  3027. attente_data=0;
  3028. TFT480.fillScreen(TFT_BLACK);
  3029. init_affi_HA();
  3030. init_affi_autopilot();
  3031. }
  3032.  
  3033. affichages();
  3034. data_ok=0;
  3035. }
  3036. else
  3037. {
  3038. TFT480.fillCircle(435, 310, 5, ROUGE);
  3039. if(attente_data==1)
  3040. {
  3041. affi_nop();
  3042. RAZ_variables();
  3043. affichages();
  3044. delay(100);
  3045. }
  3046.  
  3047. }
  3048.  
  3049. if ((vitesse > 100) && (altitude_GPS > 500)) {au_sol =0;}
  3050. }
  3051.  
  3052. //---------------------------------------------------------------------------------------
  3053.  
  3054. }
  3055.  
  3056.  
  3057. /** ***************************************************************************************
  3058. CLASS VOYANT // affiche un nombre ou un petit texte dans un rectangle
  3059. ainsi que (en plus petit) deux valeurs supplémentaires, par ex: les valeurs mini et maxi
  3060. ********************************************************************************************/
  3061.  
  3062. // Constructeur
  3063. VOYANT::VOYANT()
  3064. {
  3065.  
  3066. }
  3067.  
  3068.  
  3069.  
  3070. void VOYANT::init(uint16_t xi, uint16_t yi, uint16_t dxi, uint16_t dyi)
  3071. {
  3072. x0 = xi;
  3073. y0 = yi;
  3074. dx = dxi;
  3075. dy = dyi;
  3076.  
  3077. TFT480.setTextColor(BLANC, NOIR);
  3078. }
  3079.  
  3080.  
  3081.  
  3082. void VOYANT::affiche(uint16_t couleur_i)
  3083. {
  3084. TFT480.fillRoundRect(x0, y0, dx, dy, 3, couleur_i);
  3085. if (caract !=' ')
  3086. {
  3087. TFT480.setTextColor(BLANC);
  3088. TFT480.setFreeFont(FM9);
  3089. TFT480.drawChar(x0+8, y0+14, caract, couleur_caract, couleur_i, 1);
  3090. }
  3091. }
  3092.  
  3093.  
  3094.  
  3095.  
  3096. /**
  3097. -----------------------------------------------------------------------------------------------------------
  3098.  
  3099.   ci-dessous contenu du fichier (pour Linux): "/usr/share/games/protocol/hardware4.xml" qui va bien pour CE programme
  3100.  
  3101.   IMPORTANT : Lorsque je fais évoluer le programme principal (ci-dessus) je modifie également (le cas échéant) le fichier hardware4.xml (ci-dessous)
  3102.   je ne numérote pas le fichier ci-dessous. Donc pensez à toujours utiliser celui qui est présent ici
  3103.   (en le recopiant au bon endroit, ici ce n'est qu'un commentaire non fonctionnel en tant que tel).
  3104.   en effet les variables transmises par FG doivent correspondre exactement à ce qu'attend l'ESP32, voir la fonction "void acquisitions()"
  3105.  
  3106.  
  3107.   FG doit être lancé avec les paramètres suivants :
  3108.  
  3109. --generic=serial,in,2,/dev/ttyUSB0,9600,hardware4
  3110. --generic=serial,out,2,/dev/ttyUSB0,9600,hardware4
  3111.  
  3112. IMPORTANT :
  3113. Il faut ajouter ces DEUX lignes dans un lanceur (tel que "FGo!") pour obtenir un fonctionnement bidirectionnel
  3114.  
  3115. Remarques :
  3116.   - le nom du fichier "hardware4.xml" peut être autre chose pourvu que le paramètre de lancement corresponde exactement au nom choisi
  3117.   - le fichier en question n'existe pas par défaut dans le répertoire "/usr/share/games/protocol/", il faut le créer.
  3118.  
  3119.  
  3120. Astuce : pour gagner du temps au décollage, on peut lancer FG avec les options en ligne de commande suivantes (en plus de celles vues plus haut):
  3121.  
  3122. --prop:/autopilot/locks/heading=HDG
  3123. --prop:/autopilot/locks/altitude=ALT
  3124. --prop:/autopilot/locks/speed-ctrl=true
  3125. --prop:/autopilot/settings/target-speed-kt=160
  3126.  
  3127. ce qui configure l'autopitot correctement en adéquation avec notre PFD
  3128. les deux premières lignes en particulier permette de piloter l'avion depuis le PFD en tournant les encoreurs rotatifs du cap et de l'altitude
  3129. elles permetttent également de contrôler l'avion en mode autopilot et landing auto ILS (guidage glide et localizer)
  3130.  
  3131. -----------------------------------------------------------------------------------------------------------
  3132.  
  3133. <?xml version="1.0"?>
  3134.  
  3135. <PropertyList>
  3136.  
  3137. <generic>
  3138.   <output>
  3139.   <binary_mode>false</binary_mode>
  3140.   <line_separator>\n</line_separator>
  3141.   <var_separator>\n</var_separator>
  3142.   <preamble></preamble>
  3143.   <postamble></postamble>
  3144.  
  3145.   <chunk>
  3146.   <name>Altitude</name>
  3147.   <node>/instrumentation/gps/indicated-altitude-ft</node>
  3148.   <type>integer</type>
  3149.  
  3150.   <factor>1000</factor>
  3151.   <format>alti=%i</format>
  3152.   </chunk>
  3153.  
  3154. <chunk>
  3155. <name>ground_elevation</name>
  3156. <type>integer</type>
  3157. <node>/position/ground-elev-ft</node>
  3158. <format>gnd_elv=%i</format>
  3159. </chunk>
  3160.  
  3161.  
  3162.   <chunk>
  3163.   <name>Speed</name>
  3164.   <node>/velocities/airspeed-kt</node>
  3165.   <type>integer</type>
  3166.   <format>speed=%i</format>
  3167.   </chunk>
  3168.  
  3169.   <chunk>
  3170.   <name>Tangage</name>
  3171.   <node>/orientation/pitch-deg</node>
  3172.   <type>integer</type>
  3173.   <format>pitch=%i</format>
  3174.   </chunk>
  3175.  
  3176.   <chunk>
  3177.   <name>Roulis</name>
  3178.   <node>/orientation/roll-deg</node>
  3179.   <type>integer</type>
  3180.   <format>roll=%i</format>
  3181.   </chunk>
  3182.  
  3183.   <chunk>
  3184.   <name>Cap</name>
  3185.   <node>/orientation/heading-deg</node>
  3186.   <type>integer</type>
  3187.   <format>heading=%i</format>
  3188.   </chunk>
  3189.  
  3190.   <chunk>
  3191.   <name>Vertical_speed</name>
  3192.   <node>/velocities/vertical-speed-fps</node>
  3193.   <type>integer</type>
  3194.   <format>vspeed=%i</format>
  3195.   </chunk>
  3196.  
  3197.   <chunk>
  3198. <name>vor_frq</name>
  3199. <type>integer</type>
  3200. <node>/instrumentation/nav/frequencies/selected-mhz</node>
  3201. <factor>1000</factor>
  3202. <format>vor_frq=%i</format>
  3203. </chunk>
  3204.  
  3205.  
  3206.   <chunk>
  3207.   <name>vor_dst</name>
  3208.   <node>/instrumentation/nav/nav-distance</node>
  3209.   <type>integer</type>
  3210.   <format>vor_dst=%i</format>
  3211.   </chunk>
  3212.  
  3213.  
  3214. <chunk>
  3215. <name>ils_dst</name>
  3216. <type>integer</type>
  3217. <node>/instrumentation/nav[1]/nav-distance</node>
  3218. <format>ils_dst=%i</format>
  3219. </chunk>
  3220.  
  3221.  
  3222. <chunk>
  3223. <name>ils_loc</name>
  3224. <type>integer</type>
  3225. <node>/instrumentation/nav[1]/heading-needle-deflection</node>
  3226. <factor>1000</factor>
  3227. <format>ils_loc=%i</format>
  3228. </chunk>
  3229.  
  3230.  
  3231. <chunk>
  3232. <name>ils_glide</name>
  3233. <type>integer</type>
  3234. <node>/instrumentation/nav[1]/gs-direct-deg</node>
  3235. <factor>1000</factor>
  3236. <format>ils_glide=%i</format>
  3237. </chunk>
  3238.  
  3239.  
  3240. <chunk>
  3241. <name>GS_OK</name>
  3242. <type>integer</type>
  3243. <node>/instrumentation/nav[1]/gs-in-range</node>
  3244. <format>gs_ok=%i</format>
  3245. </chunk>
  3246.  
  3247.  
  3248. <chunk>
  3249. <name>Nav1_actual</name>
  3250. <type>integer</type>
  3251. <node>/instrumentation/nav/radials/actual-deg</node>
  3252. <factor>100</factor>
  3253. <format>vor_actual=%i</format>
  3254. </chunk>
  3255.  
  3256.  
  3257. <chunk>
  3258. <name>ils_radial</name>
  3259. <type>integer</type>
  3260. <node>/instrumentation/nav[1]/radials/target-radial-deg</node>
  3261. <factor>100</factor>
  3262. <format>ils_radial=%i</format>
  3263. </chunk>
  3264.  
  3265. <chunk>
  3266. <name>ils_actual</name>
  3267. <type>integer</type>
  3268. <node>/instrumentation/nav[1]/radials/actual-deg</node>
  3269. <factor>100</factor>
  3270. <format>ils_actual=%i</format>
  3271. </chunk>
  3272.  
  3273.  
  3274.  
  3275.   </output>
  3276.  
  3277.  
  3278.   <input>