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