/* ************************************************************************************
Radio TEF6686 par Silicium628
pour la carte CYD (Cheap Yellow Display) ESP32 Wroom + afficheur 2.8" TFT 240x320
Cette version utilise la mémoire SPIFFS; Voir:
-le dossier 'data' contenant les fichiers nécessaires
-le fichier 'platformio.ini' qui doit contenir la ligne 'board_build.partitions = perso4.csv'
-le fichier 'perso4.csv' (def des partitions) qui doit se trouver à côté du fichier platformio.ini
-les liens au bas de l'article sur mon site 'silicium628.fr'
Note :
-le dossier 'data' doit se trouver dans le dossier qui contient le fichier 'platformio.ini'
-les fichiers contenus dans 'data' sont à charger dans la mémoire flash de l'ESP
avec l'outil 'Upload FIlsystem Image' de platformio (cliquer sur l'icone "Alien" à gauche)
************************************************************************************ */
// REMARQUES:
// 1) lorsque la carte est connectée sur un bus USB de l'ordinateur,
// un terminal série tel que CuteCom affichera beaucoup de choses en temps réel.
// 2) Pour s'y retrouver dans le code, le plus simple est de partir de la fonction 'loop()' qui appelle les autres
// 3) pour reconfigurer les couleurs de fond, voir la methode 'void PRESET_PAD::set_couleurs()'
#include <Arduino.h>
String version = "2.0.34"; // (avec SPIFFS)
#include "main.h"
#include "constantes_628.h"
#include "DSP_INIT_628.h"
#include "driverTEF6686_628.h"
#include <Free_Fonts.h>
#include <SPIFFS.h>
#include "FS.h"
#include "Wire.h"
#include <stdint.h>
#include "TFT_eSPI.h" // Hardware-specific library
#include "SPI.h"
#include "Digit_Font.h"
#include <XPT2046_Touchscreen.h>
#define SPI_READ_FREQUENCY 16000000
#define bande_SW (frequence > 1500) && (frequence < 28000)
#define bande_interdite1 (frequence > 28000) && (frequence < 88000)
#define bande_interdite2 (frequence > 108000) && (frequence < 118000)
#define bande_FM (frequence >= 88000) && (frequence < 108000)
#define bande_AIR (frequence >= 118000) && (frequence < 138000)
#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33
//sur le connecteur CN1 de la carte CYD sérigraphiée 'ESP32-2432S028';
//attention: ces valeurs ne sont pas celles par défaut pour SDA et SCL
const int GPIO_SDA = 27;
const int GPIO_SCL = 22;
const int analogPin = 35;
#define High_16bto8b(a) ((uint8_t)((a) >> 8))
#define Low_16bto8b(a) ((uint8_t)(a ))
#define Convert8bto16b(a) ((uint16_t)(((uint16_t)(*(a))) << 8 |((uint16_t)(*(a+1)))))
SPIClass mySpi = SPIClass(VSPI);
XPT2046_Touchscreen ts(XPT2046_CS, XPT2046_IRQ);
TFT_eSPI TFT = TFT_eSPI(); // Configurer le fichier User_Setup.h de la bibliothèque TFT_eSPI au préalable
TFT_eSprite sprite_frq = TFT_eSprite(&TFT);
TFT_eSprite sprite_ligne1 = TFT_eSprite(&TFT);
const int _DX = 320;
const int _DY = 240;
struct ETALON_TS // etalon touch screen
{
int16_t x0;
int16_t dx;
int16_t y0;
int16_t dy;
};
ETALON_TS eTS;
uint16_t x_touch, y_touch;
float raddeg = M_PI/180.0;
float deg_to_rad = 2.0 * M_PI /360.0;
//***************************************************************************
//char var_array32[10];// 10 char + zero terminal - pour envoi par WiFi (because 2^32 -1 = 4294967295 -> 10 caractères)
// =====================================================================
boolean test_touch_screen = false; // mettre true pour activer le test (qui est une boucle infinie au démarrage...)
// pour étalonner, voir au tout début de la fonction 'init_variables_globales()'
uint16_t compteur1 = 0;
uint16_t compteur2 = 0;
uint16_t compteur3 = 0;
uint32_t frequence=10000;
uint32_t saut_freq;
uint16_t seuil = 50;
uint16_t memo_seuil = 50;
//uint32_t image_SPIFFS[300]; // permet le tri en RAM des fréquences sans toucher à l'SPIFFS
GROUPE_FREQUENCES groupe_SW;
GROUPE_FREQUENCES groupe_FM;
GROUPE_FREQUENCES groupe_AIR;
GROUPE_FREQUENCES groupe_SCAN;
uint32_t frq_preset_SW[8]; // 8 fréquences attribuées aux boutons [preset1] à [preset8] soit 8x4=32 octets
uint32_t frq_preset_FM[8]; // 8 fréquences attribuées aux boutons [preset1] à [preset8] soit 8x4=32 octets
uint32_t frq_preset_AIR[8];// 8 fréquences attribuées aux boutons [preset1] à [preset8] soit 8x4=32 octets total 32*3 = 96 octets
uint32_t memo_frequence_scan;
uint16_t frq_preset_adr_0;
String frequence_txt = "";
TOUCH_BOUTON bt_info;
TOUCH_BOUTON bt_sleep;
TOUCH_BOUTON bt_TEST;
TOUCH_BOUTON bt_mode_FRQ, bt_mode_MEM;
TOUCH_BOUTON bt_plus, bt_moins;
TOUCH_BOUTON bt_SPIFFS_RAZ, bt_SPIFFS_write, bt_erase_1F, bt_SPIFFS_LST;
TOUCH_BOUTON bt_1, bt_2, bt_3, bt_4, bt_5, bt_6; // au dessus des chiffres de la fréquence
TOUCH_BOUTON bt_affi_saisie_couleur;
TOUCH_BOUTON bt_coul_to_SPIFFS;
TOUCH_BOUTON bt_scan_frq, bt_scan_air;
TOUCH_BOUTON bt_RST_affi; // "ok"
//TOUCH_BOUTON bt_close1; // "x"
TOUCH_BOUTON bt_LEV, bt_SNR, bt_re_scan, bt_scan_suivant;
TOUCH_BOUTON bt_seuil_plus, bt_seuil_moins;
// ---------- numPad ------------
TOUCH_BOUTON bt_num0, bt_num1, bt_num2, bt_num3, bt_num4, bt_num5, bt_num6, bt_num7, bt_num8, bt_num9;
NUM_PAD numPad1;
// ---------- presetPad1 ------------
PRESET_PAD presetPad1;
// -------------------------------
TOUCH_BOUTON bt_SW, bt_FM, bt_AIR, bt_SCN;
TOUCH_BOUTON bt_mute;
TOUCH_BOUTON bt_reset;
TOUCH_BOUTON bt_stop_scan;
TOUCH_BOUTON bt_set; // attribtion d'une fréquence à un des 8 boutons preset
TOUCH_BOUTON bt_annuler; // "x"
TOUCH_BOUTON bt_close; // "x"
boolean mute;
boolean vu_metre_actif;
enum MODE_AFFI {COUL, NORMAL, SCAN_F, SCAN_M, SET_F_PRESET}; //[couleur], [normal], [scan], [set 1F pour 1Bt]
MODE_AFFI mode_affi;
enum MODE_SELECT {_FRQ=0, _MEM=1} mode_s; // mode de mofif fréquence, en tapant les chiffres /ou en mémoire
enum MODUL {AM, WFM};
MODUL modulation_active;
enum BANDE {SW, FM, AIR, SCN}; //fréquences;
BANDE bande_active;
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
GRP_ACT groupe_actif;
enum MODE_SCAN {FREQUENCE, MEMOIRE};
MODE_SCAN mode_scan;
enum MODE_SEUIL {LEV, SNR}; // level ou signal/bruit
MODE_SEUIL mode_seuil;
uint16_t FRQ_x0;
uint16_t FRQ_y0;
uint16_t x0_box_SPIFFS;
uint16_t y0_box_SPIFFS;
uint16_t x0_box_PRESET;
uint16_t y0_box_PRESET;
uint16_t x0_box_GROUPE; // SW - FM - AIR
uint16_t y0_box_GROUPE;
uint16_t x0_box_boutons_scan;
uint16_t y0_box_boutons_scan;
uint16_t x0_box_SCAN; // grande surface d'affichage
uint16_t y0_box_SCAN;
uint16_t dx_box_SCAN;
uint16_t dy_box_SCAN;
uint16_t x0_numPad;
uint16_t y0_numPad;
uint16_t x0_vu_metre;
uint16_t y0_vu_metre;
uint16_t x0_box_info1;
uint16_t y0_box_info1;
uint16_t x0_box_info2 = x0_vu_metre;
uint16_t y0_box_info2 = y0_vu_metre;
uint16_t dx_box_info2;
uint16_t dy_box_info2;
uint16_t x0_saisie;
uint16_t y0_saisie;
uint16_t x0_choix_couleur;
uint16_t y0_choix_couleur;
uint8_t n_appui; // incrémenté à chaque appui sur une touche du numPad numérique
uint32_t total_saisi;
uint16_t status;
int16_t level;
uint16_t usn;
uint16_t wam;
int16_t offset;
uint16_t bandwidth;
uint16_t mod;
int8_t snr;
uint16_t A_block;
uint16_t B_block;
uint16_t C_block;
uint16_t D_block;
uint16_t dec_error;
float position_aiguille; // vu-metre
float valeur_affi;
float memo_valeur_affi;
float ltx; // aiguille
uint16_t osx;
uint16_t osy;
uint16_t couleur_traits = GRIS_5;
uint16_t JAUNE_chiffres = 65504;
uint16_t VERT_chiffres = 2016;
uint8_t cR = 0;
uint8_t cG = 0;
uint8_t cB = 0;
uint16_t couleur_fond_ecran = 0;
float degTOrad(float angle)
{
return (angle * M_PI / 180.0);
}
uint8_t decToBcd( int val )
{
return (uint8_t) ((val / 10 * 16) + (val % 10));
}
uint16_t Color_To_565(uint8_t r, uint8_t g, uint8_t b)
{
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}
void RGB565_to_888(uint16_t color565, uint8_t *R, uint8_t *G, uint8_t *B)
{
*R=(color565 & 0xF800) >> 8;
*G=(color565 & 0x7E0) >> 3;
*B=(color565 & 0x1F) << 3 ;
}
void init_variables_globales()
// je ne les initialise pas lors de leur déclaration sinon lors d'un reset logiciel (appel de la fonction 'setup()'
// par le boouton 'RST') elles ne seraient pas réinitialisées
{
// étalonnage touch screen
eTS.x0 = -30; eTS.y0 = -30;
eTS.dx = 11; eTS.dy = 14;
mode_affi = NORMAL;
bande_active = FM;
modulation_active = WFM;
mode_s = _MEM;
mode_scan = FREQUENCE;
mode_seuil = LEV;
mute = false;
vu_metre_actif = true;
FRQ_x0 = 50; FRQ_y0 = 30;
x0_box_SPIFFS = 2; y0_box_SPIFFS = 150;
x0_box_PRESET =2; y0_box_PRESET =87;
x0_box_GROUPE = 205; y0_box_GROUPE = 115;
x0_box_boutons_scan = 2; y0_box_boutons_scan = 105;
// grande surface d'affichage
x0_box_SCAN = 2; y0_box_SCAN = 90;
dx_box_SCAN = 315; dy_box_SCAN = 148;
x0_numPad = 70; y0_numPad = 115;
x0_vu_metre = 170; y0_vu_metre = 145;
x0_box_info1 = 71; y0_box_info1 = 220;
x0_box_info2 = x0_vu_metre; y0_box_info2 = y0_vu_metre;
dx_box_info2 = 140; dy_box_info2 = 70;
x0_saisie = 3; y0_saisie = 0;
x0_choix_couleur = 170; y0_choix_couleur = 145;
n_appui = 0; // incrémenté à chaque appui sur une touche du numPad numérique
total_saisi = 0;
position_aiguille = 0; // vu-metre
valeur_affi = 0;
memo_valeur_affi = 0;
ltx = 0; // aiguille
osx = x0_vu_metre;
osy = y0_vu_metre;
}
//uint16_t bmp_offset = 0;
uint16_t bmp_width;
uint16_t bmp_heigh;
void draw_bmp565(uint16_t x0, uint16_t y0, uint8_t sens, File* fp)
{
uint16_t i,j;
uint16_t y1;
uint8_t bmp_data[2]={0};
uint16_t bmp_color[2];
fp->seek(0);
for(i=0; i<bmp_heigh; i++)
{
for(j=0; j<(bmp_width); j++)
{
fp->read(bmp_data, 2); // lit les 2 octets constituant la valeur rgb565 et les place dans bmp_data[]
if (sens == 0) {y1 = y0+bmp_heigh-i;}
else {y1 = y0+i;}
TFT.drawPixel(x0+j, y1, bmp_data[0] + (bmp_data[1] << 8) );
}
}
}
void affiche_index_frq() // 6 petits boutons juste au dessus de chaque chiffre pour indiquer celui à modifier
{
int x = FRQ_x0 +15;
int y = FRQ_y0 - 5;
uint16_t c1 = NOIR;
uint16_t c2 = VERT;
bt_1.init(x, y, 20, 5, 0); bt_1.affiche(c1, c2, 1); x+=31;
bt_2.init(x, y, 20, 5, 0); bt_2.affiche(c1, c2, 1); x+=31;
bt_3.init(x, y, 20, 5, 0); bt_3.affiche(c1, c2, 1); x+=46;
bt_4.init(x, y, 20, 5, 0); bt_4.affiche(c1, c2, 1); x+=31;
bt_5.init(x, y, 20, 5, 0); bt_5.affiche(c1, c2, 1); x+=31;
bt_6.init(x, y, 20, 5, 0); bt_6.affiche(c1, c2, 1);
}
void efface_index_frq() // les 6 petits boutons
{
int x = FRQ_x0 +15;
int y = FRQ_y0 - 5;
TFT.fillRect(x, y, 190, 5, couleur_fond_ecran);
}
void init_boutons_Plus_Moins()// boutons '<' et '>'
{
int x0 = 240;
int y0 = 90;
String s1, s2;
uint16_t c1 = GRIS_6;
uint16_t c2 = JAUNE;
if(mode_s == _FRQ) { s1 = " -"; s2 = " +"; }
if(mode_s == _MEM) { s1 = " <"; s2 = " >"; }
bt_moins.init(x0, y0, 30, 15, 1);
bt_moins.cliked = false;
bt_moins.s = s1;
bt_plus.init(x0+35, y0, 30, 15, 1);
bt_plus.cliked = false;
bt_plus.s = s2;
}
void init_boutons_GROUPE() // groupe de fréquence (SW - FM - AIR - SCAN)
{
uint16_t x = x0_box_GROUPE+4;
uint16_t y = y0_box_GROUPE+5;
TFT.setFreeFont(FF0);
bt_SW.init(x, y, 20, 15, 3);
bt_SW.cliked = false;
bt_SW.selected = false;
bt_SW.s="SW";
x+=25;
bt_FM.init(x, y, 20, 15, 3);
bt_FM.cliked = false;
bt_FM.selected = false;
bt_FM.s="FM";
x+=25;
bt_AIR.init(x, y, 22, 15, 3);
bt_AIR.cliked = false;
bt_AIR.selected = false;
bt_AIR.s="AIR";
x+=27;
bt_SCN.init(x, y, 20, 15, 3);
bt_SCN.cliked = false;
bt_SCN.selected = false;
bt_SCN.s="SC";
}
void init_1_bouton(uint16_t xi, uint16_t yi, uint8_t dx, uint8_t dy, String si, TOUCH_BOUTON *bouton_i)
{
uint16_t c1 = GRIS_5;
uint16_t c2 = BLANC;
bouton_i->init(xi, yi, dx, dy, 3);
bouton_i->cliked = false;
bouton_i->selected = false;
bouton_i->s = si;
bouton_i->affiche(c1, c2, 1);
}
void init_boutons_MODE() // en haut à gauche
{
uint16_t c1 = NOIR;
uint16_t c2 = VERT;
TFT.setFreeFont(FF0);
TFT.setTextColor(GRIS_3, NOIR);
TFT.drawString("mode", 6, 17);
TFT.drawFastVLine(45, 15, 72, couleur_traits);
bt_mode_FRQ.init(5, 35, 37, 20, 2);
bt_mode_FRQ.selected = false;
bt_mode_FRQ.s="FRQ";
bt_mode_FRQ.affiche(c1, c2, 2);
bt_mode_MEM.init(5, 60, 37, 20, 2);
bt_mode_MEM.selected = true;
bt_mode_MEM.s="MEM";
bt_mode_MEM.affiche(c1, c2, 2);
affiche_index_frq();
}
void affiche_1_bt_RGB(TOUCH_BOUTON *bouton_i, uint16_t x, uint16_t y, uint8_t dx, uint16_t couleur, String s_i)
{
uint16_t c1 = couleur;
uint16_t c2 = JAUNE;
bouton_i->init(x, y, dx, 14, 3);
bouton_i->cliked = false;
bouton_i->selected = false;
bouton_i->s = s_i;
bouton_i->affiche(c1, c2, 1);
}
void init_sprites()
{
sprite_frq.createSprite(220, 55);
sprite_frq.loadFont(digitfont1);
sprite_frq.setTextColor(JAUNE_2, NOIR);
sprite_frq.setTextDatum(MR_DATUM); // alignement du texte
}
void Tuner_Reset(void)
{
Wire.beginTransmission(0x64);
Wire.write(0x1e);
Wire.write(0x5a);
Wire.write(0x01);
Wire.write(0x5a);
Wire.write(0x5a);
Wire.endTransmission();
}
bool Tuner_Table_Write(const unsigned char *tab)
{
if (tab[1] == 0xff)
{
delay(tab[2]);
return 1;
}
else { return Tuner_WriteBuffer((unsigned char *)&tab[1], tab[0]); }
}
void Tuner_Init(const unsigned char *table)
{
uint16_t r;
const unsigned char *p = table;
for (uint16_t i = 0; i < sizeof(tuner_init_tab9216); i += (pgm_read_byte(p + i) + 1))
{
if (1 != (r = Tuner_Table_Write(p + i))) break;
}
}
void Tune_Frequence(uint32_t F)
{
TFT.setFreeFont(FF0);
TFT.setTextColor(BLEU, NOIR);
String s1 = String(F);
TFT.drawString(s1, 80, 2);
if (F == 1500)
{
efface_box_entete3();
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString("MINIMUM ", 130, 2);
}
if (bande_SW)
{
modulation_active = AM;
Tune_Frequence_AM(F);
efface_box_entete3();
TFT.setTextColor(VERT, NOIR);
TFT.drawString("SW ", 130, 2);
}
if (bande_interdite1)
{
efface_box_entete3();
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString("NON DISPONIBLE", 130, 2);
}
if (bande_FM)
{
modulation_active = WFM;
Tune_Frequence_FM(F/10);
efface_box_entete3();
TFT.setTextColor(VERT, NOIR);
TFT.drawString("bande FM", 130, 2);
}
if (bande_interdite2)
{
efface_box_entete3();
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString("NON DISPONIBLE", 130, 2);
}
if (bande_AIR)
{
modulation_active = AM;
Tune_Frequence_AM(F-110000); // nécessite un convertisseur de fréquence 110MHz en entrée antenne
efface_box_entete3();
TFT.setTextColor(BLEU_CLAIR, NOIR);
TFT.drawString("AIR BAND", 130, 2);
}
if (F == 138000)
{
efface_box_entete3();
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString("F MAX ", 130, 2);
}
}
void load_GRP_FREQ_SPIFFS() // -> to RAM
{
Serial.println("--- Frequences lues en SPIFFS ---------------");
Serial.println(" ");
Serial.println("GROUPE SW");
groupe_SW.RAZ(); // important, sinon les fréquences se trouvent dédoublées lors d'un soft-reset
groupe_SW.load_bloc(); // SPIFFS -> RAM
groupe_SW.tri_bloc(); // en RAM
groupe_SW.bloc_to_serial();
Serial.println("---------------------------------------------");
Serial.println("GROUPE FM");
groupe_FM.RAZ();
groupe_FM.load_bloc();
groupe_FM.tri_bloc();
groupe_FM.bloc_to_serial();
Serial.println("---------------------------------------------");
Serial.println("GROUPE AIR");
groupe_AIR.RAZ();
groupe_AIR.load_bloc();
groupe_AIR.tri_bloc();
groupe_AIR.bloc_to_serial();
Serial.println("---------------------------------------------");
// remarque : le groupe SCAN n'est jamais enregistré en SPIFFS
}
uint16_t brightness(uint16_t couleur)
{
uint8_t r, g, b;
r = 0xFF & (couleur >> 16);
g = 0xFF & (couleur >> 8);
b = 0xFF & couleur;
return ( r + g + b );
}
void init_affichages()
{
TFT.fillRect(0, 14, 319, 230, couleur_fond_ecran);
if (brightness(couleur_fond_ecran) > 500) {couleur_traits = NOIR;} else {couleur_traits = BLANC;}
TFT.setTextColor(JAUNE, NOIR);
TFT.drawRect(0, 0, 319, 240, couleur_traits); // cadre principal pourtour de l'écran
TFT.setFreeFont(FF0);
TFT.setTextColor(BLANC, BLEU);
String s1 = "v:" + version;
TFT.drawString(s1, 45, 15);
while (!Serial && (millis() <= 1000));
init_boutons_MODE();
affiche_box_SPIFFS();
init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+16, 40, 15, "Raz", &bt_SPIFFS_RAZ);
init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+33, 40, 15, "Write", &bt_SPIFFS_write);
TFT.setFreeFont(FF0);
init_boutons_Plus_Moins();
init_boutons_GROUPE(); // (SW - FM - AIR - SC)
init_1_bouton(305, 15, 15, 15, "?", &bt_info);
init_1_bouton(202, 222, 32, 15, "Mute", &bt_mute);
init_1_bouton(233, 222, 30, 15, "SLP", &bt_sleep);
init_1_bouton(262, 222, 25, 15, "RST", &bt_reset);
init_1_bouton(288, 222, 30, 15, "Coul", &bt_affi_saisie_couleur);
init_1_bouton(160, 120, 40, 14, "TEST", &bt_TEST);
//bt_affi_saisie_couleur.affiche(NOIR, VERT, 1);
affiche_box_boutons_scan();
init_1_bouton(5, 118, 55, 15, "scan FRQ", &bt_scan_frq);
init_1_bouton(5, 135, 55, 15, "scan AIR", &bt_scan_air);
init_1_bouton(168, 97, 30, 15, "set", &bt_set);
init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+33, 40, 15, "Write", &bt_SPIFFS_write);
init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+50, 40, 15, "raz 1F", &bt_erase_1F);
init_1_bouton(x0_box_SPIFFS+4, y0_box_SPIFFS+67, 40, 15, "LST", &bt_SPIFFS_LST);
numPad1.init(x0_numPad, y0_numPad, true);
affiche_box_presets(); // conteneur des 8 petits boutons
presetPad1.init(x0_box_PRESET +5, y0_box_PRESET +5);
efface_box_entete2();
efface_box_entete3();
init_box_info();
affiche_box_FRQ(GRIS_3); // autour de la fréquence (gros chiffres JAUNE ou VERT)
if (mode_affi == NORMAL)
{
affiche_box_GROUPE();
bt_moins.affiche(GRIS_6, VERT ,1);
bt_plus.affiche(GRIS_6, VERT ,1);
bt_SW.affiche(GRIS_5, VERT, 1);
bt_FM.affiche(GRIS_5, VERT, 1);
bt_AIR.affiche(GRIS_5, VERT, 1);
bt_SCN.affiche(GRIS_5, VERT, 1);
}
bt_4.selected = true;
bt_4.cliked = true;
bt_4.affiche(NOIR, GRIS_2,1);
bt_mute.selected = false;
bt_mute.cliked = false;
bt_mute.affiche(NOIR, ROUGE, 1);
bt_sleep.affiche(NOIR, VERT, 1);
bt_TEST.affiche(NOIR, VERT, 1);
bt_reset.affiche(NOIR, VERT, 1);
affiche_frequence(frequence);
dessine_VuMetre();
}
void read_FRQ_File(FS &fs, String path, String cible) // en mémoire SPIFFS
{
Serial.print("Reading file: "); Serial.println(path);
File file = fs.open(path);
if (!file ) { Serial.println("failed to open file for reading"); return; }
String s;
uint8_t n =0;
while (file.available())
{
char c;
c = char(file.read());
if ((c !='<') && (c !='>')) {s += c;}
if(c=='>')
{
uint32_t frq;
frq = s.toInt();
Serial.println(frq);
s="";
if(cible == "SW") {presetPad1.bt_preset[n].frequence_SW = frq;}
if(cible == "FM") {presetPad1.bt_preset[n].frequence_FM = frq;}
if(cible == "AIR") {presetPad1.bt_preset[n].frequence_AIR = frq;}
n++;
}
}
file.close();
}
String read_line_params(uint16_t line_num)
{
int i = 1;
char buffer[64];
String s;
File file = SPIFFS.open("/params.txt", "r");
while (file.available())
{
int l = file.readBytesUntil('\n', buffer, sizeof(buffer));
buffer[l] = 0;
if (line_num == i)
{
s = buffer;
file.close();
return(s);
}
i++;
}
return "";
}
int32_t extract_params(String ligne, String label)
{
String s2;
uint32_t valeur = 0;
int p1, p2;
p1 = ligne.indexOf('['); p2 = ligne.indexOf(']');
s2 = ligne.substring(p1+1, p2);
if (s2 == label)
{
p1 = ligne.indexOf('<'); p2 = ligne.indexOf('>');
s2 = ligne.substring(p1+1, p2);
valeur = s2.toInt();
return valeur;
}
return -1;
}
void setup()
{
Serial.begin(115200);
delay(100);
// Avant la première utilisation il faut avoir formaté la partition SPIFFS
// et téléversé dedans les fichiers (images, fréquences, paramètres) avec Platformio ('Upload Filesystem image')
// voir ces liens :
// https://www.programmingelectronics.com/spiffs-esp32/
// https://randomnerdtutorials.com/esp32-vs-code-platformio-spiffs/
if (!SPIFFS.begin())
{
Serial.println("ERREUR montage SPIFFS");
} else Serial.println("montage SPIFFS OK");
init_variables_globales();
Wire.begin(GPIO_SDA, GPIO_SCL, 100000);
Serial.println("display.init()");
TFT.init();
TFT.setRotation(3); // 0..3 à voir, suivant disposition de l'afficheur
TFT.fillScreen(NOIR);
init_sprites();
// Start the SPI for the touch screen and init the TS library
mySpi.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
ts.begin(mySpi);
ts.setRotation(3);
affi_image_from_spiffs("/7.bmp", 0, 0); // IMAGE D'ACCEUIL
delay(1000);
/*
à voir ...
//Use this calibration code in setup():
uint16_t calData[5] = { 671, 2090, 1096, 1736, 3 };
tft.setTouch(calData);
*/
groupe_SW.filename = "/FRQ_SW.txt"; // nom du fichier en mémoire SPIFFS
groupe_FM.filename = "/FRQ_FM.txt";
groupe_AIR.filename = "/FRQ_AIR.txt";
int Ts = SPIFFS.totalBytes();
int Us = SPIFFS.usedBytes();
Serial.println("-------------------------------------");
Serial.println("SPIFFS Info:");
Serial.print("Total Bytes "); Serial.println(Ts);
Serial.print("Used Bytes "); Serial.println(Us);
Serial.print("Free Bytes "); Serial.println(Ts-Us);
Serial.println("-------------------------------------");
load_GRP_FREQ_SPIFFS(); // -> to RAM
groupe_SCAN.RAZ();
presetPad1.set_frequences_PRST();
presetPad1.set_couleurs();
// lecture du fichier '/params.txt' en SPIFFS
Serial.println("lecture du fichier '/params.txt' en SPIFFS");
String s1;
int valeur;
Serial.println("---------------------------------------------");
Serial.println("read params() ");
for(uint16_t n=1; n<=9; n++) // lit toutes(9) lignes du fichier
{
s1 = read_line_params(n); // retourne(par exemple): [couleur_fond]<267>
Serial.print(n); Serial.println(" " + s1);
valeur = extract_params(s1, "couleur_fond"); // extrait la valeur correspondant au label
if(valeur != -1) {couleur_fond_ecran = valeur;}
valeur = extract_params(s1, "frequence");
if(valeur != -1) {frequence = extract_params(s1, "frequence");}
}
Serial.print("---------------------------------------------");
boolean vu_metre_actif = true;
TFT.fillScreen(NOIR);
init_affichages();
saut_freq = 100;
Tuner_Init(tuner_init_tab9216);
// Set_no_AM_gain_reduction();
bt_mode_FRQ.selected = false;
bt_mode_MEM.selected = true;
uint16_t c1 = GRIS_6;
uint16_t c2 = VERT;
uint16_t c3 = JAUNE;
bt_mode_FRQ.affiche(c1, c2, 2); // bt en haut à gauche
bt_mode_MEM.affiche(c1, c3, 2); // bt en haut à gauche
groupe_actif = gFM;
bande_active = FM;
modulation_active = WFM;
bt_FM.selected = true;
bt_SW.selected = false;
bt_AIR.selected = false;
bt_SCN.selected = false;
bt_SW.affiche(c1, c2, 1);
bt_FM.affiche(c1, c3, 1);
//clic_logiciel_bouton(&presetPad1.bt_preset[0]);
//traite_boutons_presetPad(0);
uint8_t nb_F = groupe_FM.nb_freq;
affiche_numero_frq(String(1), String(nb_F));
affiche_frequence(frequence);
Tune_Frequence(frequence);
Set_Volume(+60);
delay(100);
//clic_logiciel_bouton(&bt_mode_MEM);
mode_s = _MEM;
if (test_touch_screen == true) {printTouchToDisplay();}
Serial.print("- FIN DU SETUP -----------------");
// FIN DU SETUP
}
void printTouchToDisplay() // pour TEST
{
TFT.fillScreen(NOIR);
TFT.setFreeFont(FM9);
TFT.setTextColor(BLEU_CLAIR, NOIR);
TFT.drawString("TEST TOUCH screen", 80, 120);
while(1)
{
if (ts.tirqTouched() && ts.touched())
{
TS_Point p = ts.getPoint();
x_touch = eTS.x0 + p.x /eTS.dx;
y_touch = eTS.y0 + p.y /eTS.dy;
TFT.drawRect(x_touch, y_touch, 1, 1, JAUNE);
// affiche force d'appui du stylet
/*
int x = 320 / 2; // center of display
int y = 100;
int fontSize = 2;
String temp = "P= " + String(p.z);
TFT.drawCentreString(temp, x, y, fontSize);
*/
}
}
}
// -------------------------------------------------------------------------
// Le vu-metre est une variante perso du code : "/Arduino/libraries/TFT_eSPI/examples/480 x 320/TFT_Meters"
// voir le fichier licence.txt dans le dossier "/Arduino/libraries/TFT_eSPI/examples/"
void dessine_VuMetre()
{
if (vu_metre_actif == false) {return;}
uint16_t x0 = x0_vu_metre;
uint16_t y0 = y0_vu_metre;
uint16_t dx=140;
uint16_t dy=70;
uint8_t AA = 65; // 65
uint8_t BB = x0 +dx/2;// 120
uint8_t CC = y0 + dy+20; // 140
TFT.setFreeFont(FF0);
// cadre rectangulaire
TFT.fillRect(x0, y0, dx, dy, GRIS_3);
TFT.fillRect(x0+3, y0+3, dx-6, dy-6, BLANC);
TFT.setTextColor(NOIR);
// graduation chaque 5 deg entre -50 et +50 deg
for (int i = -50; i < 51; i += 10)
{
int tl = 5; // tiret plus long
// Coordonnées du tiret à dessiner
float sx = cos((i - 90) * deg_to_rad);
float sy = sin((i - 90) * deg_to_rad);
uint16_t tx0 = sx * (AA + tl) + BB;
uint16_t ty0 = sy * (AA + tl) + CC;
uint16_t tx1 = sx * AA + BB;
uint16_t ty1 = sy * AA + CC;
float sx2 = cos((i + 5 - 90) * deg_to_rad);
float sy2 = sin((i + 5 - 90) * deg_to_rad);
int tx2 = sx2 * (AA + tl) + BB;
int ty2 = sy2 * (AA + tl) + CC;
int tx3 = sx2 * AA + BB;
int ty3 = sy2 * AA + CC;
// zone verte
if (i >= 0 && i < 25)
{
TFT.fillTriangle(tx0, ty0, tx1, ty1, tx2, ty2, VERT);
TFT.fillTriangle(tx1, ty1, tx2, ty2, tx3, ty3, VERT);
}
// zone orange
if (i >= 25 && i < 50)
{
TFT.fillTriangle(tx0, ty0, tx1, ty1, tx2, ty2, ORANGE);
TFT.fillTriangle(tx1, ty1, tx2, ty2, tx3, ty3, ORANGE);
}
if (i % 25 != 0) tl = 8;
tx0 = sx * (AA + tl) + BB;
ty0 = sy * (AA + tl) + CC;
tx1 = sx * AA + BB;
ty1 = sy * AA + CC;
TFT.drawLine(tx0, ty0, tx1, ty1, NOIR);
if (i % 20 == 0)
{
tx0 = sx * (AA + tl + 10) + BB;
ty0 = sy * (AA + tl + 10) + CC;
switch (i / 20)
{
case -2: TFT.drawCentreString("0", tx0, ty0 - 6, 1); break;
case -1: TFT.drawCentreString("25", tx0, ty0 - 4, 1); break;
case 0: TFT.drawCentreString("50", tx0, ty0 - 6, 1); break;
case 1: TFT.drawCentreString("75", tx0, ty0 - 4, 1); break;
case 2: TFT.drawCentreString("100", tx0, ty0 - 6, 1); break;
}
}
sx = cos((i + 5 - 90) * deg_to_rad);
sy = sin((i + 5 - 90) * deg_to_rad);
tx0 = sx * AA + BB;
ty0 = sy * AA + CC;
if (i < 50) {TFT.drawLine(tx0, ty0, tx1, ty1, NOIR);}
}
}
void plotAiguille(float value)
{
if (vu_metre_actif == false) {return;}
uint16_t x0 = x0_vu_metre;
uint16_t y0 = y0_vu_metre;
uint16_t dx=140;
uint16_t dy=50;
uint8_t AA = dx/2; // 100
uint8_t BB = x0 +dx/2;// 120
uint8_t CC = y0 + dy+25; // 140
TFT.setTextColor(TFT_BLACK, BLANC);
char buf[8]; dtostrf(value, 4, 0, buf);
if (value < -10) value = -10;
if (value > 110) value = 110;
float sdeg = map(value, -10, 110, -150, -30);
float sx = cos(sdeg * deg_to_rad);
float sy = sin(sdeg * deg_to_rad);
float tx = tan((sdeg + 90) * deg_to_rad);
TFT.drawLine(BB + 20*ltx - 1, CC - 20, osx - 1, osy, BLANC); //efface
TFT.drawLine(BB + 20*ltx, CC - 20, osx, osy, BLANC);
TFT.drawLine(BB + 20*ltx + 1, CC - 20, osx + 1, osy, BLANC);
ltx = tx;
osx = sx*50 + BB;
osy = sy*50 + CC;
TFT.drawLine(BB + 20*ltx - 1, CC - 20, osx - 1, osy, ROUGE);
TFT.drawLine(BB + 20*ltx, CC - 20, osx, osy, VIOLET);
TFT.drawLine(BB + 20*ltx + 1, CC - 20, osx + 1, osy, ROUGE);
TFT.fillRect(x0, y0+dy+5, dx, 15, GRIS_2);
}
void init_box_info()
{
TFT.drawRect(x0_box_info1, y0_box_info1, 130, 16, NOIR);
TFT.setFreeFont(FF0);
TFT.setTextColor(JAUNE, couleur_fond_ecran);
TFT.drawString("RDS", x0_box_info1 -20, y0_box_info1 + 4);
}
void affiche_unit(String s)
{
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FM9); //FM9 FMB9 FSS9... voir le fichier FrSPIFFS_Fonts.h
TFT.drawString(s, FRQ_x0 + 225, FRQ_y0 + 35);
}
void efface_numero_frq()
{
TFT.fillRect(FRQ_x0 + 225, FRQ_y0 + 20, 40, 12, couleur_fond_ecran);
}
void affiche_numero_frq(String s1, String s2)
{
//TFT.fillRect(FRQ_x0 + 225, FRQ_y0 + 5, 10, 10, BLEU);
TFT.setTextColor(BLANC, couleur_fond_ecran);
TFT.setFreeFont(FF0);
TFT.drawString(s1 + "/" + s2 + " ", FRQ_x0 + 225, FRQ_y0 + 20);
affiche_box_FRQ(GRIS_3); // pour retracer le côté droit du rectangle
}
void affiche_band(String s)
{
//TFT.fillRect(FRQ_x0 + 225, FRQ_y0 + 5, 10, 10, BLEU);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FM9);
String blancs;
if (s == "AIR") {blancs = " ";} else {blancs = " ";}
TFT.drawString(s + blancs, FRQ_x0 + 225, FRQ_y0);
affiche_box_FRQ(GRIS_3); // pour retracer le côté droit du rectangle
}
void efface_box_entete1()
{
TFT.fillRect(0, 1, 50, 12, NOIR);
}
void efface_box_entete2()
{
TFT.fillRect(50, 1, 180, 12, NOIR);
}
void efface_box_entete3()
{
TFT.fillRect(230, 1, 76, 12, NOIR);
memo_valeur_affi--; // pour réafficher tension batterie
}
void affiche_box_FRQ(uint16_t couleur) // autour de la fréquence (en gros chiffres JAUNE
{
TFT.drawRect(0, FRQ_y0 -17, 319, 74, couleur);
}
void affiche_box_presets() // boutons 1 2 3 4 5 6 7 8
{
TFT.fillRect(x0_box_PRESET, y0_box_PRESET, 164, 24, NOIR);
TFT.setTextColor(GRIS_3, NOIR);
}
void affiche_box_GROUPE() // groupes de fréquences; contient 4 boutons SW, FM, AIR, SC
{
TFT.fillRect(x0_box_GROUPE, y0_box_GROUPE, 105, 23, NOIR);
//TFT.drawRect(x0_box_GROUPE, y0_box_GROUPE, 105, 25, couleur_traits);
TFT.setFreeFont(FF0);
TFT.setTextColor(GRIS_3, NOIR);
TFT.drawString("groupes Freq", x0_box_GROUPE+4, y0_box_GROUPE-6);
}
void efface_box_GROUPE()
{
//TFT.fillRect(x0_box_GROUPE, y0_box_GROUPE-7, 110, 33, couleur_fond_ecran);
}
void affiche_box_SPIFFS() // Raz, Write, Raz 1F, LST
{
TFT.fillRect(x0_box_SPIFFS, y0_box_SPIFFS + 10, 46, 75, NOIR);
TFT.setFreeFont(FF0);
TFT.setTextColor(GRIS_3, NOIR);
TFT.drawString("SPIFFS", x0_box_SPIFFS+6, y0_box_SPIFFS+6);
}
void affiche_box_boutons_scan()
{
TFT.fillRect(x0_box_boutons_scan, y0_box_boutons_scan + 10, 60, 38, NOIR);
}
void affiche_box_scan(uint16_t dy)
{
init_1_bouton(301, y0_box_SCAN+1, 15, 15, "x", &bt_stop_scan);
if (bande_active != AIR)
{
init_1_bouton(275, y0_box_SCAN+17, 40, 15, "rescan", &bt_re_scan);
init_1_bouton(275, y0_box_SCAN+34, 40, 14, " >>", &bt_scan_suivant);
}
init_1_bouton(255, y0_box_SCAN+1, 15, 15, "+", &bt_seuil_plus);
init_1_bouton(255, y0_box_SCAN+20, 15, 15, "-", &bt_seuil_moins);
init_1_bouton(4, y0_box_SCAN+3, 15, 15, "L", &bt_LEV);
init_1_bouton(4, y0_box_SCAN+20, 15, 15, "N", &bt_SNR);
}
void affi_boutons_SW_FM_AIR_SCN()
{
if((mode_affi == SCAN_F ) || (mode_affi == SCAN_M )) {return;}
uint16_t c1 = GRIS_5;
uint16_t c2 = VERT;
bt_SW.affiche(c1, c2, 1);
bt_FM.affiche(c1, c2, 1);
bt_AIR.affiche(c1, c2, 1);
bt_SCN.affiche(c1, BLEU_CLAIR, 1);
bt_mute.affiche(NOIR, ROUGE, 1);
}
void affiche_frequence(uint32_t frq)
{
uint16_t couleur_chiffres;
if(mode_s == _FRQ) {couleur_chiffres = VERT_chiffres;}
if(mode_s == _MEM) {couleur_chiffres = JAUNE_chiffres;}
if(bande_SW) // d'après la fréquence; SW - 28 MHz = limite haute du module
{
affiche_band("SW");
modulation_active = AM;
if (groupe_actif != gSCN) {bande_active = SW; groupe_actif == gSW;}
bt_SW.selected = true;
bt_FM.selected = false; // les boutons sont exclusifs
bt_AIR.selected = false;
//bt_SCN.selected = false;
affi_boutons_SW_FM_AIR_SCN();
String s1, sM, sK;
uint8_t L;
s1 = String(frq);
s1 = "000000" + s1;
L= s1.length();
sK = s1.substring(L-3); // kHz
sM = s1.substring(L-6, L-3); // Mhz
sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
sprite_frq.setTextColor(couleur_chiffres, NOIR);
sprite_frq.drawString(sM + "." + sK + " ", 220+10, 32);
// remarque: le fait d'ajouter " " à la fin évite aux chiffres de se balader horizontalement !
sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
affiche_unit("MHz");
Tune_Frequence(frq);
}
if(bande_FM) // bande FM, on efface les deux '0' de droite (si == 0 sinon on affiche quand même)
{
affiche_band("FM");
modulation_active = WFM;
if (groupe_actif != gSCN) {bande_active = FM; groupe_actif == gFM;}
affi_boutons_SW_FM_AIR_SCN();
String s1, sM, sK1, sK2, sK3;
String decimales;
uint8_t x0 = 0;
uint8_t L;
s1 = String(frq);
s1 = "000000" + s1;
L= s1.length();
sK1 = s1.substring(L-3, L-2); // 1ere décimale
sK2 = s1.substring(L-2, L-1); // 2eme décimale
sK3 = s1.substring(L-1, L); // 3eme décimale
if ((sK2 == "0") && (sK3 == "0"))
{
decimales = sK1;
x0=170;
}
else
{
decimales = sK1 + sK2 + sK3;
x0=232;
}
if (frq < 100000) {sM = s1.substring(L-5, L-3); }// on ne retient que deux chiffres à gauche du point
else { sM = s1.substring(L-6, L-3); } // on garde 3 chiffres à gauche du point décimal
sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
sprite_frq.setTextColor(couleur_chiffres, NOIR);
sprite_frq.drawString(sM + "." + decimales + " ", x0, 32);
// remarque: le fait d'ajouter " " à la fin évite aux chiffres de se balader horizontalement !
sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
affiche_unit("MHz");
Tune_Frequence(frq);
bt_mute.selected = false;
bt_mute.cliked = false;
}
if(bande_AIR) // bande AIR - 138000-110000 = 28MHz (limite haute de réception AM du module)
{
affiche_band("AIR");
modulation_active = AM;
if (groupe_actif != gSCN) {bande_active = AIR; groupe_actif == gAIR;}
bt_AIR.selected = true;
bt_SW.selected = false; // les boutons sont exclusifs
bt_FM.selected = false;
//bt_SCN.selected = false;
affi_boutons_SW_FM_AIR_SCN();
String s1, sM, sK;
uint8_t L;
s1 = String(frq);
s1 = "000000" + s1;
L= s1.length();
sK = s1.substring(L-3); // kHz
sM = s1.substring(L-6, L-3); // Mhz
sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
sprite_frq.setTextColor(couleur_chiffres, NOIR);
sprite_frq.drawString(sM + "." + sK + " ", 220+10, 32);
sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
affiche_unit("MHz");
Tune_Frequence(frq);
}
if(bande_interdite1 || bande_interdite2) // bandes interdites par le module TEF6686
{
affiche_band("---");
String s1, sM, sK;
uint8_t L;
s1 = String(frq);
s1 = "000000" + s1;
L= s1.length();
sK = s1.substring(L-3); // kHz
sM = s1.substring(L-6, L-3); // Mhz
sprite_frq.fillRect(0, 0, 220, 60, NOIR); // efface
sprite_frq.setTextColor(couleur_chiffres, NOIR);
sprite_frq.drawString(sM + "." + sK + " ", 220+10, 32);
// remarque: le fait d'ajouter " " à la fin évite aux chiffres de se balader horizontalement !
sprite_frq.pushSprite(FRQ_x0, FRQ_y0);
affiche_unit("MHz");
}
if(frq==138000) { affiche_band("max"); }
if(frq>138000) { affiche_band("---"); }
}
void clic_logiciel_bouton(TOUCH_BOUTON *bouton_i)
{
uint16_t c1 = NOIR;
uint16_t c2 = JAUNE;
bouton_i->cliked = true;
bouton_i->selected = true;
bouton_i->affiche(c1, c2, 1);
}
void test_clic_boutons(TOUCH_BOUTON *bouton_i)
{
uint16_t c1 = NOIR;
uint16_t c2 = GRIS_2;
if ((x_touch > bouton_i->x0) && (x_touch < bouton_i->x0 + bouton_i->read_dx())
&& ( y_touch > bouton_i->y0-4) && (y_touch < bouton_i->y0-4 + bouton_i->read_dy()) )
{
bouton_i->cliked = true;
bouton_i->selected = true;
bouton_i->affiche(c1, c2, 1);
}
}
void test_clic_6_boutons_frq() //rectangles situés au dessus des gros chiffres de la fréquence
{
uint16_t c1 = NOIR;
uint16_t c2 = VERT;
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
{
bt_1.cliked = false; bt_1.selected = false; test_clic_boutons(&bt_1 ); bt_1.affiche(c1, c2,1);
bt_2.cliked = false; bt_2.selected = false; test_clic_boutons(&bt_2 ); bt_2.affiche(c1, c2,1);
bt_3.cliked = false; bt_3.selected = false; test_clic_boutons(&bt_3 ); bt_3.affiche(c1, c2,1);
bt_4.cliked = false; bt_4.selected = false; test_clic_boutons(&bt_4 ); bt_4.affiche(c1, c2,1);
bt_5.cliked = false; bt_5.selected = false; test_clic_boutons(&bt_5 ); bt_5.affiche(c1, c2,1);
bt_6.cliked = false; bt_6.selected = false; test_clic_boutons(&bt_6 ); bt_6.affiche(c1, c2,1);
if (bt_6.cliked) {saut_freq = 1;}
if (bt_5.cliked) {saut_freq = 10;}
if (bt_4.cliked) {saut_freq = 100;}
if (bt_3.cliked) {saut_freq = 1000;}
if (bt_2.cliked) {saut_freq = 10000;}
if (bt_1.cliked) {saut_freq = 100000;}
}
}
void affiche_saisie(String s1)
{
TFT.fillRect(x0_saisie+1, y0_saisie-1, 60, 12, NOIR); // efface
TFT.setFreeFont(FF0); TFT.setTextColor(VERT, NOIR);
TFT.drawString(s1, x0_saisie+5, y0_saisie+3);
}
void traite_touches_pad(uint8_t num_touche) // pavé numérique
{
if(num_touche == 253) {return;}
uint16_t c1 = GRIS_6;
uint16_t c2 = JAUNE;
uint16_t c3 = VERT;
int p1;
if (num_touche == 254) // bouton "."
{
frequence_txt += ".";
affiche_saisie(frequence_txt);
}
if (num_touche < 10)
{
frequence_txt += String(num_touche);
affiche_saisie(frequence_txt);
delay(300);
}
x_touch =0;
y_touch =0;
if (num_touche == 255) // bouton "ok"
{
Serial.println("touche ok");
affiche_saisie(""); // efface
mode_s = _FRQ;
bt_mode_MEM.selected = false;
bt_mode_FRQ.selected = true;
bt_mode_MEM.affiche(c1, c2, 2);
bt_mode_FRQ.affiche(c1, c3, 2);
double F = frequence_txt.toDouble();
p1 = frequence_txt.indexOf(".");
if (p1 != -1) {F *=1000;} // si présence du point décimal
frequence = F;
affiche_frequence(frequence); // 'Tune_Frequence(frq)' est appelée dans cette fonction 'affiche_frequence()'
n_appui = 0;
frequence_txt = "";
TFT.fillRect(250, 0, 60, 12, NOIR); // efface
n_appui = 0;
}
num_touche = 0;
}
void record_fichier_params() // en memoire SPIFFS
{
Serial.println("write fichier '/params.txt'");
File file1 = SPIFFS.open("/params.txt", FILE_WRITE);
String s1;
s1 ="[couleur_fond]";
s1 += "<";
s1 += String(couleur_fond_ecran);
s1 +=">";
file1.println(s1);
s1 ="[frequence]";
s1 += "<";
s1 += String(frequence);
s1 +=">";
file1.println(s1);
file1.close();
delay(300);
}
void record_fichier_FRQ_SW_PRST()
{
Serial.println("record_fichier_FRQ_SW_PRST()");
File file1 = SPIFFS.open("/FRQ_FM_PRST.txt", FILE_WRITE);
String s1;
for(uint8_t n=0; n<8; n++)
{
s1 = "<";
s1 += String(presetPad1.bt_preset[n].frequence_SW);
s1 +=">";
file1.println(s1);
}
file1.close();
}
void record_fichier_FRQ_FM_PRST()
{
Serial.println("record_fichier_FRQ_FM_PRST()");
File file1 = SPIFFS.open("/FRQ_FM_PRST.txt", FILE_WRITE);
String s1;
for(uint8_t n=0; n<8; n++)
{
s1 = "<";
s1 += String(presetPad1.bt_preset[n].frequence_FM);
s1 +=">";
file1.println(s1);
}
file1.close();
}
void record_fichier_FRQ_AIR_PRST()
{
Serial.println("record_fichier_FRQ_AIR_PRST()");
File file1 = SPIFFS.open("/FRQ_AIR_PRST.txt", FILE_WRITE);
String s1;
for(uint8_t n=0; n<8; n++)
{
s1 = "<";
s1 += String(presetPad1.bt_preset[n].frequence_AIR);
s1 +=">";
file1.println(s1);
}
file1.close();
}
void traite_boutons_presetPad(uint8_t n_bt)
{
if (n_bt > 7) {return;}
uint16_t c1 = GRIS_5;
uint16_t c2 = JAUNE;
uint32_t adr0, adr1, adr2, adr;
if (mode_affi == NORMAL)
{
// Lit la frequence dans le bouton concerné (VOIR: 'class TOUCH_BOUTON_PRESET')
if(bande_active == SW) {frequence = presetPad1.bt_preset[n_bt].frequence_SW;}
if(bande_active == FM) {frequence = presetPad1.bt_preset[n_bt].frequence_FM;}
if(bande_active == AIR) {frequence = presetPad1.bt_preset[n_bt].frequence_AIR;}
}
if (mode_affi == SET_F_PRESET)
{
if(bande_active == SW)
{
presetPad1.bt_preset[n_bt].frequence_SW = frequence; // en RAM
record_fichier_FRQ_SW_PRST();
mode_affi = NORMAL;
delay(500);
}
if(bande_active == FM)
{
presetPad1.bt_preset[n_bt].frequence_FM = frequence;
record_fichier_FRQ_FM_PRST();
mode_affi = NORMAL;
delay(500);
}
if(bande_active == AIR)
{
presetPad1.bt_preset[n_bt].frequence_AIR = frequence;
record_fichier_FRQ_AIR_PRST();
mode_affi = NORMAL;
delay(500);
}
mode_affi = NORMAL;
vu_metre_actif = true;
init_affichages();
}
if (mode_affi == COUL) // saisie couleur fond d'écran
{
mode_affi = NORMAL;
couleur_fond_ecran = presetPad1.bt_preset[n_bt].couleur;
record_fichier_params();
vu_metre_actif = true;
init_affichages();
}
affiche_frequence(frequence);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF0);
Tune_Frequence(frequence);
}
uint32_t inc_Frq_in_groupe(GROUPE_FREQUENCES *groupe_Freq, int8_t di) // di = +/-1
{
if ((di<-1)||(di>1)) {return 0;}
uint16_t n_max = groupe_Freq->nb_freq;
uint16_t n = groupe_Freq->num_F_actuelle;
if(n_max > 99) {n_max = 99;}
if (di == 1)
{
if (n<n_max-1) { n++; }
else if (n >= (n_max-1)) {n=0;}
}
if (di == -1)
{
if (n>=1) { n--; }
else if (n==0) {n = n_max-1;}
}
if(n > 99) {n = 0;}
groupe_Freq->num_F_actuelle = n;
uint16_t adr = groupe_Freq->adr_1ere_frq + n;
uint8_t nb_F = groupe_Freq->nb_freq;
uint8_t num_1ere_F = groupe_Freq->adr_1ere_frq;
affiche_numero_frq(String(1 + adr - num_1ere_F), String(nb_F));
uint32_t valeur_lue = groupe_Freq->G_freq[adr];
return valeur_lue;
}
void test_clic_boutons_plus_moins()
{
uint16_t c1 = GRIS_6;
uint16_t c2 = GRIS_3;
boolean bouton_cliked = false;
efface_box_entete2();
//--------------------------------------------------------------------
if(mode_s == _FRQ) // on va modifier directement la fréquence
{
test_clic_boutons(&bt_plus );
bt_plus.affiche(c1, c2, 1);
if (bt_plus.cliked)
{
frequence += saut_freq;
bouton_cliked = true;
}
delay(20);
if (bt_plus.cliked && ((frequence + saut_freq) <= 138000 ))
{
Tune_Frequence(frequence);
}
bt_plus.cliked = false;
bt_plus.selected = false;
bt_plus.affiche(c1, c2, 1); // fugitif
test_clic_boutons(&bt_moins );
bt_moins.affiche(c1, c2, 1);
delay(20);
if (bt_moins.cliked)
{
if (frequence > saut_freq) // évite de se retrouver avec une F négative !
{
bouton_cliked = true;
frequence -= saut_freq;
}
}
if(bt_moins.cliked && frequence > saut_freq) { Tune_Frequence(frequence); }
bt_moins.cliked = false;
bt_moins.selected = false;
bt_moins.affiche(c1, c2, 1); // fugitif
if(bouton_cliked == true)
{
bouton_cliked = false;
affiche_frequence(frequence);
}
}
//-------------------------------------------------------------------------
if(mode_s == _MEM) // on va parcourir les fréquences de la liste
{
test_clic_boutons(&bt_plus );
bt_plus.affiche(c1, c2, 1);
if (bt_plus.cliked)
{
bouton_cliked = true;
Serial.println("bt_plus.cliked");
if(groupe_actif == gSW) { frequence = inc_Frq_in_groupe(&groupe_SW, 1); }
if(groupe_actif == gFM) { frequence = inc_Frq_in_groupe(&groupe_FM, 1); }
if(groupe_actif == gAIR) { frequence = inc_Frq_in_groupe(&groupe_AIR, 1); }
if(groupe_actif == gSCN) { frequence = inc_Frq_in_groupe(&groupe_SCAN, 1); }
Tune_Frequence(frequence);
delay(100);
}
bt_plus.cliked = false;
bt_plus.selected = false;
bt_plus.affiche(c1, c2, 1); // fugitif
test_clic_boutons(&bt_moins );
bt_moins.affiche(c1, c2, 1);
delay(20);
if (bt_moins.cliked)
{
bouton_cliked = true;
Serial.println("bt_moins.cliked");
if(groupe_actif == gSW) { frequence = inc_Frq_in_groupe(&groupe_SW, -1); }
if(groupe_actif == gFM) { frequence = inc_Frq_in_groupe(&groupe_FM, -1); }
if(groupe_actif == gAIR) { frequence = inc_Frq_in_groupe(&groupe_AIR, -1); }
if(groupe_actif == gSCN) { frequence = inc_Frq_in_groupe(&groupe_SCAN, -1); }
Tune_Frequence(frequence);
delay(100);
}
bt_moins.cliked = false;
bt_moins.selected = false;
bt_moins.affiche(c1, c2, 1); // fugitif
if(bouton_cliked == true)
{
bouton_cliked = false;
affiche_frequence(frequence);
}
}
}
void test_clic_bt_RST_affi() // bouton "ok" de la box saisie couleur de fond ecran
{
if(mode_affi != COUL) {return;}
uint16_t c1 = GRIS_6;
uint16_t c2 = JAUNE;
test_clic_boutons(&bt_RST_affi );
if (bt_RST_affi.cliked)
{
bt_RST_affi.cliked = false;
bt_RST_affi.selected = true;
bt_RST_affi.affiche(NOIR, VERT, 1);
init_affichages();
}
}
void test_clic_bt_affi_saisie_couleur() // bouton au coin en bas à droite
{
uint16_t c1 = GRIS_5;
uint16_t c2 = BLANC;
test_clic_boutons(&bt_affi_saisie_couleur );
if (bt_affi_saisie_couleur.cliked)
{
bt_affi_saisie_couleur.cliked = false;
bt_affi_saisie_couleur.selected = true;
bt_affi_saisie_couleur.affiche(NOIR, VERT, 1);
vu_metre_actif = false;
TFT.fillRect(x0_box_info2, y0_box_info2, dx_box_info2, dy_box_info2, NOIR);
TFT.setTextColor(VERT, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("Cliquez sur un des 8 bt", x0_box_info2+2, y0_box_info2+2);
TFT.drawString("'preset' pour choisir", x0_box_info2+2, y0_box_info2+12);
TFT.drawString("la couleur de fond", x0_box_info2+2, y0_box_info2+22);
mode_affi = COUL;
presetPad1.init(x0_box_PRESET +5, y0_box_PRESET +5);
}
}
void test_clic_bouton_mute()
{
test_clic_boutons(&bt_mute );
if (bt_mute.cliked)
{
bt_mute.affiche(NOIR, ROUGE, 1);
delay(100);
bt_mute.cliked = false;
if(mute == false) {mute = true;} else {mute = false;}
Set_Mute(mute); // fonction située dans le fichier 'driverTEF6686_628.h'
bt_mute.selected = mute;
bt_mute.affiche(NOIR, ROUGE, 1);
if (mute == false) {Tune_Frequence(frequence);}
delay(500);
}
}
void test_clic_bouton_info()
{
test_clic_boutons(&bt_info);
if (bt_info.cliked)
{
bt_info.cliked = false;
bt_info.selected = true;
bt_info.affiche(NOIR, VERT, 1);
delay(100);
// affiche une page d'information:
TFT.fillScreen(NOIR);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF1);
uint16_t y=0;
TFT.drawString("Radio TEF6686", 0, y); y+=20;
String s1="version " + version;
TFT.drawString(s1, 0, y); y+=20;
TFT.setTextColor(CYAN, NOIR);
TFT.drawString("Silicium628", 0, y); y+=40;
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("SW (AM): 1500kHz -- 28MHz", 0, y); y+=20;
TFT.drawString("bande FM (WFM): 88MHz -- 108MHz", 0, y); y+=20;
TFT.drawString("bande Aviation Civile: 118MHz -- 137MHz (AM)", 0, y); y+=20;
delay(300);
attente_clic();
}
}
void test_clic_bouton_Sleep()
{
test_clic_boutons(&bt_sleep );
if (bt_sleep.cliked)
{
bt_sleep.cliked = false;
bt_sleep.selected = true;
bt_sleep.affiche(NOIR, ROUGE, 1);
delay(100);
//todo: save en SPIFFS
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF1);
TFT.drawString("Cliquez pour MODE SLEEP", 20, 50);
TFT.drawString("de l'ESP32", 20, 70);
TFT.drawString("Eteindre pour quitter", 20, 90);
TFT.drawString("ce mode SLEEP", 20, 110);
delay(300);
attente_clic();
esp_deep_sleep_start();
}
}
uint16_t read16(fs::File &f)
{
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(fs::File &f)
{
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
void affi_image_from_spiffs(String filename, uint16_t x0, uint16_t y0)
{
// pour image bmp encodée en RGb565 (5+6+5 = 16 bits)
uint8_t bmp_data[2]={0,0};
uint8_t a, b;
uint16_t x=0;
uint16_t y=0;
uint32_t seekOffset;
uint16_t w, h, row, col;
File bmpFS = SPIFFS.open(filename, "r");
if (!bmpFS) { Serial.println("ERREUR open file on SPIFFS"); return; }
else { Serial.println("open file on SPIFFS ok");}
int16_t xmax;
uint16_t etiq1 = read16(bmpFS); // == 0x 4D42)
Serial.print("etiq1= "); Serial.println(etiq1, HEX); // ok affiche "4D42"
if (etiq1 == 0x4D42)
{
read32(bmpFS);
read32(bmpFS);
seekOffset = read32(bmpFS);
Serial.print("seekOffset= "); Serial.println(seekOffset);
read32(bmpFS);
w = read32(bmpFS);
h = read32(bmpFS);
Serial.print("w= "); Serial.println(w); // 75
Serial.print("h= "); Serial.println(h); // 50
Serial.println(read16(bmpFS)); // 1
Serial.println(read16(bmpFS)); // 16
Serial.println(read16(bmpFS)); // 3
bmpFS.seek(seekOffset);
}
y += h;
xmax = w;
if(xmax%2 == 1) {xmax +=1;}
uint16_t padding = (4 - ((w * 2) & 2)) & 2;
uint8_t lineBuffer[(w*2) + padding];
for (row = 0; row < h; row++)
{
bmpFS.read(lineBuffer, sizeof(lineBuffer));
uint8_t* bptr = lineBuffer;
uint16_t* tptr = (uint16_t*)lineBuffer;
for (uint16_t col = 0; col < w; col++)
{
a = *bptr++;
b = *bptr++;
*tptr++ = (a <<8 | b);
}
TFT.pushImage(x0 + x, y0 + y, w, 1, (uint16_t*)lineBuffer);
y--;
}
bmpFS.close();
}
/*
void ajout_1_freq()
{
// AJOUT d'une fréquence en fin d'une liste de fréquences. Travaille directement sur la mémoire SPIFFS
File file = SPIFFS.open("/FRQ_FM.txt", FILE_APPEND);
file.print("<88800>"); // ok ; attention à ne pas oublier les < >
file.close(); // enregistre CE fichier en mémoire SPIFFS, sans toucher aux autres
delay(100);
}
*/
void test_clic_bouton_TEST()
{
test_clic_boutons(&bt_TEST );
bt_TEST.affiche(NOIR, ROUGE, 1);
delay(100);
if (bt_TEST.cliked)
{
Serial.println("-------------------------------");
Serial.println("bt_TEST.cliked");
bt_TEST.cliked = false;
bt_TEST.selected = true;
bt_TEST.affiche(NOIR, ROUGE, 1);
//TFT.fillscreen(GRIS_3); // effface
//affi_image_from_spiffs("/7.bmp");
//ajout_1_freq();
/*
uint16_t dx= 40;
uint16_t dy =30;
uint16_t memo_line_H[dx*dy];
TFT.readRect(20, 20 , dx, dy, memo_line_H);
TFT.pushRect(100, 100, dx, dy, memo_line_H);
*/
String s1;
for (int n=0; n<10; n++)
{
s1 = read_line_params(n);
Serial.println(s1);
}
bt_TEST.cliked = false;
bt_TEST.selected = false;
bt_TEST.affiche(NOIR, ROUGE, 1);
//init_affichages();
Serial.println("-------------------------------");
}
}
void test_clic_Bt_reset()
{
test_clic_boutons(&bt_reset );
bt_reset.affiche(GRIS_6, NOIR, 1);
delay(100);
if (bt_reset.cliked)
{
bt_reset.cliked = false;
bt_reset.selected = true;
bt_reset.affiche(GRIS_6, VERT, 1);
delay(100);
bt_reset.selected = false;
bt_reset.affiche(GRIS_6, VERT, 1);
setup();
}
}
void test_clic_bt_LEV()
{
test_clic_boutons(&bt_LEV);
if (bt_LEV.cliked)
{
bt_LEV.cliked = false;
bt_LEV.selected = true; bt_LEV.affiche(NOIR, VERT, 1);
bt_SNR.selected = false; bt_SNR.affiche(NOIR, VERT, 1);
mode_seuil = LEV;
}
}
void test_clic_bt_SNR()
{
test_clic_boutons(&bt_SNR);
if (bt_SNR.cliked)
{
bt_SNR.cliked = false;
bt_SNR.selected = true; bt_SNR.affiche(NOIR, VERT, 1);
bt_LEV.selected = false; bt_LEV.affiche(NOIR, VERT, 1);
mode_seuil = SNR;
}
}
void test_clic_bt_stop_scan()
{
test_clic_boutons(&bt_stop_scan);
if (bt_stop_scan.cliked)
{
Serial.println("STOP scan");
bt_stop_scan.affiche(NOIR, BLANC, 1);
mode_affi = NORMAL;
bt_stop_scan.cliked = false;
bt_stop_scan.affiche(NOIR, BLANC, 1);
}
}
void test_clic_bt_annuler() // sur la petite fenêtre surgissante d'info
{
test_clic_boutons(&bt_annuler);
if (bt_annuler.cliked)
{
bt_stop_scan.cliked = false;
bt_stop_scan.affiche(NOIR, BLANC, 1);
mode_affi = NORMAL; // ce qui repasse les boutons 'preset' en mode sélection et empêche l'écriture en SPIFFS
vu_metre_actif = true;
init_affichages();
}
}
/*
MODES DE SCAN
1-scan_frq() : tt fréquences d'une bande (ex: FM). Mise en mémoire temporaire (en RAM) des stations actives.
2-scan_mem_AIR() : cannaux occupés (pour la bande aviation) - pas de mise en mémoire mais stop si message reçu
puis reprise auto du scan à la fin du message.
*/
//enum MODE_SEUIL {LEV, SNR}; // level ou signal/bruit
//MODE_SEUIL mode_seuil = LEV;
void scan_mem_AIR()
{
Serial.println("scan_mem_AIR()");
bande_active = AIR;
efface_box_GROUPE();
uint16_t couleur_ciel = 10739;
TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, couleur_ciel);
affi_image_from_spiffs("/avion1.bmp", 1, 80);
affiche_box_scan(dy_box_SCAN);
TFT.setFreeFont(FF0);
TFT.setTextColor(JAUNE, NOIR);
//TFT.drawString("air", x0_box_SCAN +110 , y0_box_SCAN + 5); // titre
TFT.fillRect(2, 2, 42, 80, couleur_ciel); // efface
affi_image_from_spiffs("/avion3.bmp", 1, 15);
affi_image_from_spiffs("/PFD42x28.bmp", 1, 40);
String si;
uint16_t y;
uint16_t xi, yi;
int16_t dy;
int16_t attente =0;
int16_t signal_i;
uint16_t base = y0_box_SCAN + dy_box_SCAN -5; // bas du graphique
uint16_t memo_line_H[320];
//boolean memo_line_OK = false;
mode_seuil = SNR; //2 types de détection possibles: LEV(level) et SNR(signal-to-noise ratio = signal/bruit)
bt_SNR.selected = true; bt_SNR.affiche(NOIR, VERT, 1);
bt_LEV.selected = false; bt_LEV.affiche(NOIR, VERT, 1);
TFT.setFreeFont(FM9);
TFT.setTextColor(JAUNE, NOIR);
frequence = 124075;
Tune_Frequence(frequence);
affiche_frequence(frequence);
//TFT.drawFastHLine(5, base -seuil/10, 320, GRIS_6); // seuil (trait horizontal sur toute la largeur)
TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne
while(mode_affi == SCAN_M)
{
y = y0_box_SCAN + 5;
uint8_t module;
if(bande_active == FM) {module = 32;} else {module = 33;}
Get_Quality( module, &status, &level, &usn, &wam, &offset, &bandwidth, &mod, &snr );
si = String(level);
TFT.drawString("level", x0_box_SCAN +25 , y);
TFT.drawString(si+" ", x0_box_SCAN +65 , y);
y+=15;
si = String(snr);
TFT.drawString("snr", x0_box_SCAN +25 , y);
TFT.drawString(si+" ", x0_box_SCAN +65 , y);
y+=20;
if (mode_seuil == LEV) { signal_i = level; } // attention! level peut être négatif (échelle log)
if (mode_seuil == SNR) { signal_i= 16 * snr; }
dy = signal_i/10;
if(dy<0) {dy=0;}
dy+=2;
// petites barres verticales
xi = (frequence - 120000)/50;
// xi(120MHz) = 0 px;
// xi(136MHz) = (136000 - 120000) /50 = 320 px
TFT.drawFastVLine(xi, base-50, 50, couleur_ciel); // 95 efface
uint16_t c0 = BLEU;
if(signal_i > seuil*10){c0 = JAUNE;}
TFT.drawFastVLine(xi, base -dy, dy, c0);
if(signal_i > seuil*10)
{
TFT.fillRect(x0_box_SCAN +100, y0_box_SCAN + 20, 20, 20, VERT); // carré coloré
attente = 2;
}
else attente --;
if (attente <=0)
{
TFT.fillRect(x0_box_SCAN +100, y0_box_SCAN + 20, 20, 20, GRIS_5); // carré coloré
frequence = inc_Frq_in_groupe(&groupe_AIR, 1);
Tune_Frequence(frequence);
affiche_frequence(frequence);
TFT.setFreeFont(FF0);
TFT.setTextColor(BLANC, NOIR);
TFT.drawString("120MHz", x0_box_SCAN +5 , base-10);
TFT.drawString("136", x0_box_SCAN +dx_box_SCAN -22, base-10);
attente =0;
}
delay(50); // ne pas réduire, temps nécessaire pour accrocher la fréquence
if (ts.tirqTouched() && ts.touched())
{
TS_Point p = ts.getPoint();
x_touch = eTS.x0 + p.x /eTS.dx;
y_touch = eTS.y0 + p.y /eTS.dy;
test_clic_bt_stop_scan();
test_clic_boutons(&bt_seuil_plus);
if (bt_seuil_plus.cliked)
{
bt_seuil_plus.cliked = false;
TFT.pushRect(0, base - memo_seuil, 319, 1, memo_line_H); // efface avec l'image enregistrée
memo_seuil = seuil;
seuil += 1;
if (seuil > 120) {seuil = 120;}
TFT.readRect(0, base - seuil , 318, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(5, base -seuil, 318, GRIS_6); // seuil (trait horizontal sur toute la largeur)
TFT.setFreeFont(FF0); TFT.setTextColor(BLANC, NOIR);
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +185 , y0_box_SCAN +23);
}
test_clic_boutons(&bt_seuil_moins);
if (bt_seuil_moins.cliked)
{
bt_seuil_moins.cliked = false;
TFT.pushRect(0, base - memo_seuil, 319, 1, memo_line_H); // efface avec l'image enregistrée
memo_seuil = seuil;
seuil -= 1;
if (seuil < 5) {seuil = 5;}
TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(5, base -seuil, 319, GRIS_6); // seuil (trait horizontal sur toute la largeur)
TFT.setFreeFont(FF0); TFT.setTextColor(BLANC, NOIR);
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +185 , y0_box_SCAN +23);
}
test_clic_bt_LEV();
test_clic_bt_SNR();
test_clic_boutons(&bt_stop_scan);
}
}
//delay(1000);
mode_s = _MEM;
mode_affi = NORMAL;
bande_active = FM;
bt_mode_MEM.selected = true; bt_mode_MEM.affiche(GRIS_6, VERT, 2);
bt_mode_FRQ.selected = false; bt_mode_FRQ.affiche(GRIS_6, VERT, 2);
//boutons_preset_set_frequences();
init_affichages();
frequence = 89400;
Tune_Frequence(frequence);
affiche_frequence(frequence);
bt_FM.selected = true; bt_FM.affiche(GRIS_6, VERT, 1);
bt_AIR.selected = false; bt_AIR.affiche(GRIS_6, VERT, 1);
}
void scan_frq() // toutes les fréquences de la bande, incrémental, saut_freq = constant
{
Serial.println("scan_frq()");
if(bande_active == SCN) {bande_active = FM;}
String si;
String s1;
String sA, sB;
float xi=0;
uint32_t xi32;
uint16_t y;
int16_t dy;
uint16_t yi;
uint16_t memo_x_touch = 0;
uint16_t nb_F;
int16_t signal_i;
uint16_t base = y0_box_SCAN + dy_box_SCAN -5; // bas du graphique
uint16_t decal_x;
uint16_t decal_y;
int n_max;
TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, NOIR);
memo_frequence_scan = frequence; // variables globales
mode_seuil = SNR; //2 types de détection possibles: LEV(level) et SNR(signal-to-noise ratio = signal/bruit)
bt_SNR.selected = true; bt_SNR.affiche(NOIR, VERT, 1);
bt_LEV.selected = false; bt_LEV.affiche(NOIR, VERT, 1);
groupe_SCAN.RAZ();
efface_box_GROUPE();
TFT.setFreeFont(FM9);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF0);
uint8_t module;
if(bande_active == FM)
{
TFT.drawString("SCAN bande FM", x0_box_SCAN +50 , y0_box_SCAN + 10); // titre
frequence = 88000;
saut_freq = 100; // kHz
module = 32;
n_max = 190;
}
else
{
TFT.drawString("SCAN bande SW", x0_box_SCAN +50 , y0_box_SCAN + 10);
//frequence = 12000; // 12MHz...
saut_freq = 5; // kHz
module = 33;
n_max = 200;
}
y = y0_box_SCAN + 5;
decal_x=0;
decal_y=0;
nb_F=0;
TFT.drawFastHLine(5, base -seuil/10, 320, GRIS_6); // seuil (trait horizontal sur toute la largeur)
sA = String(frequence);
sB = String(frequence + n_max * saut_freq);
TFT.drawString(sA, x0_box_SCAN +5 , base-5);
TFT.drawString(sB, x0_box_SCAN +dx_box_SCAN -32, base-5);
boolean rescan = false;
do
{
groupe_SCAN.RAZ();
nb_F = 0;
affiche_box_scan(dy_box_SCAN);
uint32_t freq_min = frequence;
//......................................................................
int n = n_max;
while(n>0)
{
frequence += saut_freq;
affiche_frequence(frequence);
if( (frequence + saut_freq) <= 138000 )
{
Tune_Frequence(frequence);
delay(15);
}
if(bande_active == FM) {module = 32;} else {module = 33;}
Get_Quality( module, &status, &level, &usn, &wam, &offset, &bandwidth, &mod, &snr );
delay(50);
//if(bande_active == SW) {xi += 1.6;}
//if(bande_active == FM) {xi += 2;}
xi += 1.6;
if (mode_seuil == LEV) { signal_i = level; } // attention! level peut être négatif (échelle log)
if (mode_seuil == SNR) { signal_i= 16 * snr; }
dy = signal_i/10;
if(dy<0) {dy=0;}
dy+=2;
uint16_t c1 = VERT;
if(dy>30){c1 = JAUNE;}
if(dy>40){c1 = ORANGE;}
if(dy>50){c1 = BLEU_CLAIR;}
xi32 = x0_box_SCAN + (uint32_t)xi;
if (xi32 < 318) // limite d'affichage à droite pour ne pas abimer le cadre
{
//TFT.drawFastVLine(xi32, base-dy, dy, c1); // petites barres verticales
// on va les tracer point par point afin de pouvoir les coloriser
int a = base;
int b = a - dy;
for(int n=b; n<a; n++)
{
c1 = BLEU;
if(n>180){c1 = VERT;}
if(n>190){c1 = JAUNE;}
if(n>200){c1 = ORANGE;}
if(n>215){c1 = ROUGE;}
//c1 = 10 * n *n;
TFT.drawPixel(xi32, n, c1);
}
}
if(signal_i > seuil) // DETECTION
{
if (decal_y > 5) // concerne l'affichage des textes (fréquences trouvées)
{
decal_y = 0;
decal_x ++;
}
if((nb_F % 25) == 0) // limite le nb de freq affichées simultanément à 25
{
affiche_box_scan(dy_box_SCAN/2);
decal_x = 0;
decal_y = 0;
}
s1 = String(frequence);
TFT.setTextColor(BLANC, NOIR);
TFT.drawString(s1, x0_box_SCAN + 2 + 45*decal_x, y0_box_SCAN + 9*decal_y); // affiche FREQUENCE
nb_F++;
TFT.setFreeFont(FM9);
TFT.setTextColor(VERT, NOIR);
s1 = String(nb_F);
TFT.drawString(s1, x0_box_SCAN +215 , y0_box_SCAN + 6); // nb freq
TFT.setFreeFont(FF0);
groupe_SCAN.add_frq(frequence); // AJOUTE la fréquence trouvée au groupe spécial 'groupe_SCAN'
decal_y ++;
if(groupe_SCAN.nb_freq >= 100) // groupe plein (en RAM)
{
s1 = String(frequence);
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString(s1+" groupe SC plein", x0_box_SCAN +80 , y0_box_SCAN + 60);
TFT.setTextColor(BLANC, NOIR);
n=0;
}
}
n--;
if(seuil != memo_seuil)
{
TFT.drawFastHLine(5, base -memo_seuil/10, 310, NOIR); // efface
TFT.drawFastHLine(5, base -seuil/10, 310, GRIS_6); // seuil (trait horizontal sur toute la largeur)
TFT.setTextColor(JAUNE, NOIR);
si = "seuil:" + String(seuil); TFT.drawString(si+" ", x0_box_SCAN +185 , y0_box_SCAN +23);
}
delay(10); // ne pas réduire, temps nécessaire pour accrocher la fréquence
//delay(300); // pour balayage lent
if (ts.tirqTouched() && ts.touched()) // écran tactile
{
TS_Point p = ts.getPoint();
x_touch = eTS.x0 + p.x /eTS.dx;
y_touch = eTS.y0 + p.y /eTS.dy;
test_clic_boutons(&bt_seuil_plus);
if (bt_seuil_plus.cliked)
{
bt_seuil_plus.cliked = false;
memo_seuil = seuil;
seuil += 5;
}
test_clic_boutons(&bt_seuil_moins);
if (bt_seuil_moins.cliked)
{
bt_seuil_moins.cliked = false;
memo_seuil = seuil;
seuil -= 5;
si = String(seuil); TFT.drawString(si+" ", x0_box_SCAN +55 , y);
}
// modes de détection :
test_clic_bt_LEV(); // mode Level
test_clic_bt_SNR(); // mode Signal / bruit
test_clic_boutons(&bt_re_scan);
if (bt_re_scan.cliked)
{
bt_re_scan.cliked = false;
affiche_box_scan(dy_box_SCAN); // efface le tracé et re-dessine les boutons dans la boite
frequence = memo_frequence_scan; // on repart de ma même frequence
n = n_max;
xi =0; // départ tracé à gauche
decal_x=0; // textes fréquences trouvées
decal_y=0;
nb_F=0;
}
test_clic_boutons(&bt_stop_scan);
if (bt_stop_scan.cliked)
{
n=0; // force la sortie de la boucle while()
}
}
} // fin de la boucle while()
//.......................................................................
TFT.setTextColor(CYAN, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("On peut ecouter les freq", 10, 140);
TFT.drawString("en deplacant le stylet sur le spectre", 10, 150);
boolean stop = false;
while (! stop) // attend une action en fin de scan (par ex: clic sur bouton 'stop_scan' [x]) ou [re_scan]
{
if (ts.tirqTouched() && ts.touched())
{
TS_Point p = ts.getPoint();
x_touch = eTS.x0 + p.x /eTS.dx;
y_touch = eTS.y0 + p.y /eTS.dy;
if((x_touch != memo_x_touch) && (y_touch > 170)) // écoute de la fréquence pointée avec le stylet
{
TFT.drawFastVLine(memo_x_touch, base, 4, NOIR); // efface
TFT.drawFastVLine(x_touch, base, 4, BLANC);
TFT.drawFastVLine(memo_x_touch, base-50, 4, NOIR); // efface
TFT.drawFastVLine(x_touch, base-50, 4, BLANC);
memo_x_touch = x_touch ;
float dF = (x_touch - x0_box_SCAN) * saut_freq / 1.6;
uint32_t F1 = freq_min + uint32_t(dF);
frequence = F1;
affiche_frequence(frequence);
Tune_Frequence(frequence);
String sF1 = String(F1);
TFT.drawString(sF1, 200, 100);
}
test_clic_boutons(&bt_re_scan);
if (bt_re_scan.cliked)
{
bt_re_scan.cliked = false;
frequence = memo_frequence_scan; // on repart de ma même frequence
xi=0;
xi32 = x0_box_SCAN + (uint32_t)xi;
stop =true;
rescan = true; //pas d'appel RECURSIF de la fonction. Trop de pb !!
}
test_clic_boutons(&bt_scan_suivant);
if (bt_scan_suivant.cliked)
{
bt_re_scan.cliked = false;
affiche_box_scan(dy_box_SCAN); // efface le tracé et re-dessine les boutons dans la boite
n = n_max;
xi =0; // départ tracé à gauche
decal_x=0; // textes fréquences trouvées
decal_y=0;
nb_F=0;
memo_frequence_scan = frequence;
stop =true; // sortira de la boucle while()
rescan = true; // bouclera dans la boucle do()
}
test_clic_boutons(&bt_stop_scan);
if (bt_stop_scan.cliked)
{
stop =true; // sortira de la boucle while()
rescan = false; // ne rebouclera PAS dans la boucle do()
}
}
}
} while (rescan == true); // Fin de la boucle do()
Serial.println("-----------------------");
Serial.println("groupe_SCAN");
groupe_SCAN.bloc_to_serial(); // pour test avec moniteur série (CuteCom par exemple)
Serial.println("-----------------------");
Serial.println("STOP scan");
mode_affi = NORMAL;
mode_s = _MEM;
bt_mode_FRQ.selected = false; bt_mode_FRQ.affiche(GRIS_6, VERT, 2);
bt_mode_MEM.selected = true; bt_mode_MEM.affiche(GRIS_6, VERT, 2);
//bt_mode_MEM.cliked = true;
record_fichier_params();
uint16_t ya = 20;
uint8_t dya = 15;
TFT.fillScreen(NOIR);
TFT.setTextColor(VERT, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("Les Freq. detectees sont memo en RAM", 5, ya); ya += dya;
TFT.drawString("accessibles par le bouton [SC]", 5, ya); ya += dya;
TFT.drawString("et perdues si stop radio", 5, ya); ya += dya;
TFT.drawString("Mais on peut les enregistrer en SPIFFS", 5, ya); ya += dya;
TFT.drawString("une a une avec le bouton [Write]", 5, ya); ya += dya;
delay(300);
attente_clic();
init_affichages();
groupe_actif = gSCN;
bande_active = SCN;
bt_SCN.selected = true; bt_SCN.affiche(GRIS_5, CYAN, 1);
bt_SW.selected = false; bt_SW.affiche(GRIS_5, VERT, 1);
bt_FM.selected = false; bt_FM.affiche(GRIS_5, VERT, 1);
bt_AIR.selected = false;bt_AIR.affiche(GRIS_5, VERT, 1);
affiche_numero_frq(String(1), String(nb_F));
affiche_frequence(frequence);
}
void test_clic_Bt_scan_FRQ()
{
test_clic_boutons(&bt_scan_frq);
if (bt_scan_frq.cliked == true)
{
//bt_scan_frq.affiche(NOIR, VERT, 1);
bt_scan_frq.cliked = false;
bt_scan_frq.affiche(GRIS_5, BLANC, 1);
mode_affi = SCAN_F;
mode_s = _FRQ;
bt_mode_FRQ.selected = true; bt_mode_FRQ.affiche(GRIS_6, VERT, 2);
bt_mode_MEM.selected = false; bt_mode_MEM.affiche(GRIS_6, VERT, 2);
scan_frq();
bt_scan_frq.affiche(GRIS_5, BLANC, 1);
}
delay(100);
}
void test_clic_bt_scan_air()
{
test_clic_boutons(&bt_scan_air);
if (bt_scan_air.cliked == true)
{
//bt_scan_air.affiche(GRIS_5, BLANC, 1);
bt_scan_air.cliked = false;
bt_scan_air.affiche(GRIS_5, BLANC, 1);
mode_affi = SCAN_M;
bt_scan_air.selected = true;
bande_active == AIR;
scan_mem_AIR();
bt_scan_air.affiche(GRIS_5, BLANC, 1);
mode_s = _MEM;
}
delay(100);
}
void attente_clic()
{
delay(300);
init_1_bouton(300, 5, 20, 20, "X", &bt_close);
while ( !(ts.tirqTouched() && ts.touched()) ) {;}
TFT.fillScreen(NOIR);
init_affichages();
bt_SW.selected = false;
bt_FM.selected = true;
bande_active = FM;
modulation_active = WFM;
frequence = presetPad1.bt_preset[0].frequence_FM;
bt_SW.affiche(GRIS_5, VERT, 1);
bt_FM.affiche(GRIS_5, VERT, 1);
}
void SPIFFS_listFiles()
{
Serial.println("Listing fichiers (en memoire SPIFFS)");
uint16_t y=0;
String s1;
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("Listing fichiers (en memoire SPIFFS)", 0, y); y+=30;
File root = SPIFFS.open("/");
File file = root.openNextFile();
while (file)
{
Serial.print(" FILE: ");
s1 = String(file.name());
Serial.print(s1);
TFT.setTextColor(VERT, NOIR);
TFT.drawString(s1, 0, y);
s1 = "size:";
Serial.print(s1);
TFT.setTextColor(BLANC, NOIR);
TFT.drawString(s1, 100, y);
s1 = file.size();
Serial.println(s1);
TFT.setTextColor(JAUNE, NOIR);
TFT.drawString(s1, 140, y);
y+=10;
file = root.openNextFile();
}
attente_clic();
}
void SPIFFS_RAZ()
{
boolean valider = false; // <-- ecrire "= true" pour rendre l'effacement possible
// (évite tout effacement accidentel et donc perte de centaines de fréquences...)
if(valider == false)
{
TFT.fillScreen(NOIR);
TFT.setFreeFont(FM9);
TFT.drawString("FONCTION VOLONTAIREMENT", 50, 120);
TFT.drawString("INACTIVE", 50, 140);
TFT.drawString("VOIR LE CODE SOURCE", 50, 160);
TFT.drawString("void SPIFFS_RAZ()", 50, 180);
delay(3000);
init_affichages();
return;
}
SPIFFS.remove("/FRQ_SW.txt");
SPIFFS.remove("/FRQ_SW_PRST.txt");
SPIFFS.remove("/FRQ_FM.txt");
SPIFFS.remove("/FRQ_FM_PRST.txt");
SPIFFS.remove("/FRQ_AIR.txt");
SPIFFS.remove("/FRQ_AIR_PRST.txt");
Serial.println("fin RAZ SPIFFS");
}
void test_clic_bouton_SPIFFS_RAZ()
{
uint16_t c1 = NOIR;
uint16_t c2 = VERT;
test_clic_boutons(&bt_SPIFFS_RAZ );
if(bt_SPIFFS_RAZ.cliked)
{
bt_SPIFFS_RAZ.cliked = false;
bt_SPIFFS_RAZ.selected = false;
bt_SPIFFS_RAZ.affiche(ROUGE, c1, 1);
SPIFFS_RAZ();
}
}
void test_clic_bouton_SPIFFS_LST()
{
test_clic_boutons(&bt_SPIFFS_LST );
if(bt_SPIFFS_LST.cliked)
{
bt_SPIFFS_LST.cliked = false;
bt_SPIFFS_LST.selected = false;
bt_SPIFFS_LST.affiche(VERT, GRIS_5, 1);
SPIFFS_listFiles();
}
}
void test_clic_bouton_SPIFFS_write() // en SPIFFS, dans un des fichiers ("/FRQ_SW.txt" ...)
{
uint16_t c1 = GRIS_6;
uint16_t c2 = VERT;
String s1;
test_clic_boutons(&bt_SPIFFS_write );
if(bt_SPIFFS_write.cliked)
{
bt_SPIFFS_write.cliked=false;
bt_SPIFFS_write.selected=false;
bt_SPIFFS_write.affiche(VERT, GRIS_5, 1);
Serial.println("--------------------------------");
Serial.println("bouton_SPIFFS_write clic");
//attention à ne pas oublier ces < >
s1 = "<";
s1 += String(frequence); // // fréquence en cours
s1 += ">";
boolean ok = false;
if (bande_SW)
{
if (! groupe_SW.test_Frq_presente(frequence)) // test effectué sur le groupe en RAM
{
// AJOUTE la fréquence en fin d'une liste de fréquences. Travaille directement sur la mémoire SPIFFS
File file = SPIFFS.open("/FRQ_SW.txt", FILE_APPEND);
file.print(s1);
file.close(); // enregistre CE fichier en mémoire SPIFFS, sans toucher aux autres
delay(300);
ok = true;
}
}
if (bande_FM)
{
if (! groupe_FM.test_Frq_presente(frequence))
{
File file = SPIFFS.open("/FRQ_FM.txt", FILE_APPEND);
file.print(s1);
file.close();
delay(300);
ok = true;
}
}
if (bande_AIR)
{
if (! groupe_AIR.test_Frq_presente(frequence))
{
File file = SPIFFS.open("/FRQ_AIR.txt", FILE_APPEND);
file.print(s1);
file.close();
delay(300);
ok = true;
}
}
String s1, s2;
if (ok) {s1 = "Freq. save to SPIFFS"; s2 = ""; }
else {s1 = "Freq. deja presente"; s2 = "NOT SAVE";}
Serial.println(s1);
if (ok) {load_GRP_FREQ_SPIFFS();} // recharge les listes de fréquences depuis la SPIFFS pour être à jour
TFT.fillScreen(NOIR);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF1);
TFT.drawString(s1, 5, 40);
TFT.drawString(s2, 5, 60);
attente_clic();
}
}
void test_clic_bt_erase_1F() // en SPIFFS
{
uint16_t c1 = GRIS_6;
uint16_t c2 = VERT;
test_clic_boutons(&bt_erase_1F );
if(bt_erase_1F.cliked)
{
bt_erase_1F.cliked = false;
bt_erase_1F.selected = false;
bt_erase_1F.affiche(GRIS_3, c1, 1);
delay (300);
bt_erase_1F.cliked = false;
bt_erase_1F.selected = false;
bt_erase_1F.affiche(c1, c2, 1); // fugitif
uint16_t F;
//todo: en SPIFFS
}
}
void test_clic_boutons_MODE() // FREQ - MEM
{
uint16_t c1 = NOIR;
uint16_t c2 = VERT;
uint16_t c3 = JAUNE;
bt_mode_FRQ.cliked = false;
bt_mode_MEM.cliked = false;
test_clic_boutons(&bt_mode_FRQ );
if (bt_mode_FRQ.cliked) // les boutons sont exclusifs
{
mode_s = _FRQ;
affiche_index_frq();
bt_mode_FRQ.selected = true;
bt_mode_MEM.selected = false;
affiche_frequence(frequence);
efface_numero_frq();
}
test_clic_boutons(&bt_mode_MEM );
if (bt_mode_MEM.cliked)
{
efface_index_frq();
mode_s = _MEM;
bt_mode_MEM.selected = true;
bt_mode_FRQ.selected = false;
affiche_frequence(frequence);
}
bt_mode_FRQ.affiche(c1, c2, 2);
bt_mode_MEM.affiche(c1, c3, 2);
init_boutons_Plus_Moins(); //ce qui va changer le symbole affiché en '-' et '+' ou '<' et '>' en fonction du 'mode_s'
if (mode_affi == NORMAL)
{
bt_moins.affiche(GRIS_6, VERT ,1);
bt_plus.affiche(GRIS_6, VERT ,1);
}
}
void test_clic_boutons_BANDE() // SW, FM, AIR, SCAN
{
uint16_t c1 = GRIS_5;
uint16_t c2 = VERT;
bt_SW.cliked = false;
bt_FM.cliked = false;
bt_AIR.cliked = false;
test_clic_boutons(&bt_SW );
if (bt_SW.cliked)
{
TFT.fillRect(x0_box_info1+2, y0_box_info1+2, 120, 12, couleur_fond_ecran); // efface
Serial.println("bt_SW.cliked");
bt_SW.cliked = false;
groupe_actif = gSW;
bande_active = SW;
modulation_active = AM;
bt_SW.selected = true;
bt_FM.selected = false; // les boutons sont exclusifs
bt_AIR.selected = false;
bt_SCN.selected = false;
clic_logiciel_bouton(&presetPad1.bt_preset[0]);
traite_boutons_presetPad(0);
uint8_t nb_F = groupe_SW.nb_freq;
affiche_numero_frq(String(1), String(nb_F));
}
test_clic_boutons(&bt_FM );
if (bt_FM.cliked)
{
Serial.println("bt_FM.cliked");
bt_FM.cliked = false;
groupe_actif = gFM;
bande_active = FM;
modulation_active = WFM;
bt_FM.selected = true;
bt_SW.selected = false;
bt_AIR.selected = false;
bt_SCN.selected = false;
clic_logiciel_bouton(&presetPad1.bt_preset[0]);
traite_boutons_presetPad(0);
uint8_t nb_F = groupe_FM.nb_freq;
affiche_numero_frq(String(1), String(nb_F));
}
test_clic_boutons(&bt_AIR );
if (bt_AIR.cliked)
{
TFT.fillRect(x0_box_info1+2, y0_box_info1+2, 120, 12, couleur_fond_ecran); // efface
Serial.println("bt_AIR.cliked");
bt_AIR.cliked = false;
groupe_actif = gAIR;
bande_active = AIR;
modulation_active = AM;
bt_AIR.selected = true;
bt_SW.selected = false;
bt_FM.selected = false;
bt_SCN.selected = false;
clic_logiciel_bouton(&presetPad1.bt_preset[0]);
traite_boutons_presetPad(0);
uint8_t nb_F = groupe_AIR.nb_freq;
affiche_numero_frq(String(1), String(nb_F));
}
test_clic_boutons(&bt_SCN );
if (bt_SCN.cliked == true)
{
Serial.println("bt_SCN.cliked");
bt_SCN.cliked = false;
groupe_actif = gSCN;
bande_active = SCN;
bt_SCN.selected = true; bt_SCN.affiche(c1, CYAN, 1);
bt_SW.selected = false; bt_SW.affiche(c1, c2, 1);
bt_FM.selected = false; bt_FM.affiche(c1, c2, 1);
bt_AIR.selected = false;bt_AIR.affiche(c1, c2, 1);
uint8_t nb_F = groupe_SCAN.nb_freq;
affiche_numero_frq(String(1), String(nb_F));
}
Serial.print("groupe actif = "); Serial.println(groupe_actif);
}
void test_clic_bouton_set() // bouton pour passer dans le mode d'écriture de la F en cours en SPIFFS
// L'écriture en question sera effectuée par la fonction 'traite_boutons_presetPad()'
{
test_clic_boutons(&bt_set);
if (bt_set.cliked)
{
bt_set.cliked = false;
vu_metre_actif = false;
TFT.fillRect(x0_box_info2, y0_box_info2, 140, 70, NOIR);
TFT.setTextColor(VERT, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("Cliquez sur un des 8 bt", x0_box_info2+2, y0_box_info2+2);
TFT.drawString("'preset' pour lui ", x0_box_info2+2, y0_box_info2+12);
TFT.drawString("attribuer la F en cours", x0_box_info2+2, y0_box_info2+22);
init_1_bouton(x0_box_info2+82, y0_box_info2+50, 50, 15, "annuler", &bt_annuler);
bt_annuler.affiche(NOIR, BLANC, 1);
mode_affi = SET_F_PRESET; // ce qui modifie le comportement de la fonction 'traite_boutons_presetPad()'
Serial.println("mode_affi == SET_F_PRESET");
delay (100);
bt_set.selected = false;
bt_set.affiche(NOIR, BLANC, 1);
}
}
void affiche_signal(uint16_t x, uint16_t y, uint16_t dx, int16_t valeur)
{
TFT.fillRect(x, y, dx, 8, NOIR); // efface
if(valeur<0) {valeur =0;}
if(valeur > dx) {valeur = dx;}
TFT.drawRect(x, y, dx, 5, couleur_traits);
TFT.fillRect(x, y, valeur, 5, JAUNE);
}
void affiche_tension_batt(uint16_t x, uint16_t y, uint16_t dx, int8_t valeur) // valeur en %
{
uint16_t c1;
c1 = ROUGE;
if(valeur>30){c1 = ORANGE;}
if(valeur>50){c1 = JAUNE;}
if(valeur>70){c1 = VERT;}
uint32_t v2 = valeur * dx / 100;
TFT.fillRect(x-20, y, dx, 8, NOIR); // efface
efface_box_entete3();
if(v2<0) {valeur =0;}
if(v2 > dx) {v2 = dx;}
TFT.drawRect(x, y, dx, 5, couleur_traits);
TFT.fillRect(x, y, v2, 5, c1);
String s1 = String(valeur) +"%";
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString(s1, x-20, y);
TFT.drawString("bat", x + 10 , y+5);
}
void affiche_1_bargraph(uint16_t x, uint16_t y, uint16_t dx, int16_t valeur, uint16_t couleur)
{
TFT.fillRect(x, y, dx+40, 8, NOIR); // efface
TFT.drawString(String(valeur), x, y);
if(valeur<0) {valeur =0;}
if(valeur > dx) {valeur = dx;}
TFT.drawRect(x+40, y, dx, 5, couleur_traits);
TFT.drawRect(x+40, y, valeur, 5, couleur);
}
void affiche_bars_graph()
{
affiche_1_bargraph(170, 150, 100, level/10, VERT);
affiche_1_bargraph(170, 160, 100, usn, JAUNE);
affiche_1_bargraph(170, 170, 100, wam, BLEU_CLAIR);
affiche_1_bargraph(170, 180, 100, offset, BLANC);
}
String int_to_hex(uint16_t nb)
{
char symb[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
uint8_t A = (nb & 0b1111000000000000) >>12;
uint8_t B = (nb & 0b0000111100000000) >>8;
uint8_t C = (nb & 0b0000000011110000) >>4;
uint8_t D = (nb & 0b0000000000001111);
String s1 = String(symb[A]) + String(symb[B]) + String(symb[C]) + String(symb[D]) ;
return s1;
}
void traite_signal_RDS()
{
Get_RDS_Data ( &status, &A_block, &B_block, &C_block, &D_block, &dec_error);
/*
A_Block always contains the 16-bit program identifier.
The first 11 bits (bits 15–5) of block 2 are also the same in all groups.
La Liste des codes RDS autorisés se trouve ici : https://www.csa.fr/maradiofm/radiords_tableau
pour les autres blocks, voir :
https://en.wikipedia.org/wiki/Radio_Data_System
(c'est sans doute logique mais terriblement indigeste !!!)
*/
TFT.fillRect(x0_box_info1+2, y0_box_info1+2, 120, 12, couleur_fond_ecran); // efface
String s1 = int_to_hex(A_block);
String s2, s3;
TFT.setTextColor(JAUNE, GRIS_6);
TFT.setFreeFont(FF0);
for(int n = 0; n<=nb_stations_RDS-1; n++)
{
s2 = codesRDS[n];
s3 = s2.substring(0, 4);
if (s3 == s1)
{
TFT.drawString(s2, x0_box_info1+5, y0_box_info1 +4);
return; // on ne continue pas à boucler si trouvé
}
else if (n == nb_stations_RDS-1) // pas trouvé...
{
TFT.drawString(s1, x0_box_info1+5, y0_box_info1 +4);
return;
}
}
}
void affiche_force_signal()
{
//----------------------------------------------------------------------------------------------------------
// AFFICHE FORCE SIGNAL HF
compteur1 =0;
uint8_t module;
if(bande_active == FM) {module = 32;} else {module = 33;}
Get_Quality( module, &status, &level, &usn, &wam, &offset, &bandwidth, &mod, &snr );
//float signal_sur_bruit = level;// - 1.5 * usn; // marche à peu près bien pour la FM.
float diff = level - position_aiguille;
if(diff > 30.0) {diff = 30.0;}
if(diff < -30.0) {diff = -30.0;} // évite une trop grande réaction au sortir du mode 'mute'
// supprime les tremblements de l'aiguille
position_aiguille += diff / 6.0;
//affiche_bars_graph();
affiche_signal(170, 90, 60, mod/2);
if ((mode_affi == NORMAL) && (! mute) ) { plotAiguille(position_aiguille/6.0); }
if ((mode_affi == NORMAL) && (mute) ) { plotAiguille(0); }
}
int16_t etalon_TS[2] = {-30, 11 };
void loop()
{
if((mode_affi != SCAN_F) && (mode_affi != SCAN_M))// invalide les boutons situés derrière le panneau scan en modes SCAN
{
if (ts.tirqTouched() && ts.touched())
{
TS_Point p = ts.getPoint();
x_touch = eTS.x0 + p.x /eTS.dx;
y_touch = eTS.y0 + p.y /eTS.dy;
test_clic_6_boutons_frq(); // 6 rectangles situés au dessus des gros chiffres de la fréquence
test_clic_bouton_mute();
test_clic_bouton_SPIFFS_RAZ();
test_clic_bouton_SPIFFS_write();
test_clic_bouton_SPIFFS_LST();
test_clic_bt_erase_1F();
uint8_t n_touch1 = numPad1.test_clic(); // pavé numérique
if (n_touch1 != 253) { traite_touches_pad(n_touch1); } // pavé numérique
test_clic_boutons_plus_moins(); // boutons '<' et '>'
test_clic_bouton_Sleep();
test_clic_bouton_TEST();
test_clic_bouton_info();
test_clic_Bt_reset();
test_clic_Bt_scan_FRQ();
test_clic_bt_scan_air(); // Scan mémoires
test_clic_boutons_MODE(); // FREQ / MEM (tout en haut à gauche des gros chiffres)
test_clic_boutons_BANDE(); // SW, FM, AIR, SC; (SC = SCAN)
uint8_t num_bouton = presetPad1.test_clic(); // 8 petits boutons carrés de présélection de 8 fréquences
if (num_bouton != 253) { traite_boutons_presetPad(num_bouton); }
test_clic_bouton_set(); // attribution de la fréquence en cours à un des 8 boutons preset.
test_clic_bt_annuler();
test_clic_bt_affi_saisie_couleur();
test_clic_bt_RST_affi();
}
// la limitation SW max = 28MHz est due au module TEF6686 lui-même
if (frequence >= 138000) {frequence = 138000;} //138 MHz limite à cause SW max = 28MHz et conv AirBand = 110 MHz
if (frequence < 1500) {frequence = 1500;} // 1.5 MHz
if (compteur1 >= 5)
{
affiche_force_signal();
//----------------------------------------------------------------------------------------------------------
// AFFICHE TENSION BATTERIE
//----------------------------------------------------------------------------------------------------------
// voir la feuille de calcul 'Mesure de la tension de la batterie.ods' établie sur tests avec alim numérique
// voir aussi, sur le schéma, la valeur des résistances (diviseur analogique) sur l'entrée GPIO35 (analogPin = 35)
// Note: la valeur de la tension sur le pin GPIO35 ne doit jamais dépasser 3v3 (ce qui est lu = 4096)
int valeurLue = analogRead(analogPin);
//Serial.print("valeurLue = "); Serial.println(valeurLue);
float pourcent = ((float)valeurLue - 2570.0) / 7.5;
if (pourcent > 100.0) {pourcent = 100.0;}
if (pourcent < 0.0) {pourcent = 0.0;}
//Serial.print("pourcent = "); Serial.println(pourcent);
// intégration
float diff2 = pourcent - valeur_affi;
if(diff2 > 10.0) {diff2 = 10.0;}
if(diff2 < -10.0) {diff2 = -10.0;} // évite une trop grande réaction au sortir du mode 'mute'
valeur_affi += diff2 / 10.0;
if ( abs(valeur_affi - memo_valeur_affi) > 1.5 ) // pour éviter trop d'affichages inutiles (et clignotements à l'écran)
{
affiche_tension_batt(270, 4, 46, (int8_t) valeur_affi);
memo_valeur_affi = valeur_affi;
}
}
if (compteur2 >= 100)
{
compteur2 =0;
if(bande_active == FM) {traite_signal_RDS();}
}
delay(10);
compteur1++;
compteur2++;
}
}
/** ***************************************************************************************
CLASS TOUCH_BOUTON // affiche un nombre ou un petit texte dans un rectangle
ainsi que (en plus petit) deux valeurs supplémentaires, par ex: les valeurs mini et maxi
********************************************************************************************/
// Constructeur
TOUCH_BOUTON::TOUCH_BOUTON()
{
}
// Constructeur
TOUCH_BOUTON_PRESET::TOUCH_BOUTON_PRESET()
{
}
void TOUCH_BOUTON::init(uint16_t xi, uint16_t yi, uint8_t dxi, uint8_t dyi, uint8_t dri)
{
x0 = xi;
y0 = yi;
dx = dxi;
dy = dyi;
dr = dri;
cliked = false;
selected = false;
}
void TOUCH_BOUTON::affiche(uint16_t coul_fill_unselect, uint16_t coul_fill_select, uint8_t n_font)
{
uint16_t couleur_contour = GRIS_5;
uint16_t couleur_texte = BLANC;
if(selected)
{
TFT.fillRoundRect(x0, y0, dx, dy, dr, coul_fill_select);
TFT.setTextColor(NOIR);
}
else
{
TFT.fillRoundRect(x0, y0, dx, dy, dr, coul_fill_unselect); // efface
TFT.drawRoundRect(x0, y0, dx, dy, dr, couleur_contour); // retrace juste le contour
TFT.setTextColor(couleur_texte);
}
//FM9 FMB9 FSS9... voir le fichier FrSPIFFS_Fonts.h
if (n_font == 1) { TFT.setFreeFont(FF0);}
if (n_font == 2) { TFT.setFreeFont(FM9);}
if (n_font == 3) { TFT.setFreeFont(FMB9);}
if (n_font == 4) { TFT.setFreeFont(FSS9);}
TFT.drawString(s, x0+3, y0 + 2);
}
uint8_t TOUCH_BOUTON::read_dx()
{
return dx;
}
uint8_t TOUCH_BOUTON::read_dy()
{
return dy;
}
/** ***************************************************************************************
CLASS NUMPAD
********************************************************************************************/
// Constructeur
NUM_PAD::NUM_PAD()
{
}
void NUM_PAD::init(uint16_t xi, uint16_t yi, boolean fond) // si fond =false, ne resessine que les boutons
{
x0 = xi;
y0 = yi;
uint16_t x, y;
uint8_t dxt = 25; // taille x d'une touche
uint8_t dyt = 23; // taille y d'une touche
if(fond == true) {TFT.fillRect(x0, y0, 3*dxt +6, 4*dyt +7, NOIR);}
if(fond == true) {TFT.fillRect(x0, y0, 3*dxt +6, 4*dyt +7, NOIR);}
uint16_t c1 = GRIS_5;
uint16_t c2 = JAUNE;
x = x0+2;
y = y0+2;
for(uint8_t n =1; n<10; n++)
{
bt_pad[n].init(x, y, dxt, dyt, 3);
bt_pad[n].s=String(n);
bt_pad[n].affiche(c1, c2, 2);
x += dxt+1;
if (x > (x0 + 3*dxt)) {x = x0+2; y += dyt+1; }
}
bt_pad[0].init(x, y, dxt, dyt, 3); bt_pad[0].s="0"; bt_pad[0].affiche(c1, c2, 2); x += dxt+1;
bt_point.init(x, y, dxt, dyt, 3); bt_point.s="."; bt_point.affiche(c1, c2, 2);
x += dxt+1;
bt_ok.init(x, y, dxt, dyt, 3); bt_ok.s="ok";
bt_ok.affiche(c1, c2, 1);
}
uint8_t NUM_PAD::test_clic()
{
// zone des boutons du clavier
if ( (( x_touch > x0) && (x_touch < x0 + 100)) && (( y_touch > y0) && (y_touch < y0 + 130)))
{
uint8_t num_touche =0;
for(uint8_t n = 0; n<10; n++)
{
test_clic_boutons(&bt_pad[n] ); if(bt_pad[n].cliked) {num_touche=n; n_appui ++;}
}
test_clic_boutons(&bt_point ); if(bt_point.cliked) {num_touche=254; } // bouton "."
test_clic_boutons(&bt_ok ); if(bt_ok.cliked) {num_touche=255; n_appui ++;} // bouton "ok"
delay(100);
init(x0, y0, false); // 'false' évite le clignotement lorsqu'on repeint le fond noir
return num_touche;
}
return 253;
}
/** ***************************************************************************************
CLASS PRESET_PAD
********************************************************************************************/
// Constructeur
PRESET_PAD::PRESET_PAD()
{
}
void PRESET_PAD::init(uint16_t xi, uint16_t yi)
{
x0 = xi;
y0 = yi;
uint16_t c1 = GRIS_5;
uint16_t c2 = JAUNE;
uint16_t x2, y2;
x2 = x0;
y2= y0;
for(uint8_t n=0; n<8; n++)
{
bt_preset[n].init(x2, y2, 15, 15, 3);
bt_preset[n].s=String(n+1);
if(mode_affi == COUL) {c1 = bt_preset[n].couleur;}
bt_preset[n].affiche(c1, c2, 1);
x2 += 20;
}
}
uint8_t PRESET_PAD::read_dx()
{
return dx;
}
uint8_t PRESET_PAD::read_dy()
{
return dy;
}
void PRESET_PAD::set_frequences_PRST() // lit les fréquences en SPIFFS et les attribue à chaque bouton PRESET
{
Serial.println("void PRESET_PAD::set_frequences()");
uint8_t n=0;
read_FRQ_File(SPIFFS, "/FRQ_SW_PRST.txt", "SW");
read_FRQ_File(SPIFFS, "/FRQ_FM_PRST.txt", "FM");
read_FRQ_File(SPIFFS, "/FRQ_AIR_PRST.txt", "AIR");
}
void PRESET_PAD::set_couleurs()
{
// voir la page: https://rgbcolorpicker.com/565
// qui permet de reconfigurer les couleurs RGB565 (5+6+5 = 16 bits) très simplement
bt_preset[0].couleur = 10240; // rouge sombre
bt_preset[1].couleur = 14528; // orange
bt_preset[2].couleur = 320; // vert
bt_preset[3].couleur = 14407; // violet
bt_preset[4].couleur = 26787; // rose
bt_preset[5].couleur = 260; // cyan
bt_preset[6].couleur = 267; // bleu ciel
bt_preset[7].couleur = 4; // bleu marine
}
void PRESET_PAD::deselect_boutons()
{
uint16_t c1 = GRIS_5;
uint16_t c2 = JAUNE;
for(int n =0; n<8; n++)
{
bt_preset[n].selected=false;
bt_preset[n].cliked=false;
bt_preset[n].affiche(c1, c2, 1);
}
}
uint8_t PRESET_PAD::test_clic()
{
if ( (( x_touch > x0) && (x_touch < (x0+155))) && (( y_touch > y0) && (y_touch < (y0+15))))
{
uint8_t num_bouton =0;
for(uint8_t n=0; n<8; n++)
{
test_clic_boutons(&bt_preset[n]);
if(bt_preset[n].cliked)
{
deselect_boutons(); // les autres
bt_preset[n].selected =true; // pour l'affichage de celui-ci
bt_preset[n].affiche(GRIS_5, VERT, 1);
num_bouton = n;
Serial.print("BB num_bouton= "); Serial.println(num_bouton);
}
}
return num_bouton;
}
return 253;
}
/** ***************************************************************************************
CLASS GROUPE_FREQUENCES // objet image d'un bloc mémoire en SPIFFS
permet diverses manipulations en RAM (tri...) sans toucher à la SPIFFS (évite usure mémoire flash)
********************************************************************************************/
// Constructeur
GROUPE_FREQUENCES::GROUPE_FREQUENCES()
{
}
void GROUPE_FREQUENCES::RAZ() // en RAM uniquement
{
for(int n=0; n<100; n++)
{
G_freq[n]=0;
}
nb_freq = 0;
}
void GROUPE_FREQUENCES::load_bloc() // depuis la mémoire SPIFFS -> vers groupe en RAM
{
Serial.println("--------------------------");
Serial.println("GROUPE_FREQUENCES::load_bloc()");
Serial.print("Reading file: "); Serial.println(filename);
File file = SPIFFS.open(filename);
if (!file ) { Serial.println("failed to open file for reading"); return; }
String s;
uint8_t n =0;
while (file.available())
{
char c;
c = char(file.read());
if ((c !='<') && (c !='>')) {s += c;}
if(c=='>')
{
uint32_t frq;
frq = s.toInt();
Serial.println(frq);
s="";
G_freq[n] = frq;
n++;
}
}
file.close();
Serial.print(n); Serial.println(" frequences");
}
boolean GROUPE_FREQUENCES::test_Frq_presente(uint32_t F_i) // travaille en RAM
{
Serial.println("--------------------------");
Serial.println("test_Frq_presente()");
uint16_t n =0;
uint16_t adresse_lue;
uint32_t valeur_lue;
boolean ok = false;
for (n=0; n<100; n++)
{
valeur_lue = G_freq[n];
if (valeur_lue == F_i) {return true;} // si F est présente
}
return false; // si F non présente
}
void GROUPE_FREQUENCES::tri_bloc()
{
Serial.println("--------------------------");
Serial.println("tri_block()");
// tri par bulles
uint32_t F1=0, F2=0;
uint32_t Fi;
uint16_t i_max = 100;
uint16_t p_max = 100;
for(uint16_t p=0; p<p_max; p++)
{
//for(int n=0; n<i_max-1; n++)
uint16_t n =0;
while(n<i_max-1)
{
F1=G_freq[n];
F2=G_freq[n+1];
if(F1 > F2)
{
Fi = G_freq[n];
G_freq[n] = G_freq[n+1];
G_freq[n+1] = Fi;
}
n++;
}
}
// ici les freq sont dédoublées !!!!!!!!!!!!
// compte le nombre de fréquences != 0
uint16_t nombre =0;
for(uint16_t n = 0; n<100; n++ )
{
F1 = G_freq[n];
if(F1 != 0) { nombre++;}
}
nb_freq = nombre;
// recherche première fréquence non nulle
uint16_t n2=0;
F1 =0;
while ((F1==0) && (n2<100))
{
F1=G_freq[n2];
n2++;
}
adr_1ere_frq = n2-1; // 1ere F non nulle
}
void GROUPE_FREQUENCES::bloc_to_serial()
// pour tests, avec CuteCom sous Linux
// travaille en RAM uniquement, sans toucher aux fichiers SPIFFS
{
Serial.println("--------------------------");
Serial.println("bloc_to_serial()");
uint32_t valeur_lue;
uint16_t nombre =0;
for(uint16_t n = 0; n<100; n++ )
{
valeur_lue = G_freq[n];
if(valeur_lue != 0) // n'affiche pas les emplacements vides
{
nombre++;
Serial.println(valeur_lue);
}
}
Serial.print(nombre); Serial.println(" frequences");
//Serial.print("1ere Frq= "); Serial.println(G_freq[adr_1ere_frq]);
}
void GROUPE_FREQUENCES::add_frq(uint32_t Fi) // en RAM uniquement
{
Serial.println("--------------------------");
if (nb_freq >= 100) {return;}
Serial.println("GROUPE_FREQUENCES::add_frq()");
if (test_Frq_presente(Fi) == true)
{
Serial.println("Frq presente, pas d'ajout");
return;
}
tri_bloc(); // les F nulles se retrouvent en haut
Serial.print("Ajout frequence: "); Serial.println(Fi);
G_freq[0] = Fi; // la nouvelle fréquence est placée en haut
nb_freq++;
tri_bloc(); // la nouvelle fréquence se retrouve rangée dans l'ordre de F croissantes
}
void GROUPE_FREQUENCES::erase_1_freq(uint32_t Fi) // en RAM
{
Serial.println("--------------------------");
Serial.println("GROUPE_FREQUENCES::erase_1_freq()");
uint32_t valeur_lue;
for(int n=0; n<100; n++)
{
valeur_lue = G_freq[n];
if(valeur_lue == Fi)
{
G_freq[n]=0;
}
}
tri_bloc();
}