Récepteur radio à TEF6686 et carte CYD

Ecran tactile. Utilisation simple. Code source extrêmement simple pour VisualCode & PlatformIO; Je suis reparti directement du PDF de NXP. Bandes SW, FM, aviation civile.
Album :

1 Description

On trouve sur Internet de nombreuses réalisations basées sur ce module récepteur TEF6686.Certaines réalisations sont commerciales, d'autres pas. Toutefois elles reprennent la plupart du temps le code source très complet et performant de PE5PVB disponible sur github.

Je me suis donc penché dans un premier temps sur ce code source. Et là.. Panique ! Des centaines de conditions "if, else, else if, break..." imbriquées rendant la compréhension très délicate, du moins pour moi. Je ne critique pas ce code, je dis juste qu'il ne me convient pas.

Je suis donc reparti de zéro : le document "User_Manual_TEF6686.pdf" de NXP Semiconductors. Bon d'accord il est caviardé d'un grand "CONFIDENTIAL" en travers des 100 pages, mais vu qu'il est largement divulgué sur Internet... Et puis le fait de comprendre comment ça marche leur fera sans doute vendre des modules... Sachant que ledit module est déjà présent dans des milliers d'autoradios.

Mon code source fait environ 180 ko contre environ 9 Mo pour certains autres plus complets.

Pour ma part, j'ai permis l'accès de toutes les fonctions de gestion de fréquences avec l'écran tactile de la carte CYD, le plus simplement possible :
  • Choix d'une station parmis 8 près enregistrées ("presets") dans le code source.
  • Saisie de la fréquence directement par le pavé numérique.
  • Mise en mémoire FLASH (SPIFFS)) de la fréquence en cours (100 freq pour SW, 100 freq pour FM, et 100 freq pour la bande aviation).
  • Sélection des station en FLASH (SPIFFS)) par les boutons (+) et (-).
  • Sélection de la bande de fréquence par trois boutons SW, FM, AIR.
  • Modification de la fréquence en sélectionnant le digit par les petits boutons situés au dessus des chiffres, puis boutons (+) et (+).
  • Fonction Scanner (parcours auto des fréquences et arrêt si niveau (réglable) atteint, et reprise du scan auto (utile pour la bande aviation).
  • Fonctions "Mute" (pour répondre au téléphone...) et "Sleep".. Cette fonction Sleep réduit la consommation de la carte CYD à quelques uA et réduit aussi le bruit HF de la carte, tout en laissant fonctionner le module. Pour réveiller l'ESP32 il faut reseter. (à voir...)
  • Vu-mètre du niveau de la porteuse HF, et bar-graphe sur le signal BF.
  • Choix de la couleur du fond d'écran : parmi 8 présets.
Bandes de réception :
  • SW : 1500kHz .. 28 MHz
  • FM : 88 MHz .. 108 MHz
  • AIR: 108 MHz .. 138 MHz (avec convertisseur 110 MHz en entrée antenne)
Remarque : 138 MHz = 28 + 110 MHz. Pour aller plus haut, il faut utiliser un autre convertisseur (120 MHz...) et modifier le code (affichage) en conséquence... Les limites des fréquences sont celles imposées par le module TEF6686 lui même. Mais je compte bien ne pas en rester là, et étudier un autre module...

2 VIDEO bande FM



Réception bande FM

Réception bande FM

3 VIDEO bande aviation civile



Réception AIR BAND : Scan de fréquences de la bande aviation civile (fréquences préalablement enregistrées). La détection et le maintien des fréquences actives se fait au choix par le niveau VHF (Level) ou par le rapport signal sur bruit (SNR). Un convertisseur VHF - SW doit être utilisé sur l'entrée antenne (-110 MHz).

4 Le schéma :

La carte ESP32 Cheap Yellow Display Board (CYD) est celle sérigraphiée ESP-322432S028 avec un afficheur 2.8 pouces 320x240PX; C'est la plus courante. Il en existe d'autres modèles pour lesquels il faudrait modifier cetaines parties du code source...

5 Détail connecteurs de la carte

La numérotation en vert est arbitraire (perso). En revanche l'attribution des ports (en noir) est exacte. On remarque que le GPIO22 est présent sur les deux connecteurs. En conséquence, si on retire les trois alims, nous n'avons pas cinq ports mais seulement quatre à notre disposition (GPIO 21, 22, 27, 35).

J'utilise les GPIO 22 et 27 du connecteur CN1 pour communiquer avec le module TEF6686 (SCL et SDA). Quant au GPIO21, je lis dans la documentation de la carte CYD qu'il est employé en interne pour piloter le backlight de l'afficheur. Il ne reste donc plus que le GPIO 35 de disponible. Je compte l'utiliser pour mesurer la tension de la batterie (en amont du régulateur LM7805) par l'intermédiaire d'un diviseur à résistances, pour éviter la décharge profonde de cette batterie LiPo.

6 Le bus SPI 3V3 et l'alimentation des modules en 5V

Sur la carte CYD il y a deux régulateurs 3v3

Et un sur le module TEF6686 (dont le blindage a été dessoudé pour la photo.
Remarque: Ce n'est pas MON module, photo trouvée sur Internet)

L'alimentation de la carte jaune CYD se fait en 5V. Celle du module TEF6686 se fait en 5V également. Toutefois les puces présentes sur ces cartes, à savoir l'ESP32 et la puce TEF6686 sont alimentées en 3v3. En effet, les cartes sont équipées chacune d'un régulateur 3V3 lowdrop (LD1117). Et donc le bus SPI peut se passer d'un adaptateur de tension 3v3-5V.

7 Le module TEF6686 de chez MPX

.

8 Le module ampli BF

Voir le lien plus bas.

9 Les mini Haut Parleurs

Voir le lien plus bas...

10 C'est dans la boite !

Les découpes dans le couvercle pour l'afficheur de la carte CYD et le HP ont été faites à la CNC. Je vais rajouter un joli bouton sur le potentiomètre de l'ampli BF.

11 Disposition des éléments

La face interne du couvercle est bien remplie.

La boite elle même contient la batterie (immobilisée par une pièce faite à l'imprimante 3D) + connecteur de charge + fusible (sous gaine thermo transparente).

12 Fichier source main.cpp :

CODE SOURCE en C++
  1. /* ************************************************************************************
  2. Radio TEF6686 par Silicium628
  3. pour la carte CYD (Cheap Yellow Display) ESP32 Wroom + afficheur 2.8" TFT 240x320
  4.  
  5. Cette version utilise la mémoire SPIFFS; Voir:
  6. -le dossier 'data' contenant les fichiers nécessaires
  7. -le fichier 'platformio.ini' qui doit contenir la ligne 'board_build.partitions = perso4.csv'
  8. -le fichier 'perso4.csv' (def des partitions) qui doit se trouver à côté du fichier platformio.ini
  9. -les liens au bas de l'article sur mon site 'silicium628.fr'
  10.  
  11. Note :
  12. -le dossier 'data' doit se trouver dans le dossier qui contient le fichier 'platformio.ini'
  13. -les fichiers contenus dans 'data' sont à charger dans la mémoire flash de l'ESP
  14. avec l'outil 'Upload FIlsystem Image' de platformio (cliquer sur l'icone "Alien" à gauche)
  15. ************************************************************************************ */
  16.  
  17. // REMARQUES:
  18. // 1) lorsque la carte est connectée sur un bus USB de l'ordinateur,
  19. // un terminal série tel que CuteCom affichera beaucoup de choses en temps réel.
  20. // 2) Pour s'y retrouver dans le code, le plus simple est de partir de la fonction 'loop()' qui appelle les autres
  21. // 3) pour reconfigurer les couleurs de fond, voir la methode 'void PRESET_PAD::set_couleurs()'
  22.  
  23. #include <Arduino.h>
  24.  
  25. String version = "2.0.34"; // (avec SPIFFS)
  26.  
  27. #include "main.h"
  28. #include "constantes_628.h"
  29. #include "DSP_INIT_628.h"
  30. #include "driverTEF6686_628.h"
  31. #include <Free_Fonts.h>
  32.  
  33. #include <SPIFFS.h>
  34. #include "FS.h"
  35.  
  36. #include "Wire.h"
  37.  
  38. #include <stdint.h>
  39.  
  40. #include "TFT_eSPI.h" // Hardware-specific library
  41. #include "SPI.h"
  42. #include "Digit_Font.h"
  43. #include <XPT2046_Touchscreen.h>
  44.  
  45. #define SPI_READ_FREQUENCY 16000000
  46.  
  47.  
  48. #define bande_SW (frequence > 1500) && (frequence < 28000)
  49. #define bande_interdite1 (frequence > 28000) && (frequence < 88000)
  50. #define bande_interdite2 (frequence > 108000) && (frequence < 118000)
  51. #define bande_FM (frequence >= 88000) && (frequence < 108000)
  52. #define bande_AIR (frequence >= 118000) && (frequence < 138000)
  53.  
  54. #define XPT2046_IRQ 36
  55. #define XPT2046_MOSI 32
  56. #define XPT2046_MISO 39
  57. #define XPT2046_CLK 25
  58. #define XPT2046_CS 33
  59.  
  60. //sur le connecteur CN1 de la carte CYD sérigraphiée 'ESP32-2432S028';
  61. //attention: ces valeurs ne sont pas celles par défaut pour SDA et SCL
  62. const int GPIO_SDA = 27;
  63. const int GPIO_SCL = 22;
  64.  
  65. const int analogPin = 35;
  66.  
  67. #define High_16bto8b(a) ((uint8_t)((a) >> 8))
  68. #define Low_16bto8b(a) ((uint8_t)(a ))
  69. #define Convert8bto16b(a) ((uint16_t)(((uint16_t)(*(a))) << 8 |((uint16_t)(*(a+1)))))
  70.  
  71.  
  72. SPIClass mySpi = SPIClass(VSPI);
  73. XPT2046_Touchscreen ts(XPT2046_CS, XPT2046_IRQ);
  74.  
  75. TFT_eSPI TFT = TFT_eSPI(); // Configurer le fichier User_Setup.h de la bibliothèque TFT_eSPI au préalable
  76.  
  77. TFT_eSprite sprite_frq = TFT_eSprite(&TFT);
  78. TFT_eSprite sprite_ligne1 = TFT_eSprite(&TFT);
  79.  
  80.  
  81. const int _DX = 320;
  82. const int _DY = 240;
  83.  
  84. struct ETALON_TS // etalon touch screen
  85. {
  86. int16_t x0;
  87. int16_t dx;
  88. int16_t y0;
  89. int16_t dy;
  90. };
  91.  
  92. ETALON_TS eTS;
  93.  
  94. uint16_t x_touch, y_touch;
  95.  
  96. float raddeg = M_PI/180.0;
  97. float deg_to_rad = 2.0 * M_PI /360.0;
  98.  
  99. //***************************************************************************
  100. //char var_array32[10];// 10 char + zero terminal - pour envoi par WiFi (because 2^32 -1 = 4294967295 -> 10 caractères)
  101. // =====================================================================
  102.  
  103.  
  104. boolean test_touch_screen = false; // mettre true pour activer le test (qui est une boucle infinie au démarrage...)
  105. // pour étalonner, voir au tout début de la fonction 'init_variables_globales()'
  106.  
  107. uint16_t compteur1 = 0;
  108. uint16_t compteur2 = 0;
  109. uint16_t compteur3 = 0;
  110.  
  111.  
  112. uint32_t frequence=10000;
  113. uint32_t saut_freq;
  114. uint16_t seuil = 50;
  115. uint16_t memo_seuil = 50;
  116. //uint32_t image_SPIFFS[300]; // permet le tri en RAM des fréquences sans toucher à l'SPIFFS
  117.  
  118. GROUPE_FREQUENCES groupe_SW;
  119. GROUPE_FREQUENCES groupe_FM;
  120. GROUPE_FREQUENCES groupe_AIR;
  121. GROUPE_FREQUENCES groupe_SCAN;
  122.  
  123. uint32_t frq_preset_SW[8]; // 8 fréquences attribuées aux boutons [preset1] à [preset8] soit 8x4=32 octets
  124. uint32_t frq_preset_FM[8]; // 8 fréquences attribuées aux boutons [preset1] à [preset8] soit 8x4=32 octets
  125. uint32_t frq_preset_AIR[8];// 8 fréquences attribuées aux boutons [preset1] à [preset8] soit 8x4=32 octets total 32*3 = 96 octets
  126.  
  127. uint32_t memo_frequence_scan;
  128. uint16_t frq_preset_adr_0;
  129. String frequence_txt = "";
  130.  
  131. TOUCH_BOUTON bt_info;
  132. TOUCH_BOUTON bt_sleep;
  133. TOUCH_BOUTON bt_TEST;
  134.  
  135. TOUCH_BOUTON bt_mode_FRQ, bt_mode_MEM;
  136. TOUCH_BOUTON bt_plus, bt_moins;
  137.  
  138. TOUCH_BOUTON bt_SPIFFS_RAZ, bt_SPIFFS_write, bt_erase_1F, bt_SPIFFS_LST;
  139. TOUCH_BOUTON bt_1, bt_2, bt_3, bt_4, bt_5, bt_6; // au dessus des chiffres de la fréquence
  140.  
  141. TOUCH_BOUTON bt_affi_saisie_couleur;
  142. TOUCH_BOUTON bt_coul_to_SPIFFS;
  143.  
  144. TOUCH_BOUTON bt_scan_frq, bt_scan_air;
  145.  
  146. TOUCH_BOUTON bt_RST_affi; // "ok"
  147. //TOUCH_BOUTON bt_close1; // "x"
  148.  
  149. TOUCH_BOUTON bt_LEV, bt_SNR, bt_re_scan, bt_scan_suivant;
  150. TOUCH_BOUTON bt_seuil_plus, bt_seuil_moins;
  151.  
  152. // ---------- numPad ------------
  153. TOUCH_BOUTON bt_num0, bt_num1, bt_num2, bt_num3, bt_num4, bt_num5, bt_num6, bt_num7, bt_num8, bt_num9;
  154. NUM_PAD numPad1;
  155.  
  156. // ---------- presetPad1 ------------
  157. PRESET_PAD presetPad1;
  158.  
  159. // -------------------------------
  160. TOUCH_BOUTON bt_SW, bt_FM, bt_AIR, bt_SCN;
  161. TOUCH_BOUTON bt_mute;
  162. TOUCH_BOUTON bt_reset;
  163. TOUCH_BOUTON bt_stop_scan;
  164.  
  165. TOUCH_BOUTON bt_set; // attribtion d'une fréquence à un des 8 boutons preset
  166. TOUCH_BOUTON bt_annuler; // "x"
  167. TOUCH_BOUTON bt_close; // "x"
  168.  
  169. boolean mute;
  170. boolean vu_metre_actif;
  171.  
  172. enum MODE_AFFI {COUL, NORMAL, SCAN_F, SCAN_M, SET_F_PRESET}; //[couleur], [normal], [scan], [set 1F pour 1Bt]
  173. MODE_AFFI mode_affi;
  174.  
  175. enum MODE_SELECT {_FRQ=0, _MEM=1} mode_s; // mode de mofif fréquence, en tapant les chiffres /ou en mémoire
  176.  
  177. enum MODUL {AM, WFM};
  178. MODUL modulation_active;
  179.  
  180. enum BANDE {SW, FM, AIR, SCN}; //fréquences;
  181. BANDE bande_active;
  182.  
  183. enum GRP_ACT {gSW, gFM, gAIR, gSCN}; // groupes mémoire SW, FM, AIR, SCN; le grp SCN mémorise le résultat d'un scan FREQUENCE
  184. GRP_ACT groupe_actif;
  185.  
  186. enum MODE_SCAN {FREQUENCE, MEMOIRE};
  187. MODE_SCAN mode_scan;
  188.  
  189. enum MODE_SEUIL {LEV, SNR}; // level ou signal/bruit
  190. MODE_SEUIL mode_seuil;
  191.  
  192. uint16_t FRQ_x0;
  193. uint16_t FRQ_y0;
  194.  
  195. uint16_t x0_box_SPIFFS;
  196. uint16_t y0_box_SPIFFS;
  197.  
  198. uint16_t x0_box_PRESET;
  199. uint16_t y0_box_PRESET;
  200.  
  201. uint16_t x0_box_GROUPE; // SW - FM - AIR
  202. uint16_t y0_box_GROUPE;
  203.  
  204. uint16_t x0_box_boutons_scan;
  205. uint16_t y0_box_boutons_scan;
  206.  
  207. uint16_t x0_box_SCAN; // grande surface d'affichage
  208. uint16_t y0_box_SCAN;
  209. uint16_t dx_box_SCAN;
  210. uint16_t dy_box_SCAN;
  211.  
  212. uint16_t x0_numPad;
  213. uint16_t y0_numPad;
  214.  
  215. uint16_t x0_vu_metre;
  216. uint16_t y0_vu_metre;
  217.  
  218. uint16_t x0_box_info1;
  219. uint16_t y0_box_info1;
  220.  
  221. uint16_t x0_box_info2 = x0_vu_metre;
  222. uint16_t y0_box_info2 = y0_vu_metre;
  223. uint16_t dx_box_info2;
  224. uint16_t dy_box_info2;
  225.  
  226. uint16_t x0_saisie;
  227. uint16_t y0_saisie;
  228.  
  229. uint16_t x0_choix_couleur;
  230. uint16_t y0_choix_couleur;
  231.  
  232. uint8_t n_appui; // incrémenté à chaque appui sur une touche du numPad numérique
  233. uint32_t total_saisi;
  234.  
  235.  
  236. uint16_t status;
  237. int16_t level;
  238. uint16_t usn;
  239. uint16_t wam;
  240. int16_t offset;
  241. uint16_t bandwidth;
  242. uint16_t mod;
  243. int8_t snr;
  244.  
  245. uint16_t A_block;
  246. uint16_t B_block;
  247. uint16_t C_block;
  248. uint16_t D_block;
  249. uint16_t dec_error;
  250.  
  251. float position_aiguille; // vu-metre
  252. float valeur_affi;
  253. float memo_valeur_affi;
  254. float ltx; // aiguille
  255. uint16_t osx;
  256. uint16_t osy;
  257.  
  258. uint16_t couleur_traits = GRIS_5;
  259. uint16_t JAUNE_chiffres = 65504;
  260. uint16_t VERT_chiffres = 2016;
  261.  
  262. uint8_t cR = 0;
  263. uint8_t cG = 0;
  264. uint8_t cB = 0;
  265. uint16_t couleur_fond_ecran = 0;
  266.  
  267.  
  268.  
  269. float degTOrad(float angle)
  270. {
  271. return (angle * M_PI / 180.0);
  272. }
  273.  
  274.  
  275. uint8_t decToBcd( int val )
  276. {
  277. return (uint8_t) ((val / 10 * 16) + (val % 10));
  278. }
  279.  
  280.  
  281. uint16_t Color_To_565(uint8_t r, uint8_t g, uint8_t b)
  282. {
  283. return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
  284. }
  285.  
  286.  
  287. void RGB565_to_888(uint16_t color565, uint8_t *R, uint8_t *G, uint8_t *B)
  288. {
  289. *R=(color565 & 0xF800) >> 8;
  290. *G=(color565 & 0x7E0) >> 3;
  291. *B=(color565 & 0x1F) << 3 ;
  292. }
  293.  
  294.  
  295.  
  296. void init_variables_globales()
  297. // je ne les initialise pas lors de leur déclaration sinon lors d'un reset logiciel (appel de la fonction 'setup()'
  298. // par le boouton 'RST') elles ne seraient pas réinitialisées
  299. {
  300. // étalonnage touch screen
  301. eTS.x0 = -30; eTS.y0 = -30;
  302. eTS.dx = 11; eTS.dy = 14;
  303.  
  304. mode_affi = NORMAL;
  305. bande_active = FM;
  306. modulation_active = WFM;
  307. mode_s = _MEM;
  308. mode_scan = FREQUENCE;
  309. mode_seuil = LEV;
  310. mute = false;
  311. vu_metre_actif = true;
  312.  
  313. FRQ_x0 = 50; FRQ_y0 = 30;
  314. x0_box_SPIFFS = 2; y0_box_SPIFFS = 150;
  315. x0_box_PRESET =2; y0_box_PRESET =87;
  316. x0_box_GROUPE = 205; y0_box_GROUPE = 115;
  317. x0_box_boutons_scan = 2; y0_box_boutons_scan = 105;
  318.  
  319. // grande surface d'affichage
  320. x0_box_SCAN = 2; y0_box_SCAN = 90;
  321. dx_box_SCAN = 315; dy_box_SCAN = 148;
  322.  
  323. x0_numPad = 70; y0_numPad = 115;
  324.  
  325. x0_vu_metre = 170; y0_vu_metre = 145;
  326.  
  327. x0_box_info1 = 71; y0_box_info1 = 220;
  328.  
  329. x0_box_info2 = x0_vu_metre; y0_box_info2 = y0_vu_metre;
  330. dx_box_info2 = 140; dy_box_info2 = 70;
  331.  
  332. x0_saisie = 3; y0_saisie = 0;
  333. x0_choix_couleur = 170; y0_choix_couleur = 145;
  334.  
  335. n_appui = 0; // incrémenté à chaque appui sur une touche du numPad numérique
  336. total_saisi = 0;
  337.  
  338. position_aiguille = 0; // vu-metre
  339. valeur_affi = 0;
  340. memo_valeur_affi = 0;
  341. ltx = 0; // aiguille
  342. osx = x0_vu_metre;
  343. osy = y0_vu_metre;
  344. }
  345.  
  346.  
  347. //uint16_t bmp_offset = 0;
  348. uint16_t bmp_width;
  349. uint16_t bmp_heigh;
  350.  
  351.  
  352.  
  353.  
  354. void draw_bmp565(uint16_t x0, uint16_t y0, uint8_t sens, File* fp)
  355. {
  356. uint16_t i,j;
  357. uint16_t y1;
  358. uint8_t bmp_data[2]={0};
  359. uint16_t bmp_color[2];
  360.  
  361. fp->seek(0);
  362. for(i=0; i<bmp_heigh; i++)
  363. {
  364. for(j=0; j<(bmp_width); j++)
  365. {
  366. fp->read(bmp_data, 2); // lit les 2 octets constituant la valeur rgb565 et les place dans bmp_data[]
  367. if (sens == 0) {y1 = y0+bmp_heigh-i;}
  368. else {y1 = y0+i;}
  369. TFT.drawPixel(x0+j, y1, bmp_data[0] + (bmp_data[1] << 8) );
  370. }
  371. }
  372. }
  373.  
  374.  
  375. void affiche_index_frq() // 6 petits boutons juste au dessus de chaque chiffre pour indiquer celui à modifier
  376. {
  377. int x = FRQ_x0 +15;
  378. int y = FRQ_y0 - 5;
  379. uint16_t c1 = NOIR;
  380. uint16_t c2 = VERT;
  381.  
  382. bt_1.init(x, y, 20, 5, 0); bt_1.affiche(c1, c2, 1); x+=31;
  383. bt_2.init(x, y, 20, 5, 0); bt_2.affiche(c1, c2, 1); x+=31;
  384. bt_3.init(x, y, 20, 5, 0); bt_3.affiche(c1, c2, 1); x+=46;
  385. bt_4.init(x, y, 20, 5, 0); bt_4.affiche(c1, c2, 1); x+=31;
  386. bt_5.init(x, y, 20, 5, 0); bt_5.affiche(c1, c2, 1); x+=31;
  387. bt_6.init(x, y, 20, 5, 0); bt_6.affiche(c1, c2, 1);
  388. }
  389.  
  390.  
  391. void efface_index_frq() // les 6 petits boutons
  392. {
  393. int x = FRQ_x0 +15;
  394. int y = FRQ_y0 - 5;
  395.  
  396. TFT.fillRect(x, y, 190, 5, couleur_fond_ecran);
  397. }
  398.  
  399.  
  400.  
  401.  
  402. void init_boutons_Plus_Moins()// boutons '<' et '>'
  403. {
  404. int x0 = 240;
  405. int y0 = 90;
  406.  
  407. String s1, s2;
  408.  
  409. uint16_t c1 = GRIS_6;
  410. uint16_t c2 = JAUNE;
  411.  
  412. if(mode_s == _FRQ) { s1 = " -"; s2 = " +"; }
  413. if(mode_s == _MEM) { s1 = " <"; s2 = " >"; }
  414.  
  415. bt_moins.init(x0, y0, 30, 15, 1);
  416. bt_moins.cliked = false;
  417. bt_moins.s = s1;
  418.  
  419. bt_plus.init(x0+35, y0, 30, 15, 1);
  420. bt_plus.cliked = false;
  421. bt_plus.s = s2;
  422. }
  423.  
  424.  
  425. void init_boutons_GROUPE() // groupe de fréquence (SW - FM - AIR - SCAN)
  426. {
  427. uint16_t x = x0_box_GROUPE+4;
  428. uint16_t y = y0_box_GROUPE+5;
  429.  
  430. TFT.setFreeFont(FF0);
  431.  
  432. bt_SW.init(x, y, 20, 15, 3);
  433. bt_SW.cliked = false;
  434. bt_SW.selected = false;
  435. bt_SW.s="SW";
  436. x+=25;
  437.  
  438. bt_FM.init(x, y, 20, 15, 3);
  439. bt_FM.cliked = false;
  440. bt_FM.selected = false;
  441. bt_FM.s="FM";
  442. x+=25;
  443.  
  444. bt_AIR.init(x, y, 22, 15, 3);
  445. bt_AIR.cliked = false;
  446. bt_AIR.selected = false;
  447. bt_AIR.s="AIR";
  448. x+=27;
  449.  
  450. bt_SCN.init(x, y, 20, 15, 3);
  451. bt_SCN.cliked = false;
  452. bt_SCN.selected = false;
  453. bt_SCN.s="SC";
  454.  
  455. }
  456.  
  457. void init_1_bouton(uint16_t xi, uint16_t yi, uint8_t dx, uint8_t dy, String si, TOUCH_BOUTON *bouton_i)
  458. {
  459. uint16_t c1 = GRIS_5;
  460. uint16_t c2 = BLANC;
  461.  
  462. bouton_i->init(xi, yi, dx, dy, 3);
  463. bouton_i->cliked = false;
  464. bouton_i->selected = false;
  465. bouton_i->s = si;
  466. bouton_i->affiche(c1, c2, 1);
  467. }
  468.  
  469.  
  470. void init_boutons_MODE() // en haut à gauche
  471. {
  472. uint16_t c1 = NOIR;
  473. uint16_t c2 = VERT;
  474.  
  475. TFT.setFreeFont(FF0);
  476. TFT.setTextColor(GRIS_3, NOIR);
  477. TFT.drawString("mode", 6, 17);
  478.  
  479. TFT.drawFastVLine(45, 15, 72, couleur_traits);
  480.  
  481. bt_mode_FRQ.init(5, 35, 37, 20, 2);
  482. bt_mode_FRQ.selected = false;
  483. bt_mode_FRQ.s="FRQ";
  484. bt_mode_FRQ.affiche(c1, c2, 2);
  485.  
  486. bt_mode_MEM.init(5, 60, 37, 20, 2);
  487. bt_mode_MEM.selected = true;
  488. bt_mode_MEM.s="MEM";
  489. bt_mode_MEM.affiche(c1, c2, 2);
  490.  
  491. affiche_index_frq();
  492. }
  493.  
  494.  
  495.  
  496. void affiche_1_bt_RGB(TOUCH_BOUTON *bouton_i, uint16_t x, uint16_t y, uint8_t dx, uint16_t couleur, String s_i)
  497. {
  498. uint16_t c1 = couleur;
  499. uint16_t c2 = JAUNE;
  500.  
  501. bouton_i->init(x, y, dx, 14, 3);
  502. bouton_i->cliked = false;
  503. bouton_i->selected = false;
  504. bouton_i->s = s_i;
  505. bouton_i->affiche(c1, c2, 1);
  506. }
  507.  
  508.  
  509. void init_sprites()
  510. {
  511. sprite_frq.createSprite(220, 55);
  512. sprite_frq.loadFont(digitfont1);
  513. sprite_frq.setTextColor(JAUNE_2, NOIR);
  514. sprite_frq.setTextDatum(MR_DATUM); // alignement du texte
  515.  
  516. }
  517.  
  518.  
  519. void Tuner_Reset(void)
  520. {
  521. Wire.beginTransmission(0x64);
  522. Wire.write(0x1e);
  523. Wire.write(0x5a);
  524. Wire.write(0x01);
  525. Wire.write(0x5a);
  526. Wire.write(0x5a);
  527. Wire.endTransmission();
  528. }
  529.  
  530.  
  531. bool Tuner_Table_Write(const unsigned char *tab)
  532. {
  533. if (tab[1] == 0xff)
  534. {
  535. delay(tab[2]);
  536. return 1;
  537. }
  538. else { return Tuner_WriteBuffer((unsigned char *)&tab[1], tab[0]); }
  539. }
  540.  
  541.  
  542. void Tuner_Init(const unsigned char *table)
  543. {
  544. uint16_t r;
  545. const unsigned char *p = table;
  546.  
  547. for (uint16_t i = 0; i < sizeof(tuner_init_tab9216); i += (pgm_read_byte(p + i) + 1))
  548. {
  549. if (1 != (r = Tuner_Table_Write(p + i))) break;
  550. }
  551. }
  552.  
  553.  
  554. void Tune_Frequence(uint32_t F)
  555. {
  556. TFT.setFreeFont(FF0);
  557. TFT.setTextColor(BLEU, NOIR);
  558. String s1 = String(F);
  559. TFT.drawString(s1, 80, 2);
  560.  
  561. if (F == 1500)
  562. {
  563. efface_box_entete3();
  564. TFT.setTextColor(ROUGE, NOIR);
  565. TFT.drawString("MINIMUM ", 130, 2);
  566. }
  567.  
  568. if (bande_SW)
  569. {
  570. modulation_active = AM;
  571. Tune_Frequence_AM(F);
  572. efface_box_entete3();
  573. TFT.setTextColor(VERT, NOIR);
  574. TFT.drawString("SW ", 130, 2);
  575. }
  576.  
  577. if (bande_interdite1)
  578. {
  579. efface_box_entete3();
  580. TFT.setTextColor(ROUGE, NOIR);
  581. TFT.drawString("NON DISPONIBLE", 130, 2);
  582. }
  583.  
  584. if (bande_FM)
  585. {
  586. modulation_active = WFM;
  587. Tune_Frequence_FM(F/10);
  588. efface_box_entete3();
  589. TFT.setTextColor(VERT, NOIR);
  590. TFT.drawString("bande FM", 130, 2);
  591. }
  592.  
  593. if (bande_interdite2)
  594. {
  595. efface_box_entete3();
  596. TFT.setTextColor(ROUGE, NOIR);
  597. TFT.drawString("NON DISPONIBLE", 130, 2);
  598. }
  599.  
  600. if (bande_AIR)
  601. {
  602. modulation_active = AM;
  603. Tune_Frequence_AM(F-110000); // nécessite un convertisseur de fréquence 110MHz en entrée antenne
  604. efface_box_entete3();
  605. TFT.setTextColor(BLEU_CLAIR, NOIR);
  606. TFT.drawString("AIR BAND", 130, 2);
  607. }
  608.  
  609. if (F == 138000)
  610. {
  611. efface_box_entete3();
  612. TFT.setTextColor(ROUGE, NOIR);
  613. TFT.drawString("F MAX ", 130, 2);
  614. }
  615. }
  616.  
  617.  
  618. void load_GRP_FREQ_SPIFFS() // -> to RAM
  619. {
  620. Serial.println("--- Frequences lues en SPIFFS ---------------");
  621. Serial.println(" ");
  622.  
  623. Serial.println("GROUPE SW");
  624. groupe_SW.RAZ(); // important, sinon les fréquences se trouvent dédoublées lors d'un soft-reset
  625. groupe_SW.load_bloc(); // SPIFFS -> RAM
  626. groupe_SW.tri_bloc(); // en RAM
  627. groupe_SW.bloc_to_serial();
  628.  
  629. Serial.println("---------------------------------------------");
  630.  
  631. Serial.println("GROUPE FM");
  632. groupe_FM.RAZ();
  633. groupe_FM.load_bloc();
  634. groupe_FM.tri_bloc();
  635. groupe_FM.bloc_to_serial();
  636.  
  637. Serial.println("---------------------------------------------");
  638.  
  639. Serial.println("GROUPE AIR");
  640. groupe_AIR.RAZ();
  641. groupe_AIR.load_bloc();
  642. groupe_AIR.tri_bloc();
  643. groupe_AIR.bloc_to_serial();
  644.  
  645. Serial.println("---------------------------------------------");
  646.  
  647. // remarque : le groupe SCAN n'est jamais enregistré en SPIFFS
  648. }
  649.  
  650.  
  651. uint16_t brightness(uint16_t couleur)
  652. {
  653. uint8_t r, g, b;
  654.  
  655. r = 0xFF & (couleur >> 16);
  656. g = 0xFF & (couleur >> 8);
  657. b = 0xFF & couleur;
  658.  
  659. return ( r + g + b );
  660. }
  661.  
  662.  
  663.  
  664. void init_affichages()
  665. {
  666. TFT.fillRect(0, 14, 319, 230, couleur_fond_ecran);
  667. if (brightness(couleur_fond_ecran) > 500) {couleur_traits = NOIR;} else {couleur_traits = BLANC;}
  668.  
  669. TFT.setTextColor(JAUNE, NOIR);
  670.  
  671. TFT.drawRect(0, 0, 319, 240, couleur_traits); // cadre principal pourtour de l'écran
  672. TFT.setFreeFont(FF0);
  673. TFT.setTextColor(BLANC, BLEU);
  674. String s1 = "v:" + version;
  675. TFT.drawString(s1, 45, 15);
  676.  
  677.  
  678. while (!Serial && (millis() <= 1000));
  679. init_boutons_MODE();
  680.  
  681. affiche_box_SPIFFS();
  682. init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+16, 40, 15, "Raz", &bt_SPIFFS_RAZ);
  683. init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+33, 40, 15, "Write", &bt_SPIFFS_write);
  684.  
  685. TFT.setFreeFont(FF0);
  686.  
  687. init_boutons_Plus_Moins();
  688. init_boutons_GROUPE(); // (SW - FM - AIR - SC)
  689.  
  690. init_1_bouton(305, 15, 15, 15, "?", &bt_info);
  691. init_1_bouton(202, 222, 32, 15, "Mute", &bt_mute);
  692. init_1_bouton(233, 222, 30, 15, "SLP", &bt_sleep);
  693. init_1_bouton(262, 222, 25, 15, "RST", &bt_reset);
  694. init_1_bouton(288, 222, 30, 15, "Coul", &bt_affi_saisie_couleur);
  695.  
  696. init_1_bouton(160, 120, 40, 14, "TEST", &bt_TEST);
  697.  
  698. //bt_affi_saisie_couleur.affiche(NOIR, VERT, 1);
  699.  
  700. affiche_box_boutons_scan();
  701. init_1_bouton(5, 118, 55, 15, "scan FRQ", &bt_scan_frq);
  702. init_1_bouton(5, 135, 55, 15, "scan AIR", &bt_scan_air);
  703.  
  704. init_1_bouton(168, 97, 30, 15, "set", &bt_set);
  705.  
  706. init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+33, 40, 15, "Write", &bt_SPIFFS_write);
  707. init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+50, 40, 15, "raz 1F", &bt_erase_1F);
  708. init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+67, 40, 15, "LST", &bt_SPIFFS_LST);
  709.  
  710. numPad1.init(x0_numPad, y0_numPad, true);
  711.  
  712. affiche_box_presets(); // conteneur des 8 petits boutons
  713. presetPad1.init(x0_box_PRESET +5, y0_box_PRESET +5);
  714.  
  715. efface_box_entete2();
  716. efface_box_entete3();
  717.  
  718. init_box_info();
  719. affiche_box_FRQ(GRIS_3); // autour de la fréquence (gros chiffres JAUNE ou VERT)
  720.  
  721. if (mode_affi == NORMAL)
  722. {
  723. affiche_box_GROUPE();
  724. bt_moins.affiche(GRIS_6, VERT ,1);
  725. bt_plus.affiche(GRIS_6, VERT ,1);
  726. bt_SW.affiche(GRIS_5, VERT, 1);
  727. bt_FM.affiche(GRIS_5, VERT, 1);
  728. bt_AIR.affiche(GRIS_5, VERT, 1);
  729. bt_SCN.affiche(GRIS_5, VERT, 1);
  730. }
  731.  
  732. bt_4.selected = true;
  733. bt_4.cliked = true;
  734. bt_4.affiche(NOIR, GRIS_2,1);
  735.  
  736. bt_mute.selected = false;
  737. bt_mute.cliked = false;
  738. bt_mute.affiche(NOIR, ROUGE, 1);
  739. bt_sleep.affiche(NOIR, VERT, 1);
  740. bt_TEST.affiche(NOIR, VERT, 1);
  741. bt_reset.affiche(NOIR, VERT, 1);
  742.  
  743. affiche_frequence(frequence);
  744.  
  745. dessine_VuMetre();
  746. }
  747.  
  748.  
  749. void read_FRQ_File(FS &fs, String path, String cible) // en mémoire SPIFFS
  750. {
  751. Serial.print("Reading file: "); Serial.println(path);
  752. File file = fs.open(path);
  753. if (!file ) { Serial.println("failed to open file for reading"); return; }
  754. String s;
  755. uint8_t n =0;
  756.  
  757. while (file.available())
  758. {
  759. char c;
  760. c = char(file.read());
  761. if ((c !='<') && (c !='>')) {s += c;}
  762. if(c=='>')
  763. {
  764. uint32_t frq;
  765. frq = s.toInt();
  766. Serial.println(frq);
  767. s="";
  768. if(cible == "SW") {presetPad1.bt_preset[n].frequence_SW = frq;}
  769. if(cible == "FM") {presetPad1.bt_preset[n].frequence_FM = frq;}
  770. if(cible == "AIR") {presetPad1.bt_preset[n].frequence_AIR = frq;}
  771. n++;
  772. }
  773. }
  774. file.close();
  775. }
  776.  
  777.  
  778. String read_line_params(uint16_t line_num)
  779. {
  780. int i = 1;
  781. char buffer[64];
  782. String s;
  783.  
  784. File file = SPIFFS.open("/params.txt", "r");
  785.  
  786. while (file.available())
  787. {
  788. int l = file.readBytesUntil('\n', buffer, sizeof(buffer));
  789. buffer[l] = 0;
  790. if (line_num == i)
  791. {
  792. s = buffer;
  793. file.close();
  794. return(s);
  795. }
  796. i++;
  797. }
  798. return "";
  799. }
  800.  
  801.  
  802. int32_t extract_params(String ligne, String label)
  803. {
  804. String s2;
  805. uint32_t valeur = 0;
  806. int p1, p2;
  807.  
  808. p1 = ligne.indexOf('['); p2 = ligne.indexOf(']');
  809. s2 = ligne.substring(p1+1, p2);
  810.  
  811. if (s2 == label)
  812. {
  813. p1 = ligne.indexOf('<'); p2 = ligne.indexOf('>');
  814. s2 = ligne.substring(p1+1, p2);
  815. valeur = s2.toInt();
  816. return valeur;
  817. }
  818. return -1;
  819. }
  820.  
  821.  
  822.  
  823. void setup()
  824. {
  825. Serial.begin(115200);
  826. delay(100);
  827.  
  828. // Avant la première utilisation il faut avoir formaté la partition SPIFFS
  829. // et téléversé dedans les fichiers (images, fréquences, paramètres) avec Platformio ('Upload Filesystem image')
  830. // voir ces liens :
  831. // https://www.programmingelectronics.com/spiffs-esp32/
  832. // https://randomnerdtutorials.com/esp32-vs-code-platformio-spiffs/
  833.  
  834. if (!SPIFFS.begin())
  835. {
  836. Serial.println("ERREUR montage SPIFFS");
  837. } else Serial.println("montage SPIFFS OK");
  838.  
  839.  
  840. init_variables_globales();
  841.  
  842. Wire.begin(GPIO_SDA, GPIO_SCL, 100000);
  843.  
  844. Serial.println("display.init()");
  845.  
  846. TFT.init();
  847. TFT.setRotation(3); // 0..3 à voir, suivant disposition de l'afficheur
  848. TFT.fillScreen(NOIR);
  849.  
  850. init_sprites();
  851.  
  852. // Start the SPI for the touch screen and init the TS library
  853. mySpi.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
  854. ts.begin(mySpi);
  855. ts.setRotation(3);
  856.  
  857. affi_image_from_spiffs("/7.bmp", 0, 0); // IMAGE D'ACCEUIL
  858. delay(1000);
  859.  
  860. /*
  861. à voir ...
  862. //Use this calibration code in setup():
  863. uint16_t calData[5] = { 671, 2090, 1096, 1736, 3 };
  864. tft.setTouch(calData);
  865. */
  866. groupe_SW.filename = "/FRQ_SW.txt"; // nom du fichier en mémoire SPIFFS
  867. groupe_FM.filename = "/FRQ_FM.txt";
  868. groupe_AIR.filename = "/FRQ_AIR.txt";
  869.  
  870. int Ts = SPIFFS.totalBytes();
  871. int Us = SPIFFS.usedBytes();
  872. Serial.println("-------------------------------------");
  873. Serial.println("SPIFFS Info:");
  874. Serial.print("Total Bytes "); Serial.println(Ts);
  875. Serial.print("Used Bytes "); Serial.println(Us);
  876. Serial.print("Free Bytes "); Serial.println(Ts-Us);
  877. Serial.println("-------------------------------------");
  878.  
  879. load_GRP_FREQ_SPIFFS(); // -> to RAM
  880.  
  881. groupe_SCAN.RAZ();
  882.  
  883. presetPad1.set_frequences_PRST();
  884. presetPad1.set_couleurs();
  885.  
  886. // lecture du fichier '/params.txt' en SPIFFS
  887. Serial.println("lecture du fichier '/params.txt' en SPIFFS");
  888. String s1;
  889. int valeur;
  890. Serial.println("---------------------------------------------");
  891. Serial.println("read params() ");
  892.  
  893. for(uint16_t n=1; n<=9; n++) // lit toutes(9) lignes du fichier
  894. {
  895. s1 = read_line_params(n); // retourne(par exemple): [couleur_fond]<267>
  896. Serial.print(n); Serial.println(" " + s1);
  897.  
  898. valeur = extract_params(s1, "couleur_fond"); // extrait la valeur correspondant au label
  899. if(valeur != -1) {couleur_fond_ecran = valeur;}
  900.  
  901. valeur = extract_params(s1, "frequence");
  902. if(valeur != -1) {frequence = extract_params(s1, "frequence");}
  903. }
  904. Serial.print("---------------------------------------------");
  905.  
  906. boolean vu_metre_actif = true;
  907.  
  908. TFT.fillScreen(NOIR);
  909. init_affichages();
  910.  
  911. saut_freq = 100;
  912. Tuner_Init(tuner_init_tab9216);
  913. // Set_no_AM_gain_reduction();
  914.  
  915. bt_mode_FRQ.selected = false;
  916. bt_mode_MEM.selected = true;
  917.  
  918. uint16_t c1 = GRIS_6;
  919. uint16_t c2 = VERT;
  920. uint16_t c3 = JAUNE;
  921. bt_mode_FRQ.affiche(c1, c2, 2); // bt en haut à gauche
  922. bt_mode_MEM.affiche(c1, c3, 2); // bt en haut à gauche
  923.  
  924. groupe_actif = gFM;
  925. bande_active = FM;
  926. modulation_active = WFM;
  927. bt_FM.selected = true;
  928. bt_SW.selected = false;
  929. bt_AIR.selected = false;
  930. bt_SCN.selected = false;
  931.  
  932. bt_SW.affiche(c1, c2, 1);
  933. bt_FM.affiche(c1, c3, 1);
  934.  
  935. //clic_logiciel_bouton(&presetPad1.bt_preset[0]);
  936. //traite_boutons_presetPad(0);
  937.  
  938. uint8_t nb_F = groupe_FM.nb_freq;
  939. affiche_numero_frq(String(1), String(nb_F));
  940.  
  941. affiche_frequence(frequence);
  942. Tune_Frequence(frequence);
  943.  
  944. Set_Volume(+60);
  945.  
  946. delay(100);
  947.  
  948. //clic_logiciel_bouton(&bt_mode_MEM);
  949. mode_s = _MEM;
  950.  
  951. if (test_touch_screen == true) {printTouchToDisplay();}
  952.  
  953.  
  954.  
  955. Serial.print("- FIN DU SETUP -----------------");
  956. // FIN DU SETUP
  957. }
  958.  
  959.  
  960.  
  961. void printTouchToDisplay() // pour TEST
  962. {
  963. TFT.fillScreen(NOIR);
  964.  
  965. TFT.setFreeFont(FM9);
  966. TFT.setTextColor(BLEU_CLAIR, NOIR);
  967. TFT.drawString("TEST TOUCH screen", 80, 120);
  968.  
  969. while(1)
  970. {
  971. if (ts.tirqTouched() && ts.touched())
  972. {
  973. TS_Point p = ts.getPoint();
  974. x_touch = eTS.x0 + p.x /eTS.dx;
  975. y_touch = eTS.y0 + p.y /eTS.dy;
  976.  
  977. TFT.drawRect(x_touch, y_touch, 1, 1, JAUNE);
  978.  
  979. // affiche force d'appui du stylet
  980. /*
  981. int x = 320 / 2; // center of display
  982. int y = 100;
  983. int fontSize = 2;
  984. String temp = "P= " + String(p.z);
  985. TFT.drawCentreString(temp, x, y, fontSize);
  986. */
  987. }
  988. }
  989. }
  990.  
  991.  
  992. // -------------------------------------------------------------------------
  993. // Le vu-metre est une variante perso du code : "/Arduino/libraries/TFT_eSPI/examples/480 x 320/TFT_Meters"
  994. // voir le fichier licence.txt dans le dossier "/Arduino/libraries/TFT_eSPI/examples/"
  995. void dessine_VuMetre()
  996. {
  997. if (vu_metre_actif == false) {return;}
  998.  
  999. uint16_t x0 = x0_vu_metre;
  1000. uint16_t y0 = y0_vu_metre;
  1001.  
  1002. uint16_t dx=140;
  1003. uint16_t dy=70;
  1004.  
  1005. uint8_t AA = 65; // 65
  1006. uint8_t BB = x0 +dx/2;// 120
  1007. uint8_t CC = y0 + dy+20; // 140
  1008.  
  1009. TFT.setFreeFont(FF0);
  1010. // cadre rectangulaire
  1011. TFT.fillRect(x0, y0, dx, dy, GRIS_3);
  1012. TFT.fillRect(x0+3, y0+3, dx-6, dy-6, BLANC);
  1013.  
  1014. TFT.setTextColor(NOIR);
  1015.  
  1016. // graduation chaque 5 deg entre -50 et +50 deg
  1017. for (int i = -50; i < 51; i += 10)
  1018. {
  1019. int tl = 5; // tiret plus long
  1020. // Coordonnées du tiret à dessiner
  1021. float sx = cos((i - 90) * deg_to_rad);
  1022. float sy = sin((i - 90) * deg_to_rad);
  1023. uint16_t tx0 = sx * (AA + tl) + BB;
  1024. uint16_t ty0 = sy * (AA + tl) + CC;
  1025. uint16_t tx1 = sx * AA + BB;
  1026. uint16_t ty1 = sy * AA + CC;
  1027.  
  1028. float sx2 = cos((i + 5 - 90) * deg_to_rad);
  1029. float sy2 = sin((i + 5 - 90) * deg_to_rad);
  1030. int tx2 = sx2 * (AA + tl) + BB;
  1031. int ty2 = sy2 * (AA + tl) + CC;
  1032. int tx3 = sx2 * AA + BB;
  1033. int ty3 = sy2 * AA + CC;
  1034.  
  1035. // zone verte
  1036. if (i >= 0 && i < 25)
  1037. {
  1038. TFT.fillTriangle(tx0, ty0, tx1, ty1, tx2, ty2, VERT);
  1039. TFT.fillTriangle(tx1, ty1, tx2, ty2, tx3, ty3, VERT);
  1040. }
  1041.  
  1042. // zone orange
  1043. if (i >= 25 && i < 50)
  1044. {
  1045. TFT.fillTriangle(tx0, ty0, tx1, ty1, tx2, ty2, ORANGE);
  1046. TFT.fillTriangle(tx1, ty1, tx2, ty2, tx3, ty3, ORANGE);
  1047. }
  1048.  
  1049. if (i % 25 != 0) tl = 8;
  1050.  
  1051. tx0 = sx * (AA + tl) + BB;
  1052. ty0 = sy * (AA + tl) + CC;
  1053. tx1 = sx * AA + BB;
  1054. ty1 = sy * AA + CC;
  1055.  
  1056. TFT.drawLine(tx0, ty0, tx1, ty1, NOIR);
  1057.  
  1058. if (i % 20 == 0)
  1059. {
  1060. tx0 = sx * (AA + tl + 10) + BB;
  1061. ty0 = sy * (AA + tl + 10) + CC;
  1062. switch (i / 20)
  1063. {
  1064. case -2: TFT.drawCentreString("0", tx0, ty0 - 6, 1); break;
  1065. case -1: TFT.drawCentreString("25", tx0, ty0 - 4, 1); break;
  1066. case 0: TFT.drawCentreString("50", tx0, ty0 - 6, 1); break;
  1067. case 1: TFT.drawCentreString("75", tx0, ty0 - 4, 1); break;
  1068. case 2: TFT.drawCentreString("100", tx0, ty0 - 6, 1); break;
  1069. }
  1070. }
  1071. sx = cos((i + 5 - 90) * deg_to_rad);
  1072. sy = sin((i + 5 - 90) * deg_to_rad);
  1073. tx0 = sx * AA + BB;
  1074. ty0 = sy * AA + CC;
  1075. if (i < 50) {TFT.drawLine(tx0, ty0, tx1, ty1, NOIR);}
  1076. }
  1077. }
  1078.  
  1079.  
  1080.  
  1081. void plotAiguille(float value)
  1082. {
  1083. if (vu_metre_actif == false) {return;}
  1084.  
  1085. uint16_t x0 = x0_vu_metre;
  1086. uint16_t y0 = y0_vu_metre;
  1087. uint16_t dx=140;
  1088. uint16_t dy=50;
  1089.  
  1090. uint8_t AA = dx/2; // 100
  1091. uint8_t BB = x0 +dx/2;// 120
  1092. uint8_t CC = y0 + dy+25; // 140
  1093.  
  1094. TFT.setTextColor(TFT_BLACK, BLANC);
  1095. char buf[8]; dtostrf(value, 4, 0, buf);
  1096.  
  1097. if (value < -10) value = -10;
  1098. if (value > 110) value = 110;
  1099.  
  1100. float sdeg = map(value, -10, 110, -150, -30);
  1101. float sx = cos(sdeg * deg_to_rad);
  1102. float sy = sin(sdeg * deg_to_rad);
  1103.  
  1104. float tx = tan((sdeg + 90) * deg_to_rad);
  1105.  
  1106. TFT.drawLine(BB + 20*ltx - 1, CC - 20, osx - 1, osy, BLANC); //efface
  1107. TFT.drawLine(BB + 20*ltx, CC - 20, osx, osy, BLANC);
  1108. TFT.drawLine(BB + 20*ltx + 1, CC - 20, osx + 1, osy, BLANC);
  1109.  
  1110. ltx = tx;
  1111. osx = sx*50 + BB;
  1112. osy = sy*50 + CC;
  1113.  
  1114. TFT.drawLine(BB + 20*ltx - 1, CC - 20, osx - 1, osy, ROUGE);
  1115. TFT.drawLine(BB + 20*ltx, CC - 20, osx, osy, VIOLET);
  1116. TFT.drawLine(BB + 20*ltx + 1, CC - 20, osx + 1, osy, ROUGE);
  1117.  
  1118. TFT.fillRect(x0, y0+dy+5, dx, 15, GRIS_2);
  1119. }
  1120.  
  1121.  
  1122.  
  1123. void init_box_info()
  1124. {
  1125. TFT.drawRect(x0_box_info1, y0_box_info1, 130, 16, NOIR);
  1126. TFT.setFreeFont(FF0);
  1127. TFT.setTextColor(JAUNE, couleur_fond_ecran);
  1128. TFT.drawString("RDS", x0_box_info1 -20, y0_box_info1 + 4);
  1129. }
  1130.  
  1131.  
  1132. void affiche_unit(String s)
  1133. {
  1134. TFT.setTextColor(JAUNE, NOIR);
  1135. TFT.setFreeFont(FM9); //FM9 FMB9 FSS9... voir le fichier FrSPIFFS_Fonts.h
  1136. TFT.drawString(s, FRQ_x0 + 225, FRQ_y0 + 35);
  1137. }
  1138.  
  1139.  
  1140. void efface_numero_frq()
  1141. {
  1142. TFT.fillRect(FRQ_x0 + 225, FRQ_y0 + 20, 40, 12, couleur_fond_ecran);
  1143. }
  1144.  
  1145.  
  1146. void affiche_numero_frq(String s1, String s2)
  1147. {
  1148. //TFT.fillRect(FRQ_x0 + 225, FRQ_y0 + 5, 10, 10, BLEU);
  1149. TFT.setTextColor(BLANC, couleur_fond_ecran);
  1150. TFT.setFreeFont(FF0);
  1151. TFT.drawString(s1 + "/" + s2 + " ", FRQ_x0 + 225, FRQ_y0 + 20);
  1152. affiche_box_FRQ(GRIS_3); // pour retracer le côté droit du rectangle
  1153. }
  1154.  
  1155.  
  1156. void affiche_band(String s)
  1157. {
  1158. //TFT.fillRect(FRQ_x0 + 225, FRQ_y0 + 5, 10, 10, BLEU);
  1159. TFT.setTextColor(BLANC, NOIR);
  1160. TFT.setFreeFont(FM9);
  1161. String blancs;
  1162. if (s == "AIR") {blancs = " ";} else {blancs = " ";}
  1163.  
  1164. TFT.drawString(s + blancs, FRQ_x0 + 225, FRQ_y0);
  1165. affiche_box_FRQ(GRIS_3); // pour retracer le côté droit du rectangle
  1166. }
  1167.  
  1168. void efface_box_entete1()
  1169. {
  1170. TFT.fillRect(0, 1, 50, 12, NOIR);
  1171. }
  1172.  
  1173.  
  1174. void efface_box_entete2()
  1175. {
  1176. TFT.fillRect(50, 1, 180, 12, NOIR);
  1177. }
  1178.  
  1179.  
  1180. void efface_box_entete3()
  1181. {
  1182. TFT.fillRect(230, 1, 76, 12, NOIR);
  1183. memo_valeur_affi--; // pour réafficher tension batterie
  1184. }
  1185.  
  1186.  
  1187. void affiche_box_FRQ(uint16_t couleur) // autour de la fréquence (en gros chiffres JAUNE
  1188. {
  1189. TFT.drawRect(0, FRQ_y0 -17, 319, 74, couleur);
  1190. }
  1191.  
  1192.  
  1193. void affiche_box_presets() // boutons 1 2 3 4 5 6 7 8
  1194. {
  1195. TFT.fillRect(x0_box_PRESET, y0_box_PRESET, 164, 24, NOIR);
  1196. TFT.setTextColor(GRIS_3, NOIR);
  1197.  
  1198. }
  1199.  
  1200.  
  1201. void affiche_box_GROUPE() // groupes de fréquences; contient 4 boutons SW, FM, AIR, SC
  1202. {
  1203. TFT.fillRect(x0_box_GROUPE, y0_box_GROUPE, 105, 23, NOIR);
  1204. //TFT.drawRect(x0_box_GROUPE, y0_box_GROUPE, 105, 25, couleur_traits);
  1205. TFT.setFreeFont(FF0);
  1206. TFT.setTextColor(GRIS_3, NOIR);
  1207. TFT.drawString("groupes Freq", x0_box_GROUPE+4, y0_box_GROUPE-6);
  1208. }
  1209.  
  1210.  
  1211. void efface_box_GROUPE()
  1212. {
  1213. //TFT.fillRect(x0_box_GROUPE, y0_box_GROUPE-7, 110, 33, couleur_fond_ecran);
  1214. }
  1215.  
  1216.  
  1217. void affiche_box_SPIFFS() // Raz, Write, Raz 1F, LST
  1218. {
  1219. TFT.fillRect(x0_box_SPIFFS, y0_box_SPIFFS + 10, 46, 75, NOIR);
  1220. TFT.setFreeFont(FF0);
  1221. TFT.setTextColor(GRIS_3, NOIR);
  1222. TFT.drawString("SPIFFS", x0_box_SPIFFS+6, y0_box_SPIFFS+6);
  1223. }
  1224.  
  1225.  
  1226. void affiche_box_boutons_scan()
  1227. {
  1228. TFT.fillRect(x0_box_boutons_scan, y0_box_boutons_scan + 10, 60, 38, NOIR);
  1229.  
  1230. }
  1231.  
  1232.  
  1233. void affiche_box_scan(uint16_t dy)
  1234. {
  1235. init_1_bouton(301, y0_box_SCAN+1, 15, 15, "x", &bt_stop_scan);
  1236. if (bande_active != AIR)
  1237. {
  1238. init_1_bouton(275, y0_box_SCAN+17, 40, 15, "rescan", &bt_re_scan);
  1239. init_1_bouton(275, y0_box_SCAN+34, 40, 14, " >>", &bt_scan_suivant);
  1240. }
  1241. init_1_bouton(255, y0_box_SCAN+1, 15, 15, "+", &bt_seuil_plus);
  1242. init_1_bouton(255, y0_box_SCAN+20, 15, 15, "-", &bt_seuil_moins);
  1243. init_1_bouton(4, y0_box_SCAN+3, 15, 15, "L", &bt_LEV);
  1244. init_1_bouton(4, y0_box_SCAN+20, 15, 15, "N", &bt_SNR);
  1245. }
  1246.  
  1247.  
  1248. void affi_boutons_SW_FM_AIR_SCN()
  1249. {
  1250. if((mode_affi == SCAN_F ) || (mode_affi == SCAN_M )) {return;}
  1251.  
  1252. uint16_t c1 = GRIS_5;
  1253. uint16_t c2 = VERT;
  1254. bt_SW.affiche(c1, c2, 1);
  1255. bt_FM.affiche(c1, c2, 1);
  1256. bt_AIR.affiche(c1, c2, 1);
  1257. bt_SCN.affiche(c1, BLEU_CLAIR, 1);
  1258. bt_mute.affiche(NOIR, ROUGE, 1);
  1259.  
  1260. }
  1261.  
  1262.  
  1263. void affiche_frequence(uint32_t frq)
  1264. {
  1265. uint16_t couleur_chiffres;
  1266.  
  1267. if(mode_s == _FRQ) {couleur_chiffres = VERT_chiffres;}
  1268. if(mode_s == _MEM) {couleur_chiffres = JAUNE_chiffres;}
  1269.  
  1270. if(bande_SW) // d'après la fréquence; SW - 28 MHz = limite haute du module
  1271. {
  1272. affiche_band("SW");
  1273. modulation_active = AM;
  1274. if (groupe_actif != gSCN) {bande_active = SW; groupe_actif == gSW;}
  1275. bt_SW.selected = true;
  1276. bt_FM.selected = false; // les boutons sont exclusifs
  1277. bt_AIR.selected = false;
  1278. //bt_SCN.selected = false;
  1279. affi_boutons_SW_FM_AIR_SCN();
  1280.  
  1281. String s1, sM, sK;
  1282. uint8_t L;
  1283.  
  1284. s1 = String(frq);
  1285. s1 = "000000" + s1;
  1286. L= s1.length();
  1287.  
  1288. sK = s1.substring(L-3); // kHz
  1289. sM = s1.substring(L-6, L-3); // Mhz
  1290.  
  1291. sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
  1292.  
  1293. sprite_frq.setTextColor(couleur_chiffres, NOIR);
  1294. sprite_frq.drawString(sM + "." + sK + " ", 220+10, 32);
  1295. // remarque: le fait d'ajouter " " à la fin évite aux chiffres de se balader horizontalement !
  1296. sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
  1297. affiche_unit("MHz");
  1298. Tune_Frequence(frq);
  1299. }
  1300.  
  1301. if(bande_FM) // bande FM, on efface les deux '0' de droite (si == 0 sinon on affiche quand même)
  1302. {
  1303. affiche_band("FM");
  1304. modulation_active = WFM;
  1305. if (groupe_actif != gSCN) {bande_active = FM; groupe_actif == gFM;}
  1306.  
  1307. affi_boutons_SW_FM_AIR_SCN();
  1308.  
  1309. String s1, sM, sK1, sK2, sK3;
  1310. String decimales;
  1311. uint8_t x0 = 0;
  1312. uint8_t L;
  1313.  
  1314. s1 = String(frq);
  1315. s1 = "000000" + s1;
  1316. L= s1.length();
  1317.  
  1318. sK1 = s1.substring(L-3, L-2); // 1ere décimale
  1319. sK2 = s1.substring(L-2, L-1); // 2eme décimale
  1320. sK3 = s1.substring(L-1, L); // 3eme décimale
  1321.  
  1322. if ((sK2 == "0") && (sK3 == "0"))
  1323. {
  1324. decimales = sK1;
  1325. x0=170;
  1326. }
  1327. else
  1328. {
  1329. decimales = sK1 + sK2 + sK3;
  1330. x0=232;
  1331. }
  1332.  
  1333. if (frq < 100000) {sM = s1.substring(L-5, L-3); }// on ne retient que deux chiffres à gauche du point
  1334. else { sM = s1.substring(L-6, L-3); } // on garde 3 chiffres à gauche du point décimal
  1335.  
  1336. sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
  1337. sprite_frq.setTextColor(couleur_chiffres, NOIR);
  1338. sprite_frq.drawString(sM + "." + decimales + " ", x0, 32);
  1339. // remarque: le fait d'ajouter " " à la fin évite aux chiffres de se balader horizontalement !
  1340. sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
  1341. affiche_unit("MHz");
  1342.  
  1343. Tune_Frequence(frq);
  1344. bt_mute.selected = false;
  1345. bt_mute.cliked = false;
  1346.  
  1347. }
  1348.  
  1349. if(bande_AIR) // bande AIR - 138000-110000 = 28MHz (limite haute de réception AM du module)
  1350. {
  1351. affiche_band("AIR");
  1352. modulation_active = AM;
  1353. if (groupe_actif != gSCN) {bande_active = AIR; groupe_actif == gAIR;}
  1354.  
  1355. bt_AIR.selected = true;
  1356. bt_SW.selected = false; // les boutons sont exclusifs
  1357. bt_FM.selected = false;
  1358. //bt_SCN.selected = false;
  1359. affi_boutons_SW_FM_AIR_SCN();
  1360.  
  1361. String s1, sM, sK;
  1362. uint8_t L;
  1363.  
  1364. s1 = String(frq);
  1365. s1 = "000000" + s1;
  1366. L= s1.length();
  1367.  
  1368. sK = s1.substring(L-3); // kHz
  1369. sM = s1.substring(L-6, L-3); // Mhz
  1370.  
  1371. sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
  1372. sprite_frq.setTextColor(couleur_chiffres, NOIR);
  1373. sprite_frq.drawString(sM + "." + sK + " ", 220+10, 32);
  1374. sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
  1375. affiche_unit("MHz");
  1376. Tune_Frequence(frq);
  1377. }
  1378.  
  1379. if(bande_interdite1 || bande_interdite2) // bandes interdites par le module TEF6686
  1380. {
  1381. affiche_band("---");
  1382.  
  1383. String s1, sM, sK;
  1384. uint8_t L;
  1385.  
  1386. s1 = String(frq);
  1387. s1 = "000000" + s1;
  1388. L= s1.length();
  1389.  
  1390. sK = s1.substring(L-3); // kHz
  1391. sM = s1.substring(L-6, L-3); // Mhz
  1392.  
  1393. sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
  1394. sprite_frq.setTextColor(couleur_chiffres, NOIR);
  1395. sprite_frq.drawString(sM + "." + sK + " ", 220+10, 32);
  1396. // remarque: le fait d'ajouter " " à la fin évite aux chiffres de se balader horizontalement !
  1397. sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
  1398. affiche_unit("MHz");
  1399.  
  1400. }
  1401.  
  1402. if(frq==138000) { affiche_band("max"); }
  1403. if(frq>138000) { affiche_band("---"); }
  1404. }
  1405.  
  1406.  
  1407. void clic_logiciel_bouton(TOUCH_BOUTON *bouton_i)
  1408. {
  1409. uint16_t c1 = NOIR;
  1410. uint16_t c2 = JAUNE;
  1411.  
  1412. bouton_i->cliked = true;
  1413. bouton_i->selected = true;
  1414. bouton_i->affiche(c1, c2, 1);
  1415. }
  1416.  
  1417.  
  1418.  
  1419. void test_clic_boutons(TOUCH_BOUTON *bouton_i)
  1420. {
  1421. uint16_t c1 = NOIR;
  1422. uint16_t c2 = GRIS_2;
  1423.  
  1424. if ((x_touch > bouton_i->x0) && (x_touch < bouton_i->x0 + bouton_i->read_dx())
  1425. && ( y_touch > bouton_i->y0-4) && (y_touch < bouton_i->y0-4 + bouton_i->read_dy()) )
  1426. {
  1427. bouton_i->cliked = true;
  1428. bouton_i->selected = true;
  1429. bouton_i->affiche(c1, c2, 1);
  1430. }
  1431. }
  1432.  
  1433.  
  1434.  
  1435. void test_clic_6_boutons_frq() //rectangles situés au dessus des gros chiffres de la fréquence
  1436. {
  1437. uint16_t c1 = NOIR;
  1438. uint16_t c2 = VERT;
  1439.  
  1440. if (( y_touch > (bt_1.y0-10)) && (y_touch < (bt_1.y0 + bt_1.read_dy()+10)) ) // zone des 6 boutons au dessus de la fréquence
  1441. {
  1442. bt_1.cliked = false; bt_1.selected = false; test_clic_boutons(&bt_1 ); bt_1.affiche(c1, c2,1);
  1443. bt_2.cliked = false; bt_2.selected = false; test_clic_boutons(&bt_2 ); bt_2.affiche(c1, c2,1);
  1444. bt_3.cliked = false; bt_3.selected = false; test_clic_boutons(&bt_3 ); bt_3.affiche(c1, c2,1);
  1445. bt_4.cliked = false; bt_4.selected = false; test_clic_boutons(&bt_4 ); bt_4.affiche(c1, c2,1);
  1446. bt_5.cliked = false; bt_5.selected = false; test_clic_boutons(&bt_5 ); bt_5.affiche(c1, c2,1);
  1447. bt_6.cliked = false; bt_6.selected = false; test_clic_boutons(&bt_6 ); bt_6.affiche(c1, c2,1);
  1448.  
  1449. if (bt_6.cliked) {saut_freq = 1;}
  1450. if (bt_5.cliked) {saut_freq = 10;}
  1451. if (bt_4.cliked) {saut_freq = 100;}
  1452. if (bt_3.cliked) {saut_freq = 1000;}
  1453. if (bt_2.cliked) {saut_freq = 10000;}
  1454. if (bt_1.cliked) {saut_freq = 100000;}
  1455. }
  1456. }
  1457.  
  1458.  
  1459. void affiche_saisie(String s1)
  1460. {
  1461. TFT.fillRect(x0_saisie+1, y0_saisie-1, 60, 12, NOIR); // efface
  1462. TFT.setFreeFont(FF0); TFT.setTextColor(VERT, NOIR);
  1463. TFT.drawString(s1, x0_saisie+5, y0_saisie+3);
  1464. }
  1465.  
  1466.  
  1467. void traite_touches_pad(uint8_t num_touche) // pavé numérique
  1468. {
  1469. if(num_touche == 253) {return;}
  1470.  
  1471. uint16_t c1 = GRIS_6;
  1472. uint16_t c2 = JAUNE;
  1473. uint16_t c3 = VERT;
  1474.  
  1475. int p1;
  1476.  
  1477. if (num_touche == 254) // bouton "."
  1478. {
  1479. frequence_txt += ".";
  1480. affiche_saisie(frequence_txt);
  1481. }
  1482.  
  1483. if (num_touche < 10)
  1484. {
  1485. frequence_txt += String(num_touche);
  1486. affiche_saisie(frequence_txt);
  1487. delay(300);
  1488. }
  1489.  
  1490. x_touch =0;
  1491. y_touch =0;
  1492.  
  1493. if (num_touche == 255) // bouton "ok"
  1494. {
  1495. Serial.println("touche ok");
  1496.  
  1497. affiche_saisie(""); // efface
  1498.  
  1499. mode_s = _FRQ;
  1500. bt_mode_MEM.selected = false;
  1501. bt_mode_FRQ.selected = true;
  1502.  
  1503. bt_mode_MEM.affiche(c1, c2, 2);
  1504. bt_mode_FRQ.affiche(c1, c3, 2);
  1505.  
  1506. double F = frequence_txt.toDouble();
  1507. p1 = frequence_txt.indexOf(".");
  1508. if (p1 != -1) {F *=1000;} // si présence du point décimal
  1509.  
  1510. frequence = F;
  1511. affiche_frequence(frequence); // 'Tune_Frequence(frq)' est appelée dans cette fonction 'affiche_frequence()'
  1512.  
  1513. n_appui = 0;
  1514. frequence_txt = "";
  1515. TFT.fillRect(250, 0, 60, 12, NOIR); // efface
  1516.  
  1517. n_appui = 0;
  1518.  
  1519. }
  1520. num_touche = 0;
  1521. }
  1522.  
  1523.  
  1524. void record_fichier_params() // en memoire SPIFFS
  1525. {
  1526. Serial.println("write fichier '/params.txt'");
  1527.  
  1528. File file1 = SPIFFS.open("/params.txt", FILE_WRITE);
  1529. String s1;
  1530.  
  1531. s1 ="[couleur_fond]";
  1532. s1 += "<";
  1533. s1 += String(couleur_fond_ecran);
  1534. s1 +=">";
  1535. file1.println(s1);
  1536.  
  1537. s1 ="[frequence]";
  1538. s1 += "<";
  1539. s1 += String(frequence);
  1540. s1 +=">";
  1541. file1.println(s1);
  1542.  
  1543. file1.close();
  1544. delay(300);
  1545. }
  1546.  
  1547.  
  1548. void record_fichier_FRQ_SW_PRST()
  1549. {
  1550. Serial.println("record_fichier_FRQ_SW_PRST()");
  1551.  
  1552. File file1 = SPIFFS.open("/FRQ_FM_PRST.txt", FILE_WRITE);
  1553. String s1;
  1554.  
  1555. for(uint8_t n=0; n<8; n++)
  1556. {
  1557. s1 = "<";
  1558. s1 += String(presetPad1.bt_preset[n].frequence_SW);
  1559. s1 +=">";
  1560. file1.println(s1);
  1561. }
  1562. file1.close();
  1563. }
  1564.  
  1565.  
  1566.  
  1567. void record_fichier_FRQ_FM_PRST()
  1568. {
  1569. Serial.println("record_fichier_FRQ_FM_PRST()");
  1570.  
  1571. File file1 = SPIFFS.open("/FRQ_FM_PRST.txt", FILE_WRITE);
  1572. String s1;
  1573.  
  1574. for(uint8_t n=0; n<8; n++)
  1575. {
  1576. s1 = "<";
  1577. s1 += String(presetPad1.bt_preset[n].frequence_FM);
  1578. s1 +=">";
  1579. file1.println(s1);
  1580. }
  1581. file1.close();
  1582. }
  1583.  
  1584.  
  1585. void record_fichier_FRQ_AIR_PRST()
  1586. {
  1587. Serial.println("record_fichier_FRQ_AIR_PRST()");
  1588.  
  1589. File file1 = SPIFFS.open("/FRQ_AIR_PRST.txt", FILE_WRITE);
  1590. String s1;
  1591.  
  1592. for(uint8_t n=0; n<8; n++)
  1593. {
  1594. s1 = "<";
  1595. s1 += String(presetPad1.bt_preset[n].frequence_AIR);
  1596. s1 +=">";
  1597. file1.println(s1);
  1598. }
  1599. file1.close();
  1600. }
  1601.  
  1602.  
  1603. void traite_boutons_presetPad(uint8_t n_bt)
  1604. {
  1605. if (n_bt > 7) {return;}
  1606.  
  1607. uint16_t c1 = GRIS_5;
  1608. uint16_t c2 = JAUNE;
  1609. uint32_t adr0, adr1, adr2, adr;
  1610.  
  1611. if (mode_affi == NORMAL)
  1612. {
  1613. // Lit la frequence dans le bouton concerné (VOIR: 'class TOUCH_BOUTON_PRESET')
  1614. if(bande_active == SW) {frequence = presetPad1.bt_preset[n_bt].frequence_SW;}
  1615. if(bande_active == FM) {frequence = presetPad1.bt_preset[n_bt].frequence_FM;}
  1616. if(bande_active == AIR) {frequence = presetPad1.bt_preset[n_bt].frequence_AIR;}
  1617. }
  1618.  
  1619. if (mode_affi == SET_F_PRESET)
  1620. {
  1621. if(bande_active == SW)
  1622. {
  1623. presetPad1.bt_preset[n_bt].frequence_SW = frequence; // en RAM
  1624. record_fichier_FRQ_SW_PRST();
  1625. mode_affi = NORMAL;
  1626. delay(500);
  1627. }
  1628. if(bande_active == FM)
  1629. {
  1630. presetPad1.bt_preset[n_bt].frequence_FM = frequence;
  1631. record_fichier_FRQ_FM_PRST();
  1632. mode_affi = NORMAL;
  1633. delay(500);
  1634. }
  1635. if(bande_active == AIR)
  1636. {
  1637. presetPad1.bt_preset[n_bt].frequence_AIR = frequence;
  1638. record_fichier_FRQ_AIR_PRST();
  1639. mode_affi = NORMAL;
  1640. delay(500);
  1641. }
  1642.  
  1643. mode_affi = NORMAL;
  1644. vu_metre_actif = true;
  1645. init_affichages();
  1646. }
  1647.  
  1648. if (mode_affi == COUL) // saisie couleur fond d'écran
  1649. {
  1650. mode_affi = NORMAL;
  1651.  
  1652. couleur_fond_ecran = presetPad1.bt_preset[n_bt].couleur;
  1653. record_fichier_params();
  1654.  
  1655. vu_metre_actif = true;
  1656. init_affichages();
  1657. }
  1658.  
  1659.  
  1660. affiche_frequence(frequence);
  1661. TFT.setTextColor(JAUNE, NOIR);
  1662. TFT.setFreeFont(FF0);
  1663. Tune_Frequence(frequence);
  1664. }
  1665.  
  1666.  
  1667.  
  1668. uint32_t inc_Frq_in_groupe(GROUPE_FREQUENCES *groupe_Freq, int8_t di) // di = +/-1
  1669. {
  1670. if ((di<-1)||(di>1)) {return 0;}
  1671.  
  1672. uint16_t n_max = groupe_Freq->nb_freq;
  1673.  
  1674. uint16_t n = groupe_Freq->num_F_actuelle;
  1675.  
  1676. if(n_max > 99) {n_max = 99;}
  1677.  
  1678. if (di == 1)
  1679. {
  1680. if (n<n_max-1) { n++; }
  1681. else if (n >= (n_max-1)) {n=0;}
  1682. }
  1683.  
  1684. if (di == -1)
  1685. {
  1686. if (n>=1) { n--; }
  1687. else if (n==0) {n = n_max-1;}
  1688. }
  1689.  
  1690. if(n > 99) {n = 0;}
  1691.  
  1692. groupe_Freq->num_F_actuelle = n;
  1693. uint16_t adr = groupe_Freq->adr_1ere_frq + n;
  1694.  
  1695. uint8_t nb_F = groupe_Freq->nb_freq;
  1696. uint8_t num_1ere_F = groupe_Freq->adr_1ere_frq;
  1697. affiche_numero_frq(String(1 + adr - num_1ere_F), String(nb_F));
  1698.  
  1699. uint32_t valeur_lue = groupe_Freq->G_freq[adr];
  1700. return valeur_lue;
  1701.  
  1702. }
  1703.  
  1704.  
  1705.  
  1706. void test_clic_boutons_plus_moins()
  1707. {
  1708. uint16_t c1 = GRIS_6;
  1709. uint16_t c2 = GRIS_3;
  1710.  
  1711. boolean bouton_cliked = false;
  1712. efface_box_entete2();
  1713.  
  1714. //--------------------------------------------------------------------
  1715. if(mode_s == _FRQ) // on va modifier directement la fréquence
  1716. {
  1717. test_clic_boutons(&bt_plus );
  1718. bt_plus.affiche(c1, c2, 1);
  1719. if (bt_plus.cliked)
  1720. {
  1721. frequence += saut_freq;
  1722. bouton_cliked = true;
  1723. }
  1724.  
  1725. delay(20);
  1726. if (bt_plus.cliked && ((frequence + saut_freq) <= 138000 ))
  1727. {
  1728. Tune_Frequence(frequence);
  1729. }
  1730.  
  1731. bt_plus.cliked = false;
  1732. bt_plus.selected = false;
  1733. bt_plus.affiche(c1, c2, 1); // fugitif
  1734.  
  1735. test_clic_boutons(&bt_moins );
  1736. bt_moins.affiche(c1, c2, 1);
  1737. delay(20);
  1738. if (bt_moins.cliked)
  1739. {
  1740. if (frequence > saut_freq) // évite de se retrouver avec une F négative !
  1741. {
  1742. bouton_cliked = true;
  1743. frequence -= saut_freq;
  1744. }
  1745. }
  1746.  
  1747. if(bt_moins.cliked && frequence > saut_freq) { Tune_Frequence(frequence); }
  1748. bt_moins.cliked = false;
  1749. bt_moins.selected = false;
  1750. bt_moins.affiche(c1, c2, 1); // fugitif
  1751.  
  1752. if(bouton_cliked == true)
  1753. {
  1754. bouton_cliked = false;
  1755. affiche_frequence(frequence);
  1756. }
  1757. }
  1758.  
  1759. //-------------------------------------------------------------------------
  1760.  
  1761. if(mode_s == _MEM) // on va parcourir les fréquences de la liste
  1762. {
  1763. test_clic_boutons(&bt_plus );
  1764. bt_plus.affiche(c1, c2, 1);
  1765. if (bt_plus.cliked)
  1766. {
  1767. bouton_cliked = true;
  1768.  
  1769. Serial.println("bt_plus.cliked");
  1770.  
  1771. if(groupe_actif == gSW) { frequence = inc_Frq_in_groupe(&groupe_SW, 1); }
  1772. if(groupe_actif == gFM) { frequence = inc_Frq_in_groupe(&groupe_FM, 1); }
  1773. if(groupe_actif == gAIR) { frequence = inc_Frq_in_groupe(&groupe_AIR, 1); }
  1774. if(groupe_actif == gSCN) { frequence = inc_Frq_in_groupe(&groupe_SCAN, 1); }
  1775.  
  1776. Tune_Frequence(frequence);
  1777. delay(100);
  1778. }
  1779.  
  1780. bt_plus.cliked = false;
  1781. bt_plus.selected = false;
  1782. bt_plus.affiche(c1, c2, 1); // fugitif
  1783.  
  1784. test_clic_boutons(&bt_moins );
  1785. bt_moins.affiche(c1, c2, 1);
  1786. delay(20);
  1787. if (bt_moins.cliked)
  1788. {
  1789. bouton_cliked = true;
  1790.  
  1791. Serial.println("bt_moins.cliked");
  1792.  
  1793. if(groupe_actif == gSW) { frequence = inc_Frq_in_groupe(&groupe_SW, -1); }
  1794. if(groupe_actif == gFM) { frequence = inc_Frq_in_groupe(&groupe_FM, -1); }
  1795. if(groupe_actif == gAIR) { frequence = inc_Frq_in_groupe(&groupe_AIR, -1); }
  1796. if(groupe_actif == gSCN) { frequence = inc_Frq_in_groupe(&groupe_SCAN, -1); }
  1797.  
  1798. Tune_Frequence(frequence);
  1799. delay(100);
  1800. }
  1801.  
  1802. bt_moins.cliked = false;
  1803. bt_moins.selected = false;
  1804. bt_moins.affiche(c1, c2, 1); // fugitif
  1805.  
  1806. if(bouton_cliked == true)
  1807. {
  1808. bouton_cliked = false;
  1809. affiche_frequence(frequence);
  1810. }
  1811. }
  1812. }
  1813.  
  1814.  
  1815. void test_clic_bt_RST_affi() // bouton "ok" de la box saisie couleur de fond ecran
  1816. {
  1817. if(mode_affi != COUL) {return;}
  1818.  
  1819. uint16_t c1 = GRIS_6;
  1820. uint16_t c2 = JAUNE;
  1821.  
  1822. test_clic_boutons(&bt_RST_affi );
  1823.  
  1824. if (bt_RST_affi.cliked)
  1825. {
  1826. bt_RST_affi.cliked = false;
  1827. bt_RST_affi.selected = true;
  1828. bt_RST_affi.affiche(NOIR, VERT, 1);
  1829.  
  1830. init_affichages();
  1831. }
  1832. }
  1833.  
  1834.  
  1835. void test_clic_bt_affi_saisie_couleur() // bouton au coin en bas à droite
  1836. {
  1837. uint16_t c1 = GRIS_5;
  1838. uint16_t c2 = BLANC;
  1839.  
  1840. test_clic_boutons(&bt_affi_saisie_couleur );
  1841.  
  1842. if (bt_affi_saisie_couleur.cliked)
  1843. {
  1844. bt_affi_saisie_couleur.cliked = false;
  1845. bt_affi_saisie_couleur.selected = true;
  1846. bt_affi_saisie_couleur.affiche(NOIR, VERT, 1);
  1847.  
  1848. vu_metre_actif = false;
  1849. TFT.fillRect(x0_box_info2, y0_box_info2, dx_box_info2, dy_box_info2, NOIR);
  1850.  
  1851. TFT.setTextColor(VERT, NOIR);
  1852. TFT.setFreeFont(FF0);
  1853. TFT.drawString("Cliquez sur un des 8 bt", x0_box_info2+2, y0_box_info2+2);
  1854. TFT.drawString("'preset' pour choisir", x0_box_info2+2, y0_box_info2+12);
  1855. TFT.drawString("la couleur de fond", x0_box_info2+2, y0_box_info2+22);
  1856.  
  1857. mode_affi = COUL;
  1858.  
  1859. presetPad1.init(x0_box_PRESET +5, y0_box_PRESET +5);
  1860. }
  1861. }
  1862.  
  1863.  
  1864.  
  1865. void test_clic_bouton_mute()
  1866. {
  1867. test_clic_boutons(&bt_mute );
  1868.  
  1869. if (bt_mute.cliked)
  1870. {
  1871. bt_mute.affiche(NOIR, ROUGE, 1);
  1872. delay(100);
  1873.  
  1874. bt_mute.cliked = false;
  1875. if(mute == false) {mute = true;} else {mute = false;}
  1876. Set_Mute(mute); // fonction située dans le fichier 'driverTEF6686_628.h'
  1877. bt_mute.selected = mute;
  1878. bt_mute.affiche(NOIR, ROUGE, 1);
  1879. if (mute == false) {Tune_Frequence(frequence);}
  1880. delay(500);
  1881. }
  1882. }
  1883.  
  1884.  
  1885. void test_clic_bouton_info()
  1886. {
  1887. test_clic_boutons(&bt_info);
  1888. if (bt_info.cliked)
  1889. {
  1890. bt_info.cliked = false;
  1891. bt_info.selected = true;
  1892. bt_info.affiche(NOIR, VERT, 1);
  1893. delay(100);
  1894.  
  1895. // affiche une page d'information:
  1896.  
  1897. TFT.fillScreen(NOIR);
  1898. TFT.setTextColor(JAUNE, NOIR);
  1899. TFT.setFreeFont(FF1);
  1900. uint16_t y=0;
  1901. TFT.drawString("Radio TEF6686", 0, y); y+=20;
  1902. String s1="version " + version;
  1903. TFT.drawString(s1, 0, y); y+=20;
  1904.  
  1905. TFT.setTextColor(CYAN, NOIR);
  1906. TFT.drawString("Silicium628", 0, y); y+=40;
  1907.  
  1908. TFT.setTextColor(BLANC, NOIR);
  1909. TFT.setFreeFont(FF0);
  1910. TFT.drawString("SW (AM): 1500kHz -- 28MHz", 0, y); y+=20;
  1911. TFT.drawString("bande FM (WFM): 88MHz -- 108MHz", 0, y); y+=20;
  1912. TFT.drawString("bande Aviation Civile: 118MHz -- 137MHz (AM)", 0, y); y+=20;
  1913. delay(300);
  1914.  
  1915. attente_clic();
  1916.  
  1917. }
  1918. }
  1919.  
  1920.  
  1921.  
  1922. void test_clic_bouton_Sleep()
  1923. {
  1924. test_clic_boutons(&bt_sleep );
  1925.  
  1926. if (bt_sleep.cliked)
  1927. {
  1928. bt_sleep.cliked = false;
  1929. bt_sleep.selected = true;
  1930. bt_sleep.affiche(NOIR, ROUGE, 1);
  1931. delay(100);
  1932.  
  1933. //todo: save en SPIFFS
  1934.  
  1935.  
  1936. TFT.fillScreen(NOIR);
  1937. TFT.setTextColor(BLANC, NOIR);
  1938. TFT.setFreeFont(FF1);
  1939. TFT.drawString("Cliquez pour MODE SLEEP", 20, 50);
  1940. TFT.drawString("de l'ESP32", 20, 70);
  1941. TFT.drawString("Eteindre pour quitter", 20, 90);
  1942. TFT.drawString("ce mode SLEEP", 20, 110);
  1943.  
  1944. delay(300);
  1945.  
  1946. attente_clic();
  1947.  
  1948. esp_deep_sleep_start();
  1949. }
  1950. }
  1951.  
  1952.  
  1953. uint16_t read16(fs::File &f)
  1954. {
  1955. uint16_t result;
  1956. ((uint8_t *)&result)[0] = f.read(); // LSB
  1957. ((uint8_t *)&result)[1] = f.read(); // MSB
  1958. return result;
  1959. }
  1960.  
  1961. uint32_t read32(fs::File &f)
  1962. {
  1963. uint32_t result;
  1964. ((uint8_t *)&result)[0] = f.read(); // LSB
  1965. ((uint8_t *)&result)[1] = f.read();
  1966. ((uint8_t *)&result)[2] = f.read();
  1967. ((uint8_t *)&result)[3] = f.read(); // MSB
  1968. return result;
  1969. }
  1970.  
  1971.  
  1972.  
  1973. void affi_image_from_spiffs(String filename, uint16_t x0, uint16_t y0)
  1974. {
  1975. // pour image bmp encodée en RGb565 (5+6+5 = 16 bits)
  1976.  
  1977. uint8_t bmp_data[2]={0,0};
  1978. uint8_t a, b;
  1979. uint16_t x=0;
  1980. uint16_t y=0;
  1981.  
  1982. uint32_t seekOffset;
  1983. uint16_t w, h, row, col;
  1984.  
  1985. File bmpFS = SPIFFS.open(filename, "r");
  1986. if (!bmpFS) { Serial.println("ERREUR open file on SPIFFS"); return; }
  1987. else { Serial.println("open file on SPIFFS ok");}
  1988.  
  1989. int16_t xmax;
  1990.  
  1991. uint16_t etiq1 = read16(bmpFS); // == 0x 4D42)
  1992. Serial.print("etiq1= "); Serial.println(etiq1, HEX); // ok affiche "4D42"
  1993. if (etiq1 == 0x4D42)
  1994. {
  1995. read32(bmpFS);
  1996. read32(bmpFS);
  1997. seekOffset = read32(bmpFS);
  1998. Serial.print("seekOffset= "); Serial.println(seekOffset);
  1999. read32(bmpFS);
  2000. w = read32(bmpFS);
  2001. h = read32(bmpFS);
  2002. Serial.print("w= "); Serial.println(w); // 75
  2003. Serial.print("h= "); Serial.println(h); // 50
  2004. Serial.println(read16(bmpFS)); // 1
  2005. Serial.println(read16(bmpFS)); // 16
  2006. Serial.println(read16(bmpFS)); // 3
  2007. bmpFS.seek(seekOffset);
  2008. }
  2009.  
  2010. y += h;
  2011. xmax = w;
  2012. if(xmax%2 == 1) {xmax +=1;}
  2013.  
  2014. uint16_t padding = (4 - ((w * 2) & 2)) & 2;
  2015. uint8_t lineBuffer[(w*2) + padding];
  2016.  
  2017. for (row = 0; row < h; row++)
  2018. {
  2019. bmpFS.read(lineBuffer, sizeof(lineBuffer));
  2020. uint8_t* bptr = lineBuffer;
  2021. uint16_t* tptr = (uint16_t*)lineBuffer;
  2022.  
  2023. for (uint16_t col = 0; col < w; col++)
  2024. {
  2025. a = *bptr++;
  2026. b = *bptr++;
  2027. *tptr++ = (a <<8 | b);
  2028. }
  2029. TFT.pushImage(x0 + x, y0 + y, w, 1, (uint16_t*)lineBuffer);
  2030. y--;
  2031. }
  2032. bmpFS.close();
  2033.  
  2034. }
  2035.  
  2036.  
  2037. /*
  2038. void ajout_1_freq()
  2039. {
  2040. // AJOUT d'une fréquence en fin d'une liste de fréquences. Travaille directement sur la mémoire SPIFFS
  2041. File file = SPIFFS.open("/FRQ_FM.txt", FILE_APPEND);
  2042. file.print("<88800>"); // ok ; attention à ne pas oublier les < >
  2043. file.close(); // enregistre CE fichier en mémoire SPIFFS, sans toucher aux autres
  2044. delay(100);
  2045. }
  2046. */
  2047.  
  2048.  
  2049. void test_clic_bouton_TEST()
  2050. {
  2051. test_clic_boutons(&bt_TEST );
  2052. bt_TEST.affiche(NOIR, ROUGE, 1);
  2053. delay(100);
  2054. if (bt_TEST.cliked)
  2055. {
  2056. Serial.println("-------------------------------");
  2057. Serial.println("bt_TEST.cliked");
  2058. bt_TEST.cliked = false;
  2059. bt_TEST.selected = true;
  2060. bt_TEST.affiche(NOIR, ROUGE, 1);
  2061.  
  2062. //TFT.fillscreen(GRIS_3); // effface
  2063. //affi_image_from_spiffs("/7.bmp");
  2064. //ajout_1_freq();
  2065. /*
  2066. uint16_t dx= 40;
  2067. uint16_t dy =30;
  2068. uint16_t memo_line_H[dx*dy];
  2069. TFT.readRect(20, 20 , dx, dy, memo_line_H);
  2070. TFT.pushRect(100, 100, dx, dy, memo_line_H);
  2071. */
  2072.  
  2073. String s1;
  2074. for (int n=0; n<10; n++)
  2075. {
  2076. s1 = read_line_params(n);
  2077. Serial.println(s1);
  2078. }
  2079.  
  2080. bt_TEST.cliked = false;
  2081. bt_TEST.selected = false;
  2082. bt_TEST.affiche(NOIR, ROUGE, 1);
  2083.  
  2084. //init_affichages();
  2085. Serial.println("-------------------------------");
  2086. }
  2087. }
  2088.  
  2089.  
  2090. void test_clic_Bt_reset()
  2091. {
  2092. test_clic_boutons(&bt_reset );
  2093. bt_reset.affiche(GRIS_6, NOIR, 1);
  2094. delay(100);
  2095. if (bt_reset.cliked)
  2096. {
  2097. bt_reset.cliked = false;
  2098. bt_reset.selected = true;
  2099. bt_reset.affiche(GRIS_6, VERT, 1);
  2100.  
  2101. delay(100);
  2102. bt_reset.selected = false;
  2103. bt_reset.affiche(GRIS_6, VERT, 1);
  2104.  
  2105. setup();
  2106. }
  2107. }
  2108.  
  2109.  
  2110. void test_clic_bt_LEV()
  2111. {
  2112. test_clic_boutons(&bt_LEV);
  2113. if (bt_LEV.cliked)
  2114. {
  2115. bt_LEV.cliked = false;
  2116. bt_LEV.selected = true; bt_LEV.affiche(NOIR, VERT, 1);
  2117. bt_SNR.selected = false; bt_SNR.affiche(NOIR, VERT, 1);
  2118. mode_seuil = LEV;
  2119. }
  2120. }
  2121.  
  2122.  
  2123. void test_clic_bt_SNR()
  2124. {
  2125. test_clic_boutons(&bt_SNR);
  2126. if (bt_SNR.cliked)
  2127. {
  2128. bt_SNR.cliked = false;
  2129. bt_SNR.selected = true; bt_SNR.affiche(NOIR, VERT, 1);
  2130. bt_LEV.selected = false; bt_LEV.affiche(NOIR, VERT, 1);
  2131. mode_seuil = SNR;
  2132. }
  2133. }
  2134.  
  2135.  
  2136.  
  2137. void test_clic_bt_stop_scan()
  2138. {
  2139. test_clic_boutons(&bt_stop_scan);
  2140. if (bt_stop_scan.cliked)
  2141. {
  2142. Serial.println("STOP scan");
  2143. bt_stop_scan.affiche(NOIR, BLANC, 1);
  2144. mode_affi = NORMAL;
  2145. bt_stop_scan.cliked = false;
  2146. bt_stop_scan.affiche(NOIR, BLANC, 1);
  2147. }
  2148. }
  2149.  
  2150.  
  2151. void test_clic_bt_annuler() // sur la petite fenêtre surgissante d'info
  2152. {
  2153. test_clic_boutons(&bt_annuler);
  2154. if (bt_annuler.cliked)
  2155. {
  2156. bt_stop_scan.cliked = false;
  2157. bt_stop_scan.affiche(NOIR, BLANC, 1);
  2158.  
  2159. mode_affi = NORMAL; // ce qui repasse les boutons 'preset' en mode sélection et empêche l'écriture en SPIFFS
  2160. vu_metre_actif = true;
  2161. init_affichages();
  2162. }
  2163. }
  2164.  
  2165.  
  2166. /*
  2167. MODES DE SCAN
  2168. 1-scan_frq() : tt fréquences d'une bande (ex: FM). Mise en mémoire temporaire (en RAM) des stations actives.
  2169. 2-scan_mem_AIR() : cannaux occupés (pour la bande aviation) - pas de mise en mémoire mais stop si message reçu
  2170. puis reprise auto du scan à la fin du message.
  2171. */
  2172.  
  2173. //enum MODE_SEUIL {LEV, SNR}; // level ou signal/bruit
  2174. //MODE_SEUIL mode_seuil = LEV;
  2175.  
  2176.  
  2177. void scan_mem_AIR()
  2178. {
  2179. Serial.println("scan_mem_AIR()");
  2180. bande_active = AIR;
  2181.  
  2182. efface_box_GROUPE();
  2183.  
  2184. uint16_t couleur_ciel = 10739;
  2185.  
  2186.  
  2187. TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, couleur_ciel);
  2188. affi_image_from_spiffs("/avion1.bmp", 1, 80);
  2189.  
  2190.  
  2191. affiche_box_scan(dy_box_SCAN);
  2192.  
  2193. TFT.setFreeFont(FF0);
  2194. TFT.setTextColor(JAUNE, NOIR);
  2195. //TFT.drawString("air", x0_box_SCAN +110 , y0_box_SCAN + 5); // titre
  2196.  
  2197. TFT.fillRect(2, 2, 42, 80, couleur_ciel); // efface
  2198. affi_image_from_spiffs("/avion3.bmp", 1, 15);
  2199. affi_image_from_spiffs("/PFD42x28.bmp", 1, 40);
  2200.  
  2201.  
  2202. String si;
  2203. uint16_t y;
  2204. uint16_t xi, yi;
  2205. int16_t dy;
  2206.  
  2207. int16_t attente =0;
  2208. int16_t signal_i;
  2209. uint16_t base = y0_box_SCAN + dy_box_SCAN -5; // bas du graphique
  2210. uint16_t memo_line_H[320];
  2211. //boolean memo_line_OK = false;
  2212.  
  2213. mode_seuil = SNR; //2 types de détection possibles: LEV(level) et SNR(signal-to-noise ratio = signal/bruit)
  2214. bt_SNR.selected = true; bt_SNR.affiche(NOIR, VERT, 1);
  2215. bt_LEV.selected = false; bt_LEV.affiche(NOIR, VERT, 1);
  2216.  
  2217. TFT.setFreeFont(FM9);
  2218. TFT.setTextColor(JAUNE, NOIR);
  2219.  
  2220. frequence = 124075;
  2221. Tune_Frequence(frequence);
  2222. affiche_frequence(frequence);
  2223.  
  2224. //TFT.drawFastHLine(5, base -seuil/10, 320, GRIS_6); // seuil (trait horizontal sur toute la largeur)
  2225. TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne
  2226.  
  2227. while(mode_affi == SCAN_M)
  2228. {
  2229. y = y0_box_SCAN + 5;
  2230. uint8_t module;
  2231. if(bande_active == FM) {module = 32;} else {module = 33;}
  2232. Get_Quality( module, &status, &level, &usn, &wam, &offset, &bandwidth, &mod, &snr );
  2233.  
  2234. si = String(level);
  2235. TFT.drawString("level", x0_box_SCAN +25 , y);
  2236. TFT.drawString(si+" ", x0_box_SCAN +65 , y);
  2237. y+=15;
  2238.  
  2239. si = String(snr);
  2240. TFT.drawString("snr", x0_box_SCAN +25 , y);
  2241. TFT.drawString(si+" ", x0_box_SCAN +65 , y);
  2242. y+=20;
  2243.  
  2244. if (mode_seuil == LEV) { signal_i = level; } // attention! level peut être négatif (échelle log)
  2245. if (mode_seuil == SNR) { signal_i= 16 * snr; }
  2246.  
  2247. dy = signal_i/10;
  2248. if(dy<0) {dy=0;}
  2249. dy+=2;
  2250.  
  2251. // petites barres verticales
  2252. xi = (frequence - 120000)/50;
  2253. // xi(120MHz) = 0 px;
  2254. // xi(136MHz) = (136000 - 120000) /50 = 320 px
  2255.  
  2256. TFT.drawFastVLine(xi, base-50, 50, couleur_ciel); // 95 efface
  2257. uint16_t c0 = BLEU;
  2258. if(signal_i > seuil*10){c0 = JAUNE;}
  2259. TFT.drawFastVLine(xi, base -dy, dy, c0);
  2260.  
  2261. if(signal_i > seuil*10)
  2262. {
  2263. TFT.fillRect(x0_box_SCAN +100, y0_box_SCAN + 20, 20, 20, VERT); // carré coloré
  2264. attente = 2;
  2265. }
  2266. else attente --;
  2267.  
  2268. if (attente <=0)
  2269. {
  2270. TFT.fillRect(x0_box_SCAN +100, y0_box_SCAN + 20, 20, 20, GRIS_5); // carré coloré
  2271. frequence = inc_Frq_in_groupe(&groupe_AIR, 1);
  2272. Tune_Frequence(frequence);
  2273. affiche_frequence(frequence);
  2274. TFT.setFreeFont(FF0);
  2275. TFT.setTextColor(BLANC, NOIR);
  2276. TFT.drawString("120MHz", x0_box_SCAN +5 , base-10);
  2277. TFT.drawString("136", x0_box_SCAN +dx_box_SCAN -22, base-10);
  2278.  
  2279. attente =0;
  2280. }
  2281.  
  2282. delay(50); // ne pas réduire, temps nécessaire pour accrocher la fréquence
  2283.  
  2284. if (ts.tirqTouched() && ts.touched())
  2285. {
  2286. TS_Point p = ts.getPoint();
  2287. x_touch = eTS.x0 + p.x /eTS.dx;
  2288. y_touch = eTS.y0 + p.y /eTS.dy;
  2289. test_clic_bt_stop_scan();
  2290.  
  2291. test_clic_boutons(&bt_seuil_plus);
  2292. if (bt_seuil_plus.cliked)
  2293. {
  2294. bt_seuil_plus.cliked = false;
  2295. TFT.pushRect(0, base - memo_seuil, 319, 1, memo_line_H); // efface avec l'image enregistrée
  2296. memo_seuil = seuil;
  2297. seuil += 1;
  2298. if (seuil > 120) {seuil = 120;}
  2299. TFT.readRect(0, base - seuil , 318, 1, memo_line_H); // mémorise la ligne avant de tracer
  2300. TFT.drawFastHLine(5, base -seuil, 318, GRIS_6); // seuil (trait horizontal sur toute la largeur)
  2301. TFT.setFreeFont(FF0); TFT.setTextColor(BLANC, NOIR);
  2302. si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +185 , y0_box_SCAN +23);
  2303. }
  2304.  
  2305. test_clic_boutons(&bt_seuil_moins);
  2306. if (bt_seuil_moins.cliked)
  2307. {
  2308. bt_seuil_moins.cliked = false;
  2309. TFT.pushRect(0, base - memo_seuil, 319, 1, memo_line_H); // efface avec l'image enregistrée
  2310. memo_seuil = seuil;
  2311. seuil -= 1;
  2312. if (seuil < 5) {seuil = 5;}
  2313. TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
  2314. TFT.drawFastHLine(5, base -seuil, 319, GRIS_6); // seuil (trait horizontal sur toute la largeur)
  2315. TFT.setFreeFont(FF0); TFT.setTextColor(BLANC, NOIR);
  2316. si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +185 , y0_box_SCAN +23);
  2317. }
  2318.  
  2319. test_clic_bt_LEV();
  2320. test_clic_bt_SNR();
  2321.  
  2322. test_clic_boutons(&bt_stop_scan);
  2323. }
  2324. }
  2325.  
  2326. //delay(1000);
  2327.  
  2328. mode_s = _MEM;
  2329. mode_affi = NORMAL;
  2330. bande_active = FM;
  2331. bt_mode_MEM.selected = true; bt_mode_MEM.affiche(GRIS_6, VERT, 2);
  2332. bt_mode_FRQ.selected = false; bt_mode_FRQ.affiche(GRIS_6, VERT, 2);
  2333.  
  2334. //boutons_preset_set_frequences();
  2335. init_affichages();
  2336. frequence = 89400;
  2337. Tune_Frequence(frequence);
  2338. affiche_frequence(frequence);
  2339.  
  2340. bt_FM.selected = true; bt_FM.affiche(GRIS_6, VERT, 1);
  2341. bt_AIR.selected = false; bt_AIR.affiche(GRIS_6, VERT, 1);
  2342. }
  2343.  
  2344.  
  2345.  
  2346. void scan_frq() // toutes les fréquences de la bande, incrémental, saut_freq = constant
  2347. {
  2348. Serial.println("scan_frq()");
  2349. if(bande_active == SCN) {bande_active = FM;}
  2350.  
  2351. String si;
  2352. String s1;
  2353. String sA, sB;
  2354. float xi=0;
  2355. uint32_t xi32;
  2356. uint16_t y;
  2357. int16_t dy;
  2358. uint16_t yi;
  2359. uint16_t memo_x_touch = 0;
  2360. uint16_t nb_F;
  2361. int16_t signal_i;
  2362. uint16_t base = y0_box_SCAN + dy_box_SCAN -5; // bas du graphique
  2363.  
  2364. uint16_t decal_x;
  2365. uint16_t decal_y;
  2366. int n_max;
  2367.  
  2368. TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, NOIR);
  2369. memo_frequence_scan = frequence; // variables globales
  2370.  
  2371. mode_seuil = SNR; //2 types de détection possibles: LEV(level) et SNR(signal-to-noise ratio = signal/bruit)
  2372. bt_SNR.selected = true; bt_SNR.affiche(NOIR, VERT, 1);
  2373. bt_LEV.selected = false; bt_LEV.affiche(NOIR, VERT, 1);
  2374.  
  2375. groupe_SCAN.RAZ();
  2376. efface_box_GROUPE();
  2377.  
  2378. TFT.setFreeFont(FM9);
  2379. TFT.setTextColor(JAUNE, NOIR);
  2380. TFT.setFreeFont(FF0);
  2381.  
  2382. uint8_t module;
  2383. if(bande_active == FM)
  2384. {
  2385. TFT.drawString("SCAN bande FM", x0_box_SCAN +50 , y0_box_SCAN + 10); // titre
  2386. frequence = 88000;
  2387. saut_freq = 100; // kHz
  2388. module = 32;
  2389. n_max = 190;
  2390. }
  2391. else
  2392. {
  2393. TFT.drawString("SCAN bande SW", x0_box_SCAN +50 , y0_box_SCAN + 10);
  2394. //frequence = 12000; // 12MHz...
  2395. saut_freq = 5; // kHz
  2396. module = 33;
  2397. n_max = 200;
  2398. }
  2399.  
  2400. y = y0_box_SCAN + 5;
  2401. decal_x=0;
  2402. decal_y=0;
  2403. nb_F=0;
  2404.  
  2405. TFT.drawFastHLine(5, base -seuil/10, 320, GRIS_6); // seuil (trait horizontal sur toute la largeur)
  2406.  
  2407. sA = String(frequence);
  2408. sB = String(frequence + n_max * saut_freq);
  2409. TFT.drawString(sA, x0_box_SCAN +5 , base-5);
  2410. TFT.drawString(sB, x0_box_SCAN +dx_box_SCAN -32, base-5);
  2411.  
  2412. boolean rescan = false;
  2413. do
  2414. {
  2415. groupe_SCAN.RAZ();
  2416. nb_F = 0;
  2417. affiche_box_scan(dy_box_SCAN);
  2418. uint32_t freq_min = frequence;
  2419.  
  2420. //......................................................................
  2421. int n = n_max;
  2422. while(n>0)
  2423. {
  2424. frequence += saut_freq;
  2425. affiche_frequence(frequence);
  2426.  
  2427. if( (frequence + saut_freq) <= 138000 )
  2428. {
  2429. Tune_Frequence(frequence);
  2430. delay(15);
  2431. }
  2432.  
  2433. if(bande_active == FM) {module = 32;} else {module = 33;}
  2434. Get_Quality( module, &status, &level, &usn, &wam, &offset, &bandwidth, &mod, &snr );
  2435.  
  2436. delay(50);
  2437.  
  2438. //if(bande_active == SW) {xi += 1.6;}
  2439. //if(bande_active == FM) {xi += 2;}
  2440. xi += 1.6;
  2441.  
  2442. if (mode_seuil == LEV) { signal_i = level; } // attention! level peut être négatif (échelle log)
  2443. if (mode_seuil == SNR) { signal_i= 16 * snr; }
  2444.  
  2445. dy = signal_i/10;
  2446. if(dy<0) {dy=0;}
  2447. dy+=2;
  2448.  
  2449. uint16_t c1 = VERT;
  2450. if(dy>30){c1 = JAUNE;}
  2451. if(dy>40){c1 = ORANGE;}
  2452. if(dy>50){c1 = BLEU_CLAIR;}
  2453.  
  2454. xi32 = x0_box_SCAN + (uint32_t)xi;
  2455.  
  2456. if (xi32 < 318) // limite d'affichage à droite pour ne pas abimer le cadre
  2457. {
  2458. //TFT.drawFastVLine(xi32, base-dy, dy, c1); // petites barres verticales
  2459. // on va les tracer point par point afin de pouvoir les coloriser
  2460. int a = base;
  2461. int b = a - dy;
  2462. for(int n=b; n<a; n++)
  2463. {
  2464. c1 = BLEU;
  2465. if(n>180){c1 = VERT;}
  2466. if(n>190){c1 = JAUNE;}
  2467. if(n>200){c1 = ORANGE;}
  2468. if(n>215){c1 = ROUGE;}
  2469. //c1 = 10 * n *n;
  2470. TFT.drawPixel(xi32, n, c1);
  2471. }
  2472. }
  2473.  
  2474. if(signal_i > seuil) // DETECTION
  2475. {
  2476. if (decal_y > 5) // concerne l'affichage des textes (fréquences trouvées)
  2477. {
  2478. decal_y = 0;
  2479. decal_x ++;
  2480. }
  2481.  
  2482. if((nb_F % 25) == 0) // limite le nb de freq affichées simultanément à 25
  2483. {
  2484. affiche_box_scan(dy_box_SCAN/2);
  2485. decal_x = 0;
  2486. decal_y = 0;
  2487. }
  2488.  
  2489. s1 = String(frequence);
  2490. TFT.setTextColor(BLANC, NOIR);
  2491. TFT.drawString(s1, x0_box_SCAN + 2 + 45*decal_x, y0_box_SCAN + 9*decal_y); // affiche FREQUENCE
  2492. nb_F++;
  2493.  
  2494. TFT.setFreeFont(FM9);
  2495. TFT.setTextColor(VERT, NOIR);
  2496. s1 = String(nb_F);
  2497. TFT.drawString(s1, x0_box_SCAN +215 , y0_box_SCAN + 6); // nb freq
  2498. TFT.setFreeFont(FF0);
  2499.  
  2500. groupe_SCAN.add_frq(frequence); // AJOUTE la fréquence trouvée au groupe spécial 'groupe_SCAN'
  2501. decal_y ++;
  2502.  
  2503. if(groupe_SCAN.nb_freq >= 100) // groupe plein (en RAM)
  2504. {
  2505. s1 = String(frequence);
  2506. TFT.setTextColor(ROUGE, NOIR);
  2507. TFT.drawString(s1+" groupe SC plein", x0_box_SCAN +80 , y0_box_SCAN + 60);
  2508. TFT.setTextColor(BLANC, NOIR);
  2509. n=0;
  2510. }
  2511. }
  2512. n--;
  2513.  
  2514. if(seuil != memo_seuil)
  2515. {
  2516. TFT.drawFastHLine(5, base -memo_seuil/10, 310, NOIR); // efface
  2517. TFT.drawFastHLine(5, base -seuil/10, 310, GRIS_6); // seuil (trait horizontal sur toute la largeur)
  2518. TFT.setTextColor(JAUNE, NOIR);
  2519. si = "seuil:" + String(seuil); TFT.drawString(si+" ", x0_box_SCAN +185 , y0_box_SCAN +23);
  2520. }
  2521.  
  2522.  
  2523. delay(10); // ne pas réduire, temps nécessaire pour accrocher la fréquence
  2524. //delay(300); // pour balayage lent
  2525.  
  2526. if (ts.tirqTouched() && ts.touched()) // écran tactile
  2527. {
  2528. TS_Point p = ts.getPoint();
  2529. x_touch = eTS.x0 + p.x /eTS.dx;
  2530. y_touch = eTS.y0 + p.y /eTS.dy;
  2531.  
  2532. test_clic_boutons(&bt_seuil_plus);
  2533. if (bt_seuil_plus.cliked)
  2534. {
  2535. bt_seuil_plus.cliked = false;
  2536. memo_seuil = seuil;
  2537. seuil += 5;
  2538. }
  2539.  
  2540. test_clic_boutons(&bt_seuil_moins);
  2541. if (bt_seuil_moins.cliked)
  2542. {
  2543. bt_seuil_moins.cliked = false;
  2544. memo_seuil = seuil;
  2545. seuil -= 5;
  2546. si = String(seuil); TFT.drawString(si+" ", x0_box_SCAN +55 , y);
  2547. }
  2548.  
  2549. // modes de détection :
  2550. test_clic_bt_LEV(); // mode Level
  2551. test_clic_bt_SNR(); // mode Signal / bruit
  2552.  
  2553. test_clic_boutons(&bt_re_scan);
  2554. if (bt_re_scan.cliked)
  2555. {
  2556. bt_re_scan.cliked = false;
  2557. affiche_box_scan(dy_box_SCAN); // efface le tracé et re-dessine les boutons dans la boite
  2558. frequence = memo_frequence_scan; // on repart de ma même frequence
  2559. n = n_max;
  2560. xi =0; // départ tracé à gauche
  2561. decal_x=0; // textes fréquences trouvées
  2562. decal_y=0;
  2563. nb_F=0;
  2564. }
  2565.  
  2566. test_clic_boutons(&bt_stop_scan);
  2567. if (bt_stop_scan.cliked)
  2568. {
  2569. n=0; // force la sortie de la boucle while()
  2570. }
  2571. }
  2572. } // fin de la boucle while()
  2573. //.......................................................................
  2574. TFT.setTextColor(CYAN, NOIR);
  2575. TFT.setFreeFont(FF0);
  2576. TFT.drawString("On peut ecouter les freq", 10, 140);
  2577. TFT.drawString("en deplacant le stylet sur le spectre", 10, 150);
  2578.  
  2579. boolean stop = false;
  2580.  
  2581. while (! stop) // attend une action en fin de scan (par ex: clic sur bouton 'stop_scan' [x]) ou [re_scan]
  2582. {
  2583. if (ts.tirqTouched() && ts.touched())
  2584. {
  2585. TS_Point p = ts.getPoint();
  2586. x_touch = eTS.x0 + p.x /eTS.dx;
  2587. y_touch = eTS.y0 + p.y /eTS.dy;
  2588.  
  2589. if((x_touch != memo_x_touch) && (y_touch > 170)) // écoute de la fréquence pointée avec le stylet
  2590. {
  2591. TFT.drawFastVLine(memo_x_touch, base, 4, NOIR); // efface
  2592. TFT.drawFastVLine(x_touch, base, 4, BLANC);
  2593.  
  2594. TFT.drawFastVLine(memo_x_touch, base-50, 4, NOIR); // efface
  2595. TFT.drawFastVLine(x_touch, base-50, 4, BLANC);
  2596.  
  2597. memo_x_touch = x_touch ;
  2598.  
  2599. float dF = (x_touch - x0_box_SCAN) * saut_freq / 1.6;
  2600. uint32_t F1 = freq_min + uint32_t(dF);
  2601. frequence = F1;
  2602. affiche_frequence(frequence);
  2603. Tune_Frequence(frequence);
  2604. String sF1 = String(F1);
  2605. TFT.drawString(sF1, 200, 100);
  2606. }
  2607.  
  2608. test_clic_boutons(&bt_re_scan);
  2609. if (bt_re_scan.cliked)
  2610. {
  2611. bt_re_scan.cliked = false;
  2612. frequence = memo_frequence_scan; // on repart de ma même frequence
  2613. xi=0;
  2614. xi32 = x0_box_SCAN + (uint32_t)xi;
  2615. stop =true;
  2616. rescan = true; //pas d'appel RECURSIF de la fonction. Trop de pb !!
  2617. }
  2618.  
  2619. test_clic_boutons(&bt_scan_suivant);
  2620. if (bt_scan_suivant.cliked)
  2621. {
  2622. bt_re_scan.cliked = false;
  2623. affiche_box_scan(dy_box_SCAN); // efface le tracé et re-dessine les boutons dans la boite
  2624.  
  2625. n = n_max;
  2626. xi =0; // départ tracé à gauche
  2627. decal_x=0; // textes fréquences trouvées
  2628. decal_y=0;
  2629. nb_F=0;
  2630. memo_frequence_scan = frequence;
  2631. stop =true; // sortira de la boucle while()
  2632. rescan = true; // bouclera dans la boucle do()
  2633. }
  2634.  
  2635. test_clic_boutons(&bt_stop_scan);
  2636. if (bt_stop_scan.cliked)
  2637. {
  2638. stop =true; // sortira de la boucle while()
  2639. rescan = false; // ne rebouclera PAS dans la boucle do()
  2640. }
  2641. }
  2642. }
  2643.  
  2644. } while (rescan == true); // Fin de la boucle do()
  2645.  
  2646.  
  2647.  
  2648. Serial.println("-----------------------");
  2649. Serial.println("groupe_SCAN");
  2650. groupe_SCAN.bloc_to_serial(); // pour test avec moniteur série (CuteCom par exemple)
  2651. Serial.println("-----------------------");
  2652.  
  2653. Serial.println("STOP scan");
  2654.  
  2655. mode_affi = NORMAL;
  2656. mode_s = _MEM;
  2657. bt_mode_FRQ.selected = false; bt_mode_FRQ.affiche(GRIS_6, VERT, 2);
  2658. bt_mode_MEM.selected = true; bt_mode_MEM.affiche(GRIS_6, VERT, 2);
  2659. //bt_mode_MEM.cliked = true;
  2660.  
  2661.  
  2662. record_fichier_params();
  2663.  
  2664. uint16_t ya = 20;
  2665. uint8_t dya = 15;
  2666. TFT.fillScreen(NOIR);
  2667. TFT.setTextColor(VERT, NOIR);
  2668. TFT.setFreeFont(FF0);
  2669. TFT.drawString("Les Freq. detectees sont memo en RAM", 5, ya); ya += dya;
  2670. TFT.drawString("accessibles par le bouton [SC]", 5, ya); ya += dya;
  2671. TFT.drawString("et perdues si stop radio", 5, ya); ya += dya;
  2672. TFT.drawString("Mais on peut les enregistrer en SPIFFS", 5, ya); ya += dya;
  2673. TFT.drawString("une a une avec le bouton [Write]", 5, ya); ya += dya;
  2674.  
  2675. delay(300);
  2676.  
  2677. attente_clic();
  2678.  
  2679. init_affichages();
  2680.  
  2681. groupe_actif = gSCN;
  2682. bande_active = SCN;
  2683.  
  2684. bt_SCN.selected = true; bt_SCN.affiche(GRIS_5, CYAN, 1);
  2685. bt_SW.selected = false; bt_SW.affiche(GRIS_5, VERT, 1);
  2686. bt_FM.selected = false; bt_FM.affiche(GRIS_5, VERT, 1);
  2687. bt_AIR.selected = false;bt_AIR.affiche(GRIS_5, VERT, 1);
  2688.  
  2689. affiche_numero_frq(String(1), String(nb_F));
  2690. affiche_frequence(frequence);
  2691. }
  2692.  
  2693.  
  2694. void test_clic_Bt_scan_FRQ()
  2695. {
  2696. test_clic_boutons(&bt_scan_frq);
  2697.  
  2698. if (bt_scan_frq.cliked == true)
  2699. {
  2700. //bt_scan_frq.affiche(NOIR, VERT, 1);
  2701. bt_scan_frq.cliked = false;
  2702. bt_scan_frq.affiche(GRIS_5, BLANC, 1);
  2703.  
  2704. mode_affi = SCAN_F;
  2705. mode_s = _FRQ;
  2706. bt_mode_FRQ.selected = true; bt_mode_FRQ.affiche(GRIS_6, VERT, 2);
  2707. bt_mode_MEM.selected = false; bt_mode_MEM.affiche(GRIS_6, VERT, 2);
  2708.  
  2709. scan_frq();
  2710.  
  2711. bt_scan_frq.affiche(GRIS_5, BLANC, 1);
  2712. }
  2713. delay(100);
  2714. }
  2715.  
  2716.  
  2717. void test_clic_bt_scan_air()
  2718. {
  2719. test_clic_boutons(&bt_scan_air);
  2720.  
  2721. if (bt_scan_air.cliked == true)
  2722. {
  2723. //bt_scan_air.affiche(GRIS_5, BLANC, 1);
  2724. bt_scan_air.cliked = false;
  2725. bt_scan_air.affiche(GRIS_5, BLANC, 1);
  2726. mode_affi = SCAN_M;
  2727. bt_scan_air.selected = true;
  2728. bande_active == AIR;
  2729. scan_mem_AIR();
  2730. bt_scan_air.affiche(GRIS_5, BLANC, 1);
  2731. mode_s = _MEM;
  2732. }
  2733. delay(100);
  2734. }
  2735.  
  2736.  
  2737. void attente_clic()
  2738. {
  2739. delay(300);
  2740. init_1_bouton(300, 5, 20, 20, "X", &bt_close);
  2741. while ( !(ts.tirqTouched() && ts.touched()) ) {;}
  2742. TFT.fillScreen(NOIR);
  2743. init_affichages();
  2744. bt_SW.selected = false;
  2745. bt_FM.selected = true;
  2746. bande_active = FM;
  2747. modulation_active = WFM;
  2748. frequence = presetPad1.bt_preset[0].frequence_FM;
  2749. bt_SW.affiche(GRIS_5, VERT, 1);
  2750. bt_FM.affiche(GRIS_5, VERT, 1);
  2751. }
  2752.  
  2753.  
  2754.  
  2755. void SPIFFS_listFiles()
  2756. {
  2757. Serial.println("Listing fichiers (en memoire SPIFFS)");
  2758. uint16_t y=0;
  2759. String s1;
  2760.  
  2761. TFT.fillScreen(NOIR);
  2762. TFT.setTextColor(BLANC, NOIR);
  2763. TFT.setFreeFont(FF0);
  2764. TFT.drawString("Listing fichiers (en memoire SPIFFS)", 0, y); y+=30;
  2765.  
  2766.  
  2767. File root = SPIFFS.open("/");
  2768. File file = root.openNextFile();
  2769. while (file)
  2770. {
  2771. Serial.print(" FILE: ");
  2772.  
  2773. s1 = String(file.name());
  2774. Serial.print(s1);
  2775. TFT.setTextColor(VERT, NOIR);
  2776. TFT.drawString(s1, 0, y);
  2777.  
  2778. s1 = "size:";
  2779. Serial.print(s1);
  2780. TFT.setTextColor(BLANC, NOIR);
  2781. TFT.drawString(s1, 100, y);
  2782.  
  2783. s1 = file.size();
  2784. Serial.println(s1);
  2785. TFT.setTextColor(JAUNE, NOIR);
  2786. TFT.drawString(s1, 140, y);
  2787.  
  2788. y+=10;
  2789.  
  2790. file = root.openNextFile();
  2791. }
  2792. attente_clic();
  2793. }
  2794.  
  2795.  
  2796.  
  2797. void SPIFFS_RAZ()
  2798. {
  2799. boolean valider = false; // <-- ecrire "= true" pour rendre l'effacement possible
  2800. // (évite tout effacement accidentel et donc perte de centaines de fréquences...)
  2801.  
  2802. if(valider == false)
  2803. {
  2804. TFT.fillScreen(NOIR);
  2805. TFT.setFreeFont(FM9);
  2806. TFT.drawString("FONCTION VOLONTAIREMENT", 50, 120);
  2807. TFT.drawString("INACTIVE", 50, 140);
  2808. TFT.drawString("VOIR LE CODE SOURCE", 50, 160);
  2809. TFT.drawString("void SPIFFS_RAZ()", 50, 180);
  2810. delay(3000);
  2811. init_affichages();
  2812. return;
  2813. }
  2814.  
  2815. SPIFFS.remove("/FRQ_SW.txt");
  2816. SPIFFS.remove("/FRQ_SW_PRST.txt");
  2817. SPIFFS.remove("/FRQ_FM.txt");
  2818. SPIFFS.remove("/FRQ_FM_PRST.txt");
  2819. SPIFFS.remove("/FRQ_AIR.txt");
  2820. SPIFFS.remove("/FRQ_AIR_PRST.txt");
  2821.  
  2822. Serial.println("fin RAZ SPIFFS");
  2823. }
  2824.  
  2825.  
  2826.  
  2827. void test_clic_bouton_SPIFFS_RAZ()
  2828. {
  2829. uint16_t c1 = NOIR;
  2830. uint16_t c2 = VERT;
  2831.  
  2832. test_clic_boutons(&bt_SPIFFS_RAZ );
  2833. if(bt_SPIFFS_RAZ.cliked)
  2834. {
  2835. bt_SPIFFS_RAZ.cliked = false;
  2836. bt_SPIFFS_RAZ.selected = false;
  2837. bt_SPIFFS_RAZ.affiche(ROUGE, c1, 1);
  2838.  
  2839. SPIFFS_RAZ();
  2840. }
  2841. }
  2842.  
  2843.  
  2844. void test_clic_bouton_SPIFFS_LST()
  2845. {
  2846. test_clic_boutons(&bt_SPIFFS_LST );
  2847. if(bt_SPIFFS_LST.cliked)
  2848. {
  2849. bt_SPIFFS_LST.cliked = false;
  2850. bt_SPIFFS_LST.selected = false;
  2851. bt_SPIFFS_LST.affiche(VERT, GRIS_5, 1);
  2852. SPIFFS_listFiles();
  2853. }
  2854. }
  2855.  
  2856.  
  2857.  
  2858. void test_clic_bouton_SPIFFS_write() // en SPIFFS, dans un des fichiers ("/FRQ_SW.txt" ...)
  2859. {
  2860. uint16_t c1 = GRIS_6;
  2861. uint16_t c2 = VERT;
  2862. String s1;
  2863.  
  2864. test_clic_boutons(&bt_SPIFFS_write );
  2865. if(bt_SPIFFS_write.cliked)
  2866. {
  2867. bt_SPIFFS_write.cliked=false;
  2868. bt_SPIFFS_write.selected=false;
  2869. bt_SPIFFS_write.affiche(VERT, GRIS_5, 1);
  2870.  
  2871. Serial.println("--------------------------------");
  2872. Serial.println("bouton_SPIFFS_write clic");
  2873.  
  2874. //attention à ne pas oublier ces < >
  2875. s1 = "<";
  2876. s1 += String(frequence); // // fréquence en cours
  2877. s1 += ">";
  2878.  
  2879. boolean ok = false;
  2880. if (bande_SW)
  2881. {
  2882. if (! groupe_SW.test_Frq_presente(frequence)) // test effectué sur le groupe en RAM
  2883. {
  2884. // AJOUTE la fréquence en fin d'une liste de fréquences. Travaille directement sur la mémoire SPIFFS
  2885. File file = SPIFFS.open("/FRQ_SW.txt", FILE_APPEND);
  2886. file.print(s1);
  2887. file.close(); // enregistre CE fichier en mémoire SPIFFS, sans toucher aux autres
  2888. delay(300);
  2889. ok = true;
  2890. }
  2891. }
  2892.  
  2893. if (bande_FM)
  2894. {
  2895. if (! groupe_FM.test_Frq_presente(frequence))
  2896. {
  2897. File file = SPIFFS.open("/FRQ_FM.txt", FILE_APPEND);
  2898. file.print(s1);
  2899. file.close();
  2900. delay(300);
  2901. ok = true;
  2902. }
  2903. }
  2904.  
  2905. if (bande_AIR)
  2906. {
  2907. if (! groupe_AIR.test_Frq_presente(frequence))
  2908. {
  2909. File file = SPIFFS.open("/FRQ_AIR.txt", FILE_APPEND);
  2910. file.print(s1);
  2911. file.close();
  2912. delay(300);
  2913. ok = true;
  2914. }
  2915. }
  2916.  
  2917. String s1, s2;
  2918. if (ok) {s1 = "Freq. save to SPIFFS"; s2 = ""; }
  2919. else {s1 = "Freq. deja presente"; s2 = "NOT SAVE";}
  2920. Serial.println(s1);
  2921.  
  2922. if (ok) {load_GRP_FREQ_SPIFFS();} // recharge les listes de fréquences depuis la SPIFFS pour être à jour
  2923.  
  2924. TFT.fillScreen(NOIR);
  2925. TFT.setTextColor(JAUNE, NOIR);
  2926. TFT.setFreeFont(FF1);
  2927. TFT.drawString(s1, 5, 40);
  2928. TFT.drawString(s2, 5, 60);
  2929. attente_clic();
  2930. }
  2931. }
  2932.  
  2933.  
  2934.  
  2935. void test_clic_bt_erase_1F() // en SPIFFS
  2936. {
  2937. uint16_t c1 = GRIS_6;
  2938. uint16_t c2 = VERT;
  2939.  
  2940. test_clic_boutons(&bt_erase_1F );
  2941. if(bt_erase_1F.cliked)
  2942. {
  2943. bt_erase_1F.cliked = false;
  2944. bt_erase_1F.selected = false;
  2945. bt_erase_1F.affiche(GRIS_3, c1, 1);
  2946.  
  2947. delay (300);
  2948. bt_erase_1F.cliked = false;
  2949. bt_erase_1F.selected = false;
  2950. bt_erase_1F.affiche(c1, c2, 1); // fugitif
  2951.  
  2952. uint16_t F;
  2953.  
  2954. //todo: en SPIFFS
  2955.  
  2956. }
  2957. }
  2958.  
  2959.  
  2960. void test_clic_boutons_MODE() // FREQ - MEM
  2961. {
  2962. uint16_t c1 = NOIR;
  2963. uint16_t c2 = VERT;
  2964. uint16_t c3 = JAUNE;
  2965.  
  2966. bt_mode_FRQ.cliked = false;
  2967. bt_mode_MEM.cliked = false;
  2968.  
  2969. test_clic_boutons(&bt_mode_FRQ );
  2970. if (bt_mode_FRQ.cliked) // les boutons sont exclusifs
  2971. {
  2972. mode_s = _FRQ;
  2973. affiche_index_frq();
  2974. bt_mode_FRQ.selected = true;
  2975. bt_mode_MEM.selected = false;
  2976. affiche_frequence(frequence);
  2977. efface_numero_frq();
  2978.  
  2979. }
  2980.  
  2981. test_clic_boutons(&bt_mode_MEM );
  2982. if (bt_mode_MEM.cliked)
  2983. {
  2984. efface_index_frq();
  2985. mode_s = _MEM;
  2986. bt_mode_MEM.selected = true;
  2987. bt_mode_FRQ.selected = false;
  2988. affiche_frequence(frequence);
  2989. }
  2990.  
  2991. bt_mode_FRQ.affiche(c1, c2, 2);
  2992. bt_mode_MEM.affiche(c1, c3, 2);
  2993. init_boutons_Plus_Moins(); //ce qui va changer le symbole affiché en '-' et '+' ou '<' et '>' en fonction du 'mode_s'
  2994. if (mode_affi == NORMAL)
  2995. {
  2996. bt_moins.affiche(GRIS_6, VERT ,1);
  2997. bt_plus.affiche(GRIS_6, VERT ,1);
  2998. }
  2999.  
  3000. }
  3001.  
  3002.  
  3003. void test_clic_boutons_BANDE() // SW, FM, AIR, SCAN
  3004. {
  3005. uint16_t c1 = GRIS_5;
  3006. uint16_t c2 = VERT;
  3007.  
  3008. bt_SW.cliked = false;
  3009. bt_FM.cliked = false;
  3010. bt_AIR.cliked = false;
  3011.  
  3012. test_clic_boutons(&bt_SW );
  3013. if (bt_SW.cliked)
  3014. {
  3015. TFT.fillRect(x0_box_info1+2, y0_box_info1+2, 120, 12, couleur_fond_ecran); // efface
  3016. Serial.println("bt_SW.cliked");
  3017. bt_SW.cliked = false;
  3018.  
  3019. groupe_actif = gSW;
  3020. bande_active = SW;
  3021. modulation_active = AM;
  3022. bt_SW.selected = true;
  3023. bt_FM.selected = false; // les boutons sont exclusifs
  3024. bt_AIR.selected = false;
  3025. bt_SCN.selected = false;
  3026.  
  3027. clic_logiciel_bouton(&presetPad1.bt_preset[0]);
  3028. traite_boutons_presetPad(0);
  3029.  
  3030.  
  3031. uint8_t nb_F = groupe_SW.nb_freq;
  3032. affiche_numero_frq(String(1), String(nb_F));
  3033. }
  3034.  
  3035. test_clic_boutons(&bt_FM );
  3036. if (bt_FM.cliked)
  3037. {
  3038. Serial.println("bt_FM.cliked");
  3039. bt_FM.cliked = false;
  3040.  
  3041. groupe_actif = gFM;
  3042. bande_active = FM;
  3043. modulation_active = WFM;
  3044. bt_FM.selected = true;
  3045. bt_SW.selected = false;
  3046. bt_AIR.selected = false;
  3047. bt_SCN.selected = false;
  3048.  
  3049. clic_logiciel_bouton(&presetPad1.bt_preset[0]);
  3050. traite_boutons_presetPad(0);
  3051.  
  3052. uint8_t nb_F = groupe_FM.nb_freq;
  3053. affiche_numero_frq(String(1), String(nb_F));
  3054. }
  3055.  
  3056. test_clic_boutons(&bt_AIR );
  3057. if (bt_AIR.cliked)
  3058. {
  3059. TFT.fillRect(x0_box_info1+2, y0_box_info1+2, 120, 12, couleur_fond_ecran); // efface
  3060. Serial.println("bt_AIR.cliked");
  3061. bt_AIR.cliked = false;
  3062.  
  3063. groupe_actif = gAIR;
  3064. bande_active = AIR;
  3065. modulation_active = AM;
  3066. bt_AIR.selected = true;
  3067. bt_SW.selected = false;
  3068. bt_FM.selected = false;
  3069. bt_SCN.selected = false;
  3070.  
  3071. clic_logiciel_bouton(&presetPad1.bt_preset[0]);
  3072. traite_boutons_presetPad(0);
  3073.  
  3074. uint8_t nb_F = groupe_AIR.nb_freq;
  3075. affiche_numero_frq(String(1), String(nb_F));
  3076. }
  3077.  
  3078. test_clic_boutons(&bt_SCN );
  3079. if (bt_SCN.cliked == true)
  3080. {
  3081. Serial.println("bt_SCN.cliked");
  3082. bt_SCN.cliked = false;
  3083.  
  3084. groupe_actif = gSCN;
  3085. bande_active = SCN;
  3086. bt_SCN.selected = true; bt_SCN.affiche(c1, CYAN, 1);
  3087. bt_SW.selected = false; bt_SW.affiche(c1, c2, 1);
  3088. bt_FM.selected = false; bt_FM.affiche(c1, c2, 1);
  3089. bt_AIR.selected = false;bt_AIR.affiche(c1, c2, 1);
  3090.  
  3091. uint8_t nb_F = groupe_SCAN.nb_freq;
  3092. affiche_numero_frq(String(1), String(nb_F));
  3093. }
  3094.  
  3095. Serial.print("groupe actif = "); Serial.println(groupe_actif);
  3096.  
  3097. }
  3098.  
  3099.  
  3100. void test_clic_bouton_set() // bouton pour passer dans le mode d'écriture de la F en cours en SPIFFS
  3101. // L'écriture en question sera effectuée par la fonction 'traite_boutons_presetPad()'
  3102. {
  3103. test_clic_boutons(&bt_set);
  3104. if (bt_set.cliked)
  3105. {
  3106. bt_set.cliked = false;
  3107. vu_metre_actif = false;
  3108. TFT.fillRect(x0_box_info2, y0_box_info2, 140, 70, NOIR);
  3109.  
  3110. TFT.setTextColor(VERT, NOIR);
  3111. TFT.setFreeFont(FF0);
  3112. TFT.drawString("Cliquez sur un des 8 bt", x0_box_info2+2, y0_box_info2+2);
  3113. TFT.drawString("'preset' pour lui ", x0_box_info2+2, y0_box_info2+12);
  3114. TFT.drawString("attribuer la F en cours", x0_box_info2+2, y0_box_info2+22);
  3115.  
  3116. init_1_bouton(x0_box_info2+82, y0_box_info2+50, 50, 15, "annuler", &bt_annuler);
  3117. bt_annuler.affiche(NOIR, BLANC, 1);
  3118.  
  3119. mode_affi = SET_F_PRESET; // ce qui modifie le comportement de la fonction 'traite_boutons_presetPad()'
  3120. Serial.println("mode_affi == SET_F_PRESET");
  3121.  
  3122. delay (100);
  3123. bt_set.selected = false;
  3124. bt_set.affiche(NOIR, BLANC, 1);
  3125. }
  3126. }
  3127.  
  3128.  
  3129. void affiche_signal(uint16_t x, uint16_t y, uint16_t dx, int16_t valeur)
  3130. {
  3131. TFT.fillRect(x, y, dx, 8, NOIR); // efface
  3132. if(valeur<0) {valeur =0;}
  3133. if(valeur > dx) {valeur = dx;}
  3134. TFT.drawRect(x, y, dx, 5, couleur_traits);
  3135. TFT.fillRect(x, y, valeur, 5, JAUNE);
  3136. }
  3137.  
  3138.  
  3139. void affiche_tension_batt(uint16_t x, uint16_t y, uint16_t dx, int8_t valeur) // valeur en %
  3140. {
  3141. uint16_t c1;
  3142. c1 = ROUGE;
  3143. if(valeur>30){c1 = ORANGE;}
  3144. if(valeur>50){c1 = JAUNE;}
  3145. if(valeur>70){c1 = VERT;}
  3146.  
  3147. uint32_t v2 = valeur * dx / 100;
  3148. TFT.fillRect(x-20, y, dx, 8, NOIR); // efface
  3149. efface_box_entete3();
  3150. if(v2<0) {valeur =0;}
  3151. if(v2 > dx) {v2 = dx;}
  3152. TFT.drawRect(x, y, dx, 5, couleur_traits);
  3153. TFT.fillRect(x, y, v2, 5, c1);
  3154.  
  3155. String s1 = String(valeur) +"%";
  3156. TFT.setTextColor(BLANC, NOIR);
  3157. TFT.setFreeFont(FF0);
  3158. TFT.drawString(s1, x-20, y);
  3159. TFT.drawString("bat", x + 10 , y+5);
  3160. }
  3161.  
  3162.  
  3163.  
  3164. void affiche_1_bargraph(uint16_t x, uint16_t y, uint16_t dx, int16_t valeur, uint16_t couleur)
  3165. {
  3166. TFT.fillRect(x, y, dx+40, 8, NOIR); // efface
  3167. TFT.drawString(String(valeur), x, y);
  3168.  
  3169. if(valeur<0) {valeur =0;}
  3170. if(valeur > dx) {valeur = dx;}
  3171. TFT.drawRect(x+40, y, dx, 5, couleur_traits);
  3172. TFT.drawRect(x+40, y, valeur, 5, couleur);
  3173. }
  3174.  
  3175.  
  3176. void affiche_bars_graph()
  3177. {
  3178. affiche_1_bargraph(170, 150, 100, level/10, VERT);
  3179. affiche_1_bargraph(170, 160, 100, usn, JAUNE);
  3180. affiche_1_bargraph(170, 170, 100, wam, BLEU_CLAIR);
  3181. affiche_1_bargraph(170, 180, 100, offset, BLANC);
  3182. }
  3183.  
  3184.  
  3185. String int_to_hex(uint16_t nb)
  3186. {
  3187. char symb[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  3188. uint8_t A = (nb & 0b1111000000000000) >>12;
  3189. uint8_t B = (nb & 0b0000111100000000) >>8;
  3190. uint8_t C = (nb & 0b0000000011110000) >>4;
  3191. uint8_t D = (nb & 0b0000000000001111);
  3192. String s1 = String(symb[A]) + String(symb[B]) + String(symb[C]) + String(symb[D]) ;
  3193. return s1;
  3194. }
  3195.  
  3196.  
  3197.  
  3198. void traite_signal_RDS()
  3199. {
  3200. Get_RDS_Data ( &status, &A_block, &B_block, &C_block, &D_block, &dec_error);
  3201. /*
  3202. A_Block always contains the 16-bit program identifier.
  3203. The first 11 bits (bits 15–5) of block 2 are also the same in all groups.
  3204. La Liste des codes RDS autorisés se trouve ici : https://www.csa.fr/maradiofm/radiords_tableau
  3205. pour les autres blocks, voir :
  3206. https://en.wikipedia.org/wiki/Radio_Data_System
  3207. (c'est sans doute logique mais terriblement indigeste !!!)
  3208. */
  3209.  
  3210. TFT.fillRect(x0_box_info1+2, y0_box_info1+2, 120, 12, couleur_fond_ecran); // efface
  3211. String s1 = int_to_hex(A_block);
  3212.  
  3213. String s2, s3;
  3214. TFT.setTextColor(JAUNE, GRIS_6);
  3215. TFT.setFreeFont(FF0);
  3216.  
  3217. for(int n = 0; n<=nb_stations_RDS-1; n++)
  3218. {
  3219. s2 = codesRDS[n];
  3220. s3 = s2.substring(0, 4);
  3221.  
  3222. if (s3 == s1)
  3223. {
  3224. TFT.drawString(s2, x0_box_info1+5, y0_box_info1 +4);
  3225. return; // on ne continue pas à boucler si trouvé
  3226. }
  3227. else if (n == nb_stations_RDS-1) // pas trouvé...
  3228. {
  3229. TFT.drawString(s1, x0_box_info1+5, y0_box_info1 +4);
  3230. return;
  3231. }
  3232. }
  3233. }
  3234.  
  3235.  
  3236.  
  3237. void affiche_force_signal()
  3238. {
  3239. //----------------------------------------------------------------------------------------------------------
  3240. // AFFICHE FORCE SIGNAL HF
  3241. compteur1 =0;
  3242. uint8_t module;
  3243. if(bande_active == FM) {module = 32;} else {module = 33;}
  3244. Get_Quality( module, &status, &level, &usn, &wam, &offset, &bandwidth, &mod, &snr );
  3245.  
  3246. //float signal_sur_bruit = level;// - 1.5 * usn; // marche à peu près bien pour la FM.
  3247.  
  3248. float diff = level - position_aiguille;
  3249. if(diff > 30.0) {diff = 30.0;}
  3250. if(diff < -30.0) {diff = -30.0;} // évite une trop grande réaction au sortir du mode 'mute'
  3251. // supprime les tremblements de l'aiguille
  3252. position_aiguille += diff / 6.0;
  3253.  
  3254. //affiche_bars_graph();
  3255. affiche_signal(170, 90, 60, mod/2);
  3256. if ((mode_affi == NORMAL) && (! mute) ) { plotAiguille(position_aiguille/6.0); }
  3257. if ((mode_affi == NORMAL) && (mute) ) { plotAiguille(0); }
  3258. }
  3259.  
  3260.  
  3261. int16_t etalon_TS[2] = {-30, 11 };
  3262.  
  3263.  
  3264. void loop()
  3265. {
  3266. if((mode_affi != SCAN_F) && (mode_affi != SCAN_M))// invalide les boutons situés derrière le panneau scan en modes SCAN
  3267. {
  3268. if (ts.tirqTouched() && ts.touched())
  3269. {
  3270. TS_Point p = ts.getPoint();
  3271. x_touch = eTS.x0 + p.x /eTS.dx;
  3272. y_touch = eTS.y0 + p.y /eTS.dy;
  3273.  
  3274. test_clic_6_boutons_frq(); // 6 rectangles situés au dessus des gros chiffres de la fréquence
  3275. test_clic_bouton_mute();
  3276. test_clic_bouton_SPIFFS_RAZ();
  3277. test_clic_bouton_SPIFFS_write();
  3278. test_clic_bouton_SPIFFS_LST();
  3279. test_clic_bt_erase_1F();
  3280. uint8_t n_touch1 = numPad1.test_clic(); // pavé numérique
  3281. if (n_touch1 != 253) { traite_touches_pad(n_touch1); } // pavé numérique
  3282.  
  3283. test_clic_boutons_plus_moins(); // boutons '<' et '>'
  3284. test_clic_bouton_Sleep();
  3285. test_clic_bouton_TEST();
  3286. test_clic_bouton_info();
  3287. test_clic_Bt_reset();
  3288. test_clic_Bt_scan_FRQ();
  3289. test_clic_bt_scan_air(); // Scan mémoires
  3290. test_clic_boutons_MODE(); // FREQ / MEM (tout en haut à gauche des gros chiffres)
  3291. test_clic_boutons_BANDE(); // SW, FM, AIR, SC; (SC = SCAN)
  3292.  
  3293. uint8_t num_bouton = presetPad1.test_clic(); // 8 petits boutons carrés de présélection de 8 fréquences
  3294. if (num_bouton != 253) { traite_boutons_presetPad(num_bouton); }
  3295.  
  3296. test_clic_bouton_set(); // attribution de la fréquence en cours à un des 8 boutons preset.
  3297. test_clic_bt_annuler();
  3298.  
  3299. test_clic_bt_affi_saisie_couleur();
  3300. test_clic_bt_RST_affi();
  3301. }
  3302.  
  3303. // la limitation SW max = 28MHz est due au module TEF6686 lui-même
  3304. if (frequence >= 138000) {frequence = 138000;} //138 MHz limite à cause SW max = 28MHz et conv AirBand = 110 MHz
  3305. if (frequence < 1500) {frequence = 1500;} // 1.5 MHz
  3306.  
  3307.  
  3308. if (compteur1 >= 5)
  3309. {
  3310. affiche_force_signal();
  3311.  
  3312. //----------------------------------------------------------------------------------------------------------
  3313. // AFFICHE TENSION BATTERIE
  3314. //----------------------------------------------------------------------------------------------------------
  3315. // voir la feuille de calcul 'Mesure de la tension de la batterie.ods' établie sur tests avec alim numérique
  3316. // voir aussi, sur le schéma, la valeur des résistances (diviseur analogique) sur l'entrée GPIO35 (analogPin = 35)
  3317. // Note: la valeur de la tension sur le pin GPIO35 ne doit jamais dépasser 3v3 (ce qui est lu = 4096)
  3318.  
  3319. int valeurLue = analogRead(analogPin);
  3320. //Serial.print("valeurLue = "); Serial.println(valeurLue);
  3321. float pourcent = ((float)valeurLue - 2570.0) / 7.5;
  3322. if (pourcent > 100.0) {pourcent = 100.0;}
  3323. if (pourcent < 0.0) {pourcent = 0.0;}
  3324.  
  3325. //Serial.print("pourcent = "); Serial.println(pourcent);
  3326.  
  3327. // intégration
  3328. float diff2 = pourcent - valeur_affi;
  3329. if(diff2 > 10.0) {diff2 = 10.0;}
  3330. if(diff2 < -10.0) {diff2 = -10.0;} // évite une trop grande réaction au sortir du mode 'mute'
  3331. valeur_affi += diff2 / 10.0;
  3332.  
  3333. if ( abs(valeur_affi - memo_valeur_affi) > 1.5 ) // pour éviter trop d'affichages inutiles (et clignotements à l'écran)
  3334. {
  3335. affiche_tension_batt(270, 4, 46, (int8_t) valeur_affi);
  3336. memo_valeur_affi = valeur_affi;
  3337. }
  3338. }
  3339.  
  3340. if (compteur2 >= 100)
  3341. {
  3342. compteur2 =0;
  3343.  
  3344. if(bande_active == FM) {traite_signal_RDS();}
  3345. }
  3346.  
  3347. delay(10);
  3348. compteur1++;
  3349. compteur2++;
  3350. }
  3351. }
  3352.  
  3353.  
  3354. /** ***************************************************************************************
  3355. CLASS TOUCH_BOUTON // affiche un nombre ou un petit texte dans un rectangle
  3356. ainsi que (en plus petit) deux valeurs supplémentaires, par ex: les valeurs mini et maxi
  3357. ********************************************************************************************/
  3358.  
  3359. // Constructeur
  3360. TOUCH_BOUTON::TOUCH_BOUTON()
  3361. {
  3362.  
  3363. }
  3364.  
  3365. // Constructeur
  3366. TOUCH_BOUTON_PRESET::TOUCH_BOUTON_PRESET()
  3367. {
  3368.  
  3369. }
  3370.  
  3371.  
  3372.  
  3373. void TOUCH_BOUTON::init(uint16_t xi, uint16_t yi, uint8_t dxi, uint8_t dyi, uint8_t dri)
  3374. {
  3375. x0 = xi;
  3376. y0 = yi;
  3377. dx = dxi;
  3378. dy = dyi;
  3379. dr = dri;
  3380.  
  3381. cliked = false;
  3382. selected = false;
  3383. }
  3384.  
  3385.  
  3386.  
  3387. void TOUCH_BOUTON::affiche(uint16_t coul_fill_unselect, uint16_t coul_fill_select, uint8_t n_font)
  3388. {
  3389. uint16_t couleur_contour = GRIS_5;
  3390. uint16_t couleur_texte = BLANC;
  3391.  
  3392. if(selected)
  3393. {
  3394. TFT.fillRoundRect(x0, y0, dx, dy, dr, coul_fill_select);
  3395. TFT.setTextColor(NOIR);
  3396. }
  3397. else
  3398. {
  3399. TFT.fillRoundRect(x0, y0, dx, dy, dr, coul_fill_unselect); // efface
  3400. TFT.drawRoundRect(x0, y0, dx, dy, dr, couleur_contour); // retrace juste le contour
  3401. TFT.setTextColor(couleur_texte);
  3402. }
  3403.  
  3404. //FM9 FMB9 FSS9... voir le fichier FrSPIFFS_Fonts.h
  3405. if (n_font == 1) { TFT.setFreeFont(FF0);}
  3406. if (n_font == 2) { TFT.setFreeFont(FM9);}
  3407. if (n_font == 3) { TFT.setFreeFont(FMB9);}
  3408. if (n_font == 4) { TFT.setFreeFont(FSS9);}
  3409.  
  3410. TFT.drawString(s, x0+3, y0 + 2);
  3411. }
  3412.  
  3413. uint8_t TOUCH_BOUTON::read_dx()
  3414. {
  3415. return dx;
  3416. }
  3417.  
  3418. uint8_t TOUCH_BOUTON::read_dy()
  3419. {
  3420. return dy;
  3421. }
  3422.  
  3423.  
  3424.  
  3425.  
  3426. /** ***************************************************************************************
  3427. CLASS NUMPAD
  3428. ********************************************************************************************/
  3429. // Constructeur
  3430. NUM_PAD::NUM_PAD()
  3431. {
  3432.  
  3433. }
  3434.  
  3435.  
  3436.  
  3437. void NUM_PAD::init(uint16_t xi, uint16_t yi, boolean fond) // si fond =false, ne resessine que les boutons
  3438. {
  3439. x0 = xi;
  3440. y0 = yi;
  3441. uint16_t x, y;
  3442. uint8_t dxt = 25; // taille x d'une touche
  3443. uint8_t dyt = 23; // taille y d'une touche
  3444.  
  3445. if(fond == true) {TFT.fillRect(x0, y0, 3*dxt +6, 4*dyt +7, NOIR);}
  3446.  
  3447. if(fond == true) {TFT.fillRect(x0, y0, 3*dxt +6, 4*dyt +7, NOIR);}
  3448.  
  3449. uint16_t c1 = GRIS_5;
  3450. uint16_t c2 = JAUNE;
  3451.  
  3452. x = x0+2;
  3453. y = y0+2;
  3454.  
  3455. for(uint8_t n =1; n<10; n++)
  3456. {
  3457. bt_pad[n].init(x, y, dxt, dyt, 3);
  3458. bt_pad[n].s=String(n);
  3459. bt_pad[n].affiche(c1, c2, 2);
  3460. x += dxt+1;
  3461. if (x > (x0 + 3*dxt)) {x = x0+2; y += dyt+1; }
  3462. }
  3463. bt_pad[0].init(x, y, dxt, dyt, 3); bt_pad[0].s="0"; bt_pad[0].affiche(c1, c2, 2); x += dxt+1;
  3464. bt_point.init(x, y, dxt, dyt, 3); bt_point.s="."; bt_point.affiche(c1, c2, 2);
  3465.  
  3466. x += dxt+1;
  3467. bt_ok.init(x, y, dxt, dyt, 3); bt_ok.s="ok";
  3468. bt_ok.affiche(c1, c2, 1);
  3469. }
  3470.  
  3471.  
  3472. uint8_t NUM_PAD::test_clic()
  3473. {
  3474. // zone des boutons du clavier
  3475. if ( (( x_touch > x0) && (x_touch < x0 + 100)) && (( y_touch > y0) && (y_touch < y0 + 130)))
  3476. {
  3477. uint8_t num_touche =0;
  3478.  
  3479. for(uint8_t n = 0; n<10; n++)
  3480. {
  3481. test_clic_boutons(&bt_pad[n] ); if(bt_pad[n].cliked) {num_touche=n; n_appui ++;}
  3482. }
  3483.  
  3484. test_clic_boutons(&bt_point ); if(bt_point.cliked) {num_touche=254; } // bouton "."
  3485. test_clic_boutons(&bt_ok ); if(bt_ok.cliked) {num_touche=255; n_appui ++;} // bouton "ok"
  3486. delay(100);
  3487. init(x0, y0, false); // 'false' évite le clignotement lorsqu'on repeint le fond noir
  3488.  
  3489. return num_touche;
  3490. }
  3491. return 253;
  3492. }
  3493.  
  3494. /** ***************************************************************************************
  3495. CLASS PRESET_PAD
  3496. ********************************************************************************************/
  3497.  
  3498. // Constructeur
  3499. PRESET_PAD::PRESET_PAD()
  3500. {
  3501.  
  3502. }
  3503.  
  3504.  
  3505. void PRESET_PAD::init(uint16_t xi, uint16_t yi)
  3506. {
  3507. x0 = xi;
  3508. y0 = yi;
  3509.  
  3510. uint16_t c1 = GRIS_5;
  3511. uint16_t c2 = JAUNE;
  3512.  
  3513. uint16_t x2, y2;
  3514. x2 = x0;
  3515. y2= y0;
  3516.  
  3517. for(uint8_t n=0; n<8; n++)
  3518. {
  3519. bt_preset[n].init(x2, y2, 15, 15, 3);
  3520. bt_preset[n].s=String(n+1);
  3521. if(mode_affi == COUL) {c1 = bt_preset[n].couleur;}
  3522. bt_preset[n].affiche(c1, c2, 1);
  3523. x2 += 20;
  3524. }
  3525. }
  3526.  
  3527.  
  3528. uint8_t PRESET_PAD::read_dx()
  3529. {
  3530. return dx;
  3531. }
  3532.  
  3533.  
  3534. uint8_t PRESET_PAD::read_dy()
  3535. {
  3536. return dy;
  3537. }
  3538.  
  3539.  
  3540.  
  3541. void PRESET_PAD::set_frequences_PRST() // lit les fréquences en SPIFFS et les attribue à chaque bouton PRESET
  3542. {
  3543. Serial.println("void PRESET_PAD::set_frequences()");
  3544.  
  3545. uint8_t n=0;
  3546.  
  3547. read_FRQ_File(SPIFFS, "/FRQ_SW_PRST.txt", "SW");
  3548. read_FRQ_File(SPIFFS, "/FRQ_FM_PRST.txt", "FM");
  3549. read_FRQ_File(SPIFFS, "/FRQ_AIR_PRST.txt", "AIR");
  3550. }
  3551.  
  3552.  
  3553. void PRESET_PAD::set_couleurs()
  3554. {
  3555. // voir la page: https://rgbcolorpicker.com/565
  3556. // qui permet de reconfigurer les couleurs RGB565 (5+6+5 = 16 bits) très simplement
  3557.  
  3558. bt_preset[0].couleur = 10240; // rouge sombre
  3559. bt_preset[1].couleur = 14528; // orange
  3560. bt_preset[2].couleur = 320; // vert
  3561. bt_preset[3].couleur = 14407; // violet
  3562. bt_preset[4].couleur = 26787; // rose
  3563. bt_preset[5].couleur = 260; // cyan
  3564. bt_preset[6].couleur = 267; // bleu ciel
  3565. bt_preset[7].couleur = 4; // bleu marine
  3566. }
  3567.  
  3568.  
  3569.  
  3570. void PRESET_PAD::deselect_boutons()
  3571. {
  3572. uint16_t c1 = GRIS_5;
  3573. uint16_t c2 = JAUNE;
  3574.  
  3575. for(int n =0; n<8; n++)
  3576. {
  3577. bt_preset[n].selected=false;
  3578. bt_preset[n].cliked=false;
  3579. bt_preset[n].affiche(c1, c2, 1);
  3580. }
  3581. }
  3582.  
  3583.  
  3584. uint8_t PRESET_PAD::test_clic()
  3585. {
  3586. if ( (( x_touch > x0) && (x_touch < (x0+155))) && (( y_touch > y0) && (y_touch < (y0+15))))
  3587. {
  3588. uint8_t num_bouton =0;
  3589. for(uint8_t n=0; n<8; n++)
  3590. {
  3591. test_clic_boutons(&bt_preset[n]);
  3592. if(bt_preset[n].cliked)
  3593. {
  3594. deselect_boutons(); // les autres
  3595. bt_preset[n].selected =true; // pour l'affichage de celui-ci
  3596. bt_preset[n].affiche(GRIS_5, VERT, 1);
  3597. num_bouton = n;
  3598. Serial.print("BB num_bouton= "); Serial.println(num_bouton);
  3599. }
  3600. }
  3601. return num_bouton;
  3602. }
  3603. return 253;
  3604. }
  3605.  
  3606.  
  3607.  
  3608.  
  3609.  
  3610.  
  3611. /** ***************************************************************************************
  3612. CLASS GROUPE_FREQUENCES // objet image d'un bloc mémoire en SPIFFS
  3613. permet diverses manipulations en RAM (tri...) sans toucher à la SPIFFS (évite usure mémoire flash)
  3614. ********************************************************************************************/
  3615.  
  3616. // Constructeur
  3617. GROUPE_FREQUENCES::GROUPE_FREQUENCES()
  3618. {
  3619.  
  3620. }
  3621.  
  3622.  
  3623. void GROUPE_FREQUENCES::RAZ() // en RAM uniquement
  3624. {
  3625. for(int n=0; n<100; n++)
  3626. {
  3627. G_freq[n]=0;
  3628. }
  3629. nb_freq = 0;
  3630. }
  3631.  
  3632.  
  3633. void GROUPE_FREQUENCES::load_bloc() // depuis la mémoire SPIFFS -> vers groupe en RAM
  3634. {
  3635. Serial.println("--------------------------");
  3636. Serial.println("GROUPE_FREQUENCES::load_bloc()");
  3637. Serial.print("Reading file: "); Serial.println(filename);
  3638. File file = SPIFFS.open(filename);
  3639. if (!file ) { Serial.println("failed to open file for reading"); return; }
  3640. String s;
  3641. uint8_t n =0;
  3642.  
  3643. while (file.available())
  3644. {
  3645. char c;
  3646. c = char(file.read());
  3647. if ((c !='<') && (c !='>')) {s += c;}
  3648. if(c=='>')
  3649. {
  3650. uint32_t frq;
  3651. frq = s.toInt();
  3652. Serial.println(frq);
  3653. s="";
  3654. G_freq[n] = frq;
  3655. n++;
  3656. }
  3657. }
  3658. file.close();
  3659. Serial.print(n); Serial.println(" frequences");
  3660. }
  3661.  
  3662.  
  3663. boolean GROUPE_FREQUENCES::test_Frq_presente(uint32_t F_i) // travaille en RAM
  3664. {
  3665. Serial.println("--------------------------");
  3666. Serial.println("test_Frq_presente()");
  3667. uint16_t n =0;
  3668. uint16_t adresse_lue;
  3669. uint32_t valeur_lue;
  3670. boolean ok = false;
  3671. for (n=0; n<100; n++)
  3672. {
  3673. valeur_lue = G_freq[n];
  3674. if (valeur_lue == F_i) {return true;} // si F est présente
  3675. }
  3676. return false; // si F non présente
  3677. }
  3678.  
  3679.  
  3680. void GROUPE_FREQUENCES::tri_bloc()
  3681. {
  3682. Serial.println("--------------------------");
  3683. Serial.println("tri_block()");
  3684. // tri par bulles
  3685.  
  3686. uint32_t F1=0, F2=0;
  3687. uint32_t Fi;
  3688. uint16_t i_max = 100;
  3689. uint16_t p_max = 100;
  3690.  
  3691.  
  3692. for(uint16_t p=0; p<p_max; p++)
  3693. {
  3694. //for(int n=0; n<i_max-1; n++)
  3695. uint16_t n =0;
  3696. while(n<i_max-1)
  3697. {
  3698. F1=G_freq[n];
  3699. F2=G_freq[n+1];
  3700.  
  3701. if(F1 > F2)
  3702. {
  3703. Fi = G_freq[n];
  3704. G_freq[n] = G_freq[n+1];
  3705. G_freq[n+1] = Fi;
  3706. }
  3707. n++;
  3708. }
  3709. }
  3710.  
  3711. // ici les freq sont dédoublées !!!!!!!!!!!!
  3712.  
  3713. // compte le nombre de fréquences != 0
  3714. uint16_t nombre =0;
  3715. for(uint16_t n = 0; n<100; n++ )
  3716. {
  3717. F1 = G_freq[n];
  3718. if(F1 != 0) { nombre++;}
  3719. }
  3720. nb_freq = nombre;
  3721.  
  3722. // recherche première fréquence non nulle
  3723. uint16_t n2=0;
  3724. F1 =0;
  3725. while ((F1==0) && (n2<100))
  3726. {
  3727. F1=G_freq[n2];
  3728. n2++;
  3729. }
  3730. adr_1ere_frq = n2-1; // 1ere F non nulle
  3731.  
  3732. }
  3733.  
  3734.  
  3735. void GROUPE_FREQUENCES::bloc_to_serial()
  3736. // pour tests, avec CuteCom sous Linux
  3737. // travaille en RAM uniquement, sans toucher aux fichiers SPIFFS
  3738. {
  3739. Serial.println("--------------------------");
  3740. Serial.println("bloc_to_serial()");
  3741. uint32_t valeur_lue;
  3742. uint16_t nombre =0;
  3743. for(uint16_t n = 0; n<100; n++ )
  3744. {
  3745. valeur_lue = G_freq[n];
  3746. if(valeur_lue != 0) // n'affiche pas les emplacements vides
  3747. {
  3748. nombre++;
  3749. Serial.println(valeur_lue);
  3750. }
  3751. }
  3752. Serial.print(nombre); Serial.println(" frequences");
  3753. //Serial.print("1ere Frq= "); Serial.println(G_freq[adr_1ere_frq]);
  3754.  
  3755. }
  3756.  
  3757.  
  3758. void GROUPE_FREQUENCES::add_frq(uint32_t Fi) // en RAM uniquement
  3759. {
  3760. Serial.println("--------------------------");
  3761. if (nb_freq >= 100) {return;}
  3762. Serial.println("GROUPE_FREQUENCES::add_frq()");
  3763.  
  3764. if (test_Frq_presente(Fi) == true)
  3765. {
  3766. Serial.println("Frq presente, pas d'ajout");
  3767. return;
  3768. }
  3769. tri_bloc(); // les F nulles se retrouvent en haut
  3770. Serial.print("Ajout frequence: "); Serial.println(Fi);
  3771. G_freq[0] = Fi; // la nouvelle fréquence est placée en haut
  3772. nb_freq++;
  3773. tri_bloc(); // la nouvelle fréquence se retrouve rangée dans l'ordre de F croissantes
  3774. }
  3775.  
  3776.  
  3777.  
  3778. void GROUPE_FREQUENCES::erase_1_freq(uint32_t Fi) // en RAM
  3779. {
  3780. Serial.println("--------------------------");
  3781. Serial.println("GROUPE_FREQUENCES::erase_1_freq()");
  3782. uint32_t valeur_lue;
  3783. for(int n=0; n<100; n++)
  3784. {
  3785. valeur_lue = G_freq[n];
  3786. if(valeur_lue == Fi)
  3787. {
  3788. G_freq[n]=0;
  3789. }
  3790. }
  3791. tri_bloc();
  3792. }
  3793.  
  3794.  

Voir plus bas "Documents" le code source complet comprenant les 'includes' et 'library' pour PlatformIO.
Remarque : Lorsque le module tuner TEF6686 n'est pas présent, n'est pas connecté physiquement à la carte CYD, le programme tourne très lentement, l'ESP32 passant son temps à attendre des réponses aux requêtes qu'il envoie sur le bus SPI.

13 Fichier source driver TEF6686_628.cpp

CODE SOURCE en C++
  1. /*************************************************************************************
  2. NOTE Silicium628
  3.  
  4. Les fonctions ci-dessous sont inspirées le plus directement possible de la lecture du pdf "TEF668X User Manuel" (NPX)
  5. Je n'utilise pas l'opérateur conditionnel ternaire ((condition) ? a : b) qui, bien que de haut niveau
  6. et permettant une écriture concise, ne facilite pas la lisibilité du programme.
  7.  
  8. **************************************************************************************/
  9.  
  10.  
  11. #include <Arduino.h>
  12. #include "Wire.h"
  13. #include "driverTEF6686_628.h"
  14.  
  15. byte addr_ISP = 0x64; // adresse du module TEF6686
  16.  
  17. #define conv8to16(a) ((uint16_t)(((uint16_t)(*(a))) << 8 |((uint16_t)(*(a+1)))))
  18.  
  19.  
  20. void Write2(uint8_t *buf, uint8_t len)
  21. {
  22. Wire.beginTransmission(addr_ISP);
  23. for (int i = 0; i < len; i++)
  24. {
  25. Wire.write(*buf++);
  26. }
  27. Wire.endTransmission();
  28. }
  29.  
  30.  
  31. void Set_Cmd(uint8_t module, uint8_t cmd, int len, ...)
  32. {
  33. uint8_t i;
  34. uint8_t buf[31];
  35. uint16_t temp;
  36. va_list vArgs;
  37. va_start(vArgs, len);
  38. buf[0] = module;
  39. buf[1] = cmd;
  40. buf[2] = 1;
  41. for (i = 0; i < len; i++)
  42. {
  43. temp = va_arg(vArgs, int);
  44. buf[3 + i * 2] = (uint8_t)(temp >> 8);
  45. buf[4 + i * 2] = (uint8_t)temp;
  46. }
  47.  
  48. va_end(vArgs);
  49. Write2(buf, len * 2 + 3);
  50. }
  51.  
  52.  
  53. void Set_Volume(int v)
  54. {
  55. Set_Cmd(48, 11, 1, 0); //unmute (IMPORTANT sinon débute en mode MUTE...)
  56. int MapVolume = map(v, 0, 100, -599, 50);
  57. Set_Cmd(48, 10, 1, MapVolume); // module 48 : AUDIO = Audio processing
  58. }
  59.  
  60.  
  61.  
  62. void Tune_Frequence_FM(uint16_t F)
  63. {
  64. uint8_t octet_L, octet_H;
  65.  
  66. octet_L = F%256;
  67. octet_H = F/256;
  68.  
  69. Wire.beginTransmission(addr_ISP);
  70. Wire.write(0x20);
  71. Wire.write(0x01);
  72. Wire.write(0x01);
  73. Wire.write(0x00);
  74. Wire.write(0x01);
  75. Wire.write(octet_H);
  76. Wire.write(octet_L);
  77. Wire.endTransmission();
  78. }
  79.  
  80.  
  81. void Tune_Frequence_AM(uint16_t F)
  82. {
  83. uint8_t octet_L, octet_H;
  84.  
  85. octet_L = F%256;
  86. octet_H = F/256;
  87.  
  88. Wire.beginTransmission(addr_ISP);
  89. Wire.write(0x21);
  90. Wire.write(0x01);
  91. Wire.write(0x01);
  92. Wire.write(0x00);
  93. Wire.write(0x01);
  94. Wire.write(octet_H);
  95. Wire.write(octet_L);
  96. Wire.endTransmission();
  97. }
  98.  
  99.  
  100.  
  101. void Set_Mute(boolean M)
  102. {
  103. if (M == true) //radio standby mode (low-power mode without radio functionality)
  104. {
  105. Wire.beginTransmission(addr_ISP);
  106. Wire.write(0x40);
  107. Wire.write(0x01);
  108. Wire.write(0x01);
  109. Wire.endTransmission();
  110. }
  111. else // normal operation
  112. {
  113. Wire.beginTransmission(addr_ISP);
  114. Wire.write(0x40);
  115. Wire.write(0x01);
  116. Wire.write(0x00);
  117. Wire.endTransmission();
  118. }
  119. }
  120.  
  121.  
  122. void Set_no_AM_gain_reduction()
  123. {
  124. Wire.beginTransmission(addr_ISP);
  125. Wire.write(0x21); // 33
  126. Wire.write(0x0C); // 12
  127. Wire.write(0x01);
  128. Wire.write(0x00);
  129. Wire.write(0x00);
  130. Wire.endTransmission();
  131. }
  132.  
  133.  
  134. bool Tuner_WriteBuffer(uint8_t *buf, uint16_t len)
  135. {
  136. Wire.beginTransmission(0x64);
  137. for (uint16_t i = 0; i < len; i++) {Wire.write(buf[i]);}
  138. uint8_t r = Wire.endTransmission();
  139. delay(2);
  140. if(r==0) {return 1;}
  141. else {return 0;} // l'opérateur conditionnel ternaire (?) c'est pas mon truc !
  142. }
  143.  
  144.  
  145. bool Tuner_ReadBuffer(uint8_t *buf, uint16_t len)
  146. {
  147. Wire.requestFrom(0x64, len);
  148. if (Wire.available() == len)
  149. {
  150. for (uint16_t i = 0; i < len; i++) { buf[i] = Wire.read(); }
  151. return 1;
  152. }
  153. else {return 0;}
  154. }
  155.  
  156.  
  157. bool Tuner_Get_Cmd(uint8_t module, uint8_t cmd, uint8_t *receive, uint16_t len)
  158. {
  159. uint8_t buf[3];
  160. buf[0] = module;
  161. buf[1] = cmd;
  162. buf[2] = 1;
  163.  
  164. Tuner_WriteBuffer(buf, 3);
  165. return Tuner_ReadBuffer(receive, len); // 1 si ok, 0 si erreur
  166. }
  167.  
  168.  
  169. void Get_Quality (
  170. // paramètres passés par adresse (donc variables), tous actualisés par cette fonction
  171. // tous des uint16_t ou int16_t sauf le dernier int8_t
  172. //ce qui nous fait 7*2 +1 = 15 octets lus dans le module
  173. uint8_t module,
  174. uint16_t *status,
  175. int16_t *level,
  176. uint16_t *usn,
  177. uint16_t *wam,
  178. int16_t *offset,
  179. uint16_t *bandwidth,
  180. uint16_t *mod,
  181. int8_t *snr )
  182. {
  183. uint8_t buf[14];
  184.  
  185. uint16_t r = Tuner_Get_Cmd(module, 129, buf, sizeof(buf));
  186.  
  187. // voir datasheet du TEF6686
  188. // actualisation des paramètres
  189. *status = conv8to16(buf);
  190. *level = conv8to16(buf + 2);
  191. *usn = conv8to16(buf + 4); // noise
  192. *wam = conv8to16(buf + 6); // ‘wideband-AM’
  193. *offset = conv8to16(buf + 8); //radio frequency offset
  194. *bandwidth = conv8to16(buf + 10) / 10; // IF bandwidth
  195. *mod = conv8to16(buf + 12) / 10; // modulation detector
  196. if (*level < -200) *level = -200;
  197. if (*level > 1200) *level = 1200;
  198. *snr = int(0.46222375 * (float)(*level) / 10 - 0.082495118 * (float)(*usn) / 10) + 10;
  199. }
  200.  
  201.  
  202. bool Get_RDS_Data (
  203. uint16_t *status,
  204. uint16_t *A_block,
  205. uint16_t *B_block,
  206. uint16_t *C_block,
  207. uint16_t *D_block,
  208. uint16_t *dec_error)
  209. {
  210. uint8_t buf[12];
  211. uint8_t r = Tuner_Get_Cmd(32, 131, buf, sizeof(buf));
  212. *status = conv8to16(buf);
  213. *A_block = conv8to16(buf + 2);
  214. *B_block = conv8to16(buf + 4);
  215. *C_block = conv8to16(buf + 6);
  216. *D_block = conv8to16(buf + 8);
  217. *dec_error = conv8to16(buf + 10);
  218. return r;
  219. }

14 Fichier source main.h

CODE SOURCE en C++
  1. #include <Arduino.h>
  2.  
  3.  
  4. /** ***********************************************************************************
  5. CLASS
  6. ***************************************************************************************/
  7.  
  8. class TOUCH_BOUTON
  9. {
  10. protected:
  11. uint8_t dx;
  12. uint8_t dy;
  13. uint8_t dr; // rayon de courbure des angles
  14.  
  15. public:
  16. uint16_t x0;
  17. uint16_t y0;
  18.  
  19. String s;
  20. boolean cliked;
  21. boolean selected;
  22.  
  23. uint8_t read_dx();
  24. uint8_t read_dy();
  25.  
  26. TOUCH_BOUTON(); // constructeur
  27.  
  28. void init(uint16_t xi, uint16_t yi, uint8_t dxi, uint8_t dyi, uint8_t dri);
  29. void affiche(uint16_t coul_fill_unselect, uint16_t coul_fill_select, uint8_t n_font);
  30.  
  31. private:
  32.  
  33. };
  34.  
  35.  
  36. class TOUCH_BOUTON_PRESET : public TOUCH_BOUTON
  37. {
  38. public:
  39. uint32_t frequence_SW; // 4 octets
  40. uint32_t frequence_FM; // 4 octets
  41. uint32_t frequence_AIR;// 4 octets
  42. String nom;
  43. uint16_t couleur;
  44.  
  45. TOUCH_BOUTON_PRESET(); // constructeur
  46.  
  47. private:
  48.  
  49. };
  50.  
  51.  
  52. /** ***************************************************************************************
  53. CLASS PRESET_PAD // objet 8 touches d'accès rapide à 8 fréquences favorites adns chaque gamme
  54. ********************************************************************************************/
  55. class PRESET_PAD
  56. {
  57. protected:
  58. uint8_t dx;
  59. uint8_t dy;
  60.  
  61. public:
  62. uint8_t x0;
  63. uint8_t y0;
  64.  
  65. TOUCH_BOUTON_PRESET bt_preset[8];
  66.  
  67. PRESET_PAD(); // constructeur
  68.  
  69. void init(uint16_t x0, uint16_t y0);
  70. uint8_t read_dx();
  71. uint8_t read_dy();
  72. void set_frequences_PRST();
  73. void set_couleurs();
  74.  
  75. void deselect_boutons();
  76. uint8_t test_clic();
  77. //void traite_presetPad(uint8_t n_touch);
  78.  
  79. private:
  80.  
  81. };
  82.  
  83. /** ***************************************************************************************
  84. CLASS NUM_PAD // objet clavier numérique
  85. ********************************************************************************************/
  86.  
  87.  
  88. class NUM_PAD
  89. {
  90. protected:
  91.  
  92.  
  93. public:
  94. uint8_t x0;
  95. uint8_t y0;
  96.  
  97. TOUCH_BOUTON bt_pad[10];
  98.  
  99. TOUCH_BOUTON bt_point;
  100. TOUCH_BOUTON bt_ok;
  101.  
  102. NUM_PAD(); // constructeur
  103.  
  104. void init(uint16_t x0, uint16_t y0, boolean fond);
  105. uint8_t test_clic();
  106.  
  107. private:
  108.  
  109. };
  110.  
  111.  
  112. /** ***************************************************************************************
  113. CLASS GROUPE_FREQUENCES // objet image d'un bloc mémoire en SPIFFS
  114. permet diverses manipulations en RAM (tri...) sans toucher à la mémoire SPIFFS (qui est en mémoire flash)
  115. ********************************************************************************************/
  116. class GROUPE_FREQUENCES
  117. {
  118. public:
  119. uint32_t G_freq[100];
  120. uint16_t adr_1ere_frq; // après un tri les F=0 se retrouvent en haut de liste. La 1ere F se retrouve donc bien plus bas
  121. uint16_t nb_freq; // nombre de fréquences !=0 enregistées
  122. uint16_t num_F_actuelle;
  123. String filename; // du fichier en mémoire SPIFFS (par exemple "/FRQ_FM.txt")
  124.  
  125. GROUPE_FREQUENCES(); // constructeur
  126.  
  127. void RAZ();
  128. void load_bloc(); // depuis SPIFFS
  129. void bloc_to_serial(); // pour tests
  130. void tri_bloc(); // par valeur numérique des fréquences
  131. void add_frq(uint32_t Fi);
  132. void erase_1_freq(uint32_t Fi);
  133. boolean test_Frq_presente(uint32_t F_i);
  134.  
  135. private:
  136.  
  137. };
  138.  
  139.  
  140. // ************************************************************************************
  141.  
  142.  
  143. void setup();
  144. void loop();
  145. void printTouchToDisplay();
  146. void init_sprites();
  147. void SPIFFS_listFiles();
  148. void affi_image_from_spiffs(String filename, uint16_t x0, uint16_t y0);
  149. void record_fichier_params(); // en mémoire SPIFFS
  150. String read_line_params(uint16_t line_num);
  151. int32_t extract_params(String ligne, String label);
  152. void affiche_unit(String s);
  153. void affiche_band(String s);
  154. void affiche_numero_frq(String s1, String s2);
  155. void efface_box_entete2();
  156. void efface_box_entete3();
  157. //void affiche_box_choix_couleur();
  158. //void affi_valeurs_RGB();
  159. void affiche_box_FRQ(uint16_t couleur);
  160. void affiche_box_presets();
  161. void deselect_boutons_presets();
  162. void traite_boutons_presetPad(uint8_t n_bt);
  163. void affiche_box_GROUPE();
  164. void efface_box_GROUPE();
  165. void affiche_box_boutons_scan();
  166. void affiche_box_SPIFFS();
  167. void affiche_box_FRQ(uint16_t couleur);
  168. void affiche_frequence(uint32_t frq); // en kHz
  169. void affiche_index_frq();
  170. void affiche_force_signal();
  171. void clic_logiciel_bouton(TOUCH_BOUTON *bouton_i);
  172. void dessine_VuMetre();
  173. void init_box_info();
  174. void test_clic_boutons_BANDE();
  175. void test_clic_bouton_TEST();
  176. void scan_frq();
  177. void attente_clic();
  178.  
  179. //void Tune_Frequence_FM(uint16_t F);
  180. void Set_Volume(int v);

15 à suivre...

16 décembre 2025 :
en cours : Scanner (en particulier pour les messages ultra-courts de la bande aviation).

Il reste encore des choses à faire :
  • Règlage numérique du volume.
  • règler les paramètres de la CAG (gain)
  • Scanner (avec, et aussi sans mise en mémoire des stations), pas le genre de truc qui efface toute la mémoire à la moindre erreur de manip !!!!
  • Utiliser les fonctions WiFi de l'ESP32 pour récupérer et gérer les stations depuis l'ordinateur et éventuellement le téléphone.
  • Ajouter un bouton de sélection pas à pas rotatif. (difficulté: trouver 2 ports GPIO libres !)
  • Connecter une interface matérielle (comprenant un ESP32 classique) pleine de boutons par WiFi (Bluetooth), voire même une souris !
  • ...
29 décembre 2025 :
Le scan de fréquences fonctionne correctement pour la bande FM. (mémorisation des stations détectées dans un groupe de fréquence à part (pas directement dans le groupe FM, ceci afin de ne pas modifier ce groupe. On peut alors parcourir les stations une à une dans ce groupe "SCAN" et éventuellement les enregistrer dans le groupe FM le cas échéant).

Le scan de la bande aviation (en fait des fréquences précédemment enregistrées dans le groupe de fréquences AIR BAND) avec arrêt sur les fréquences actives et reprise du scan auto à la fin des messages est également fonctionnel comme vous pouvez le voir sur une des vidéos plus haut.

Je vais maintenant implémenter la liaison WiFi / Bluetooth pour gérer les fréquences extérieurement.

Un scoop au passage : J'ai commandé une puce Si4684 dans le but de réaliser un récepteur de radio numérique DAB+ : Un nouvel article vous décrira l'évolution de cette étude.

05 janvier 2026 :
Bonne année à toutes et à tous !

Je viens de publier la version 19.0 du firmware :
- programmation davantage orienté objet (avec de nouvelles "class") ce qui rend la structure générale plus solide et en facilite la compréhension (oui, même pour moi qui en suis l'auteur, il m'arrive de chercher plusieurs minutes tel ou tel détail, malgré toutes les possibilités de recherche que nous offre l'éditeur PlatformIO).

- Dans cette version 19.0 il est possible d'attribuer (et enregistrer en EEPROM) les fréquences des 8 boutons 'preset' par un simple clic. Par défaut les 8 boutons pointent sur 2.000 MHz en SW, 88.0 MHz en FM et 118 MHz en bande aviation. A vous de configurer tout ça, sans être obligé de modifier le code source.

17 janvier 2026 :

Nous en sommes à la version 20.5

Ces derniers temps j'ai beaucoup travaillé sur les fonctions scan. J'ai également fait pas mal de modifs dans l'affichage. Tout en programmant je teste et re-teste la radio et je mets toujours l'accent sur la simplicité d'utilisation. C’est pas juste un gadget pour faire joli, elle doit être performante, fonctionnelle et utile.

Je compte également faire un manuel d'utilisation avec captures d'écran annotées. Je ne l'ai pas encore fait parce qu'il faudra le mettre à jour à chaque modif du firmware...

26 janvier 2026 :
Version actuelle = 21.0

Cette semaine je me suis penché sur le problème de l'utilisation d'une SDcard avec la carte CYD. Il s'agit bien d'un problème car les concepteurs de la carte n'ont pas partagé (au niveau de la connexion physique, du circuit imprimé donc) le bus SPI entre l'afficheur, le TouchPad et le lecteur SDcard. Comme l'ESP32 dispose logiciellement de 3 bus SPI dont un est utilisé en interne pour sa programmation, reste deux ports. Et ces deux ports ont été utilisés pour le TFT et le Toucscreen. Reste Zéro port pour le lecteur de carte.
Certains utilisateurs proposent des solutions de contournement logicielles: je les ai toutes essayées, je dois être particulièrement nul (!) mais aucune n'a fonctionné. Je me suis ensuite penché sur une solution matérielle qui consiste à couper trois pistes (avec une CNC, vu la taille des composants) et à recâbler les lignes SCL, MISO et MOSI avec des petits fils à wrapper (AWG30) en m'inspirant d'une vidéo (blog.mark-stevens.co.uk, voir le lien plus bas). Mais il se trouve qu'il y a pas mal de cartes CYD 2.8" sur le marché, pas identiques quant à leur implantation et routage des pistes. Ce n'est qu'une fois les pistes coupées que je me suis rendu compte de la subtilité (des Vias pas au même endroit) ce qui a mis hors circuit les résistances de pullup (10k smd) sur le bus SPI. La CYD pouvait bien lire les micro SDcard, l'affichage et son Touchsreen fonctionnaient... mais pas longtemps ! Au bout d'une minute l'affichage devenait totalement psychédélique. J'ai essayé de rattraper le coup, loupe, fer à souder pour CMS... Et la carte a fini à la poubelle !

Conclusion : Il va falloir rapidement contourner tous les problèmes :
  • utilisation de l'afficheur TFT + Touchscreen + SDcard simultanément problématique : j'entends par "simultanément" : au sein du même programme (pas "en même temps"), et durablement. Dans la dernière version que je publie, je configure l'affichage, puis je configure la SD, puis je lis une image d'accueil sur la SD et l'affiche, puis je configure le touchpad. Et dès lors il devient impossible de lire sur la SD. Donc oui ça marche un coup pour l'image d'accueil, et c'est tout.
  • très peu de ports dispos
  • ports GPIO gaspillés pour le SPI non partagé
  • 1 port GPIO26 gaspillé comme sortie audio.
  • 3 ports GPIO 4, 16, 17 gaspillés pour une LED RVB, de plus située à l'arrière ! Certes On pourrait utiliser une fibre optique pour la voir sur la face avant...

Ce n'est donc pas une carte "universelle" et configurable pour n'importe quelle utilisation mais plutôt un jouet High-Tech assez frustrant. Je vais donc repartir de zéro : Un afficheur 2.8" (que je viens de commander) et un ESP32 wroom 30pins dev kit, et optimiser le schéma.

En attendant j'ai trouvé le moyen de contourner (un peu) le problème en enregistrant les images dans des sprites (donc en RAM). On peut dès lors les réutiliser plus tard autant qu'on veut. Mais la limite semble être environ 100 kB au total, ce qui ne couvre pas tout l'écran, mais 310 x170 px. Pour quelques petites icones ça peut convenir. Mais on est loin des 32GB d'une petite SDcard. Cette limite peut (peut-être) être augmentée en touchant au partitionnement de l'ESP32, à configurer dans le fichier platformio.ini. (actuellemnt -> board_build.partitions = min_spiffs.csv). A voir...

4 février 2026 :

NOUVELLE VERSION 2.0.22 utilisant le système de mémoire SPIFFS (2Mo voire plus...) de l'ESP32 avec:
  • outil de partitionnement en ligne (voir le lien en bas)
  • Upload des fichiers en mémoire SPIFFS avec l'outil disponible de VScode/Platformio


15 février 2026 :

La version utilisant le système de mémoire SPIFFS fonctionne parfaitement, avec la possibilité d'afficher n'importe quelle image à tout moment, sans entrer en conflit avec l'affichage, et l'écran tactile.

Toutefois il subsiste des limitations très frustrantes :
  • Le fait de ne pas pouvoir utiliser le lecteur SDcard 120 GB (giga) c'est quand même autre chose que 2MB (2 mega octet) !!)
  • La difficulté pour récupérer une capture d'écran sur le PC (download des fichiers SPIFFS -> PC problématique; éventuellement par hébergement d'une interface web(?)
  • Le manque cruel de ports GPIO libres sur l'ESP32 (je voudrais en particulier pouvoir utiliser des encodeurs rotatifs pas à pas)
  • Le fait de devoir utiliser l'application VScode/Platformio pour simplement mettre à jour les fichiers en mémoire SPIFFS; Insérer une SDcard compatible avec n'importe quel PC / Smartphone serait aussi très appréciable. (on pourrait toutefois passer par une liaison WiFi / Bluetooth avec l'ESP32, à voir, d'autant que j'ai déjà largement démontré dans mes réalisations antérieures que je savais le faire)
Et ce sont les raisons qui me font entreprendre le développement d'une carte personnalisée, en fait un simple circuit imprimé, reliant une Carte "ESP32 USB-C WROOM Devkit V1" et un "afficheur ILI9341 + Ecran tactile et lecteur de carte SD", avec partage optimisé des bus SPI ! Ce n'est pas juste une idée, ça fonctionne déjà parfaitement (sur plaque d'essais), le dessin du circuit imprimé est fait, et j'ai passé une commande de 5 exemplaires à JLCPCB (pour 4 € les 5 , port compris).
Donc un nouvel article sur ce site ne devrait pas tarder !!

Note : Cet article est en cours de rédaction permanente, je publie les avancées pratiquement chaque jour, avec bien entendu mise à jour du logiciel.

16 Aperçu de ma prochaine réalisation, en remplacement de la CYD par une ESP32 + ILI9341

Un nouvel article y sera consacré, avec tous les documents, dès que j'aurai reçu le circuit imprimé (histoire de pouvoir confirmer que ce dernier est ok). On peut d'ores et déjà apprécier le nombre de ports GPIO disponibles (14) ! Seul regret, le connecteur SDcard est au grand format... (pas micro-SD), faut utiliser un adaptateur, mais ça fait un peu moche ! Quant au prix des composants, cela revient au même, il faudra juste souder des connecteurs classiques (DIL au pas 2.54mm).

17 Documents

Un aperçu du code en cours de rédaction dans l'éditeur de VScode + PlatformIO

Code source en C++
Version du code source adaptée à l’éditeur VScode/PlatformIO :


18 -

Liens...
Pour me joindre : silicium628@free.fr

1438