/* ************************************************************************************
Radio TEF6686 par Silicium628
pour ma carte (fab : JLCPCB) ESP32 Wroom + afficheur 2.8" TFT 240x320 + SDcard
Cette version utilise la SDcard
************************************************************************************ */
// 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) Le fichier User_Setup dans le dossier 'lib/TFT_eSPI' est spécifique à cette configuration
// pour ce qui concerne les connexions mais aussi les limitations de fréquence du bus SPI
#include <Arduino.h>
#include "main.h"
//#include "Tuner_Patch_Lithio_V102_p224.h" // voir la fonction 'Tuner_Patch()' dans la fonction 'setup()'
String version = "1.11.0"; // (avec enregistrement sur SD card)
#include "FS.h"
#include "SD.h"
#include "Wire.h"
#include <stdint.h>
#include <Free_Fonts.h>
#include "TFT_eSPI.h" // Hardware-specific library
#include "SPI.h"
#include "Digit_Font.h"
#include <XPT2046_Touchscreen.h>
#include "constantes_628.h"
#include "Couleurs_AEC.h"
#include "DSP_INIT_628.h"
#include "driverTEF6686_628.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 //T_DI 32
#define XPT2046_MISO 39 //T_DO 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 = 21;
const int GPIO_SCL = 22;
const int analogPin = 35;
const int GPIO_BL = 4; // pour LED backlight ILI9341
const int _DX = 320;
const int _DY = 240;
#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);
SPIClass mySpi2 = SPIClass(HSPI);
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);
struct ETALON_TS // etalon touch screen
{
int16_t x0;
int16_t dx;
int16_t y0;
int16_t dy;
};
ETALON_TS eTS;
struct POINT
{
uint16_t x;
uint16_t y;
};
// coordonnées des points de calibrage de l'écran tactile
// (calibration ? étalonnage ?? ajustage ??? boaf, m'enfin !!)
POINT A, B;
uint16_t x_touch, y_touch;
uint16_t memo_x_touch, memo_y_touch;
uint16_t memo_tiret_H[20];
uint16_t memo_tiret_V[20];
uint16_t valeur_bargraph=0;
uint8_t SDcardOk=0;
uint16_t color565px;
boolean stop = false;
float raddeg = M_PI/180.0;
float deg_to_rad = 2.0 * M_PI /360.0;
boolean test_touch_screen = false; // mettre true pour activer le test
uint16_t compteur1 = 0;
uint16_t compteur2 = 0;
uint16_t compteur3 = 0;
uint8_t num_capture = 0;
uint32_t frequence=10000;
uint32_t saut_freq;
uint16_t seuil = 50;
uint16_t memo_seuil = 50;
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_freq;
uint16_t frq_preset_adr_0;
String frequence_txt = "";
TOUCH_BOUTON bt_info;
TOUCH_BOUTON bt_capture; // capture écran
TOUCH_BOUTON bt_sleep;
TOUCH_BOUTON bt_quiet; // calme (anti-parasites)
TOUCH_BOUTON bt_TEST;
TOUCH_BOUTON bt_mode_FRQ, bt_mode_MEM;
TOUCH_BOUTON bt_plus, bt_moins;
TOUCH_BOUTON bt_SD_write, bt_erase_1F, bt_LST; //, bt_SD_LST, bt_SD_RAZ;
TOUCH_BOUTON bt_1, bt_2, bt_3, bt_4, bt_5, bt_6; // 6 boutons au dessus des chiffres de la fréquence
TOUCH_BOUTON bt_coul;
TOUCH_BOUTON bt_coul_to_SD;
TOUCH_BOUTON Bt_SCAN, bt_scan_air;
TOUCH_BOUTON bt_scan_SW, bt_scan_FM;
TOUCH_BOUTON bt_RST_affi; // "ok"
TOUCH_BOUTON bt_LEV, bt_SNR, bt_re_scan, bt_scan_suivant;
TOUCH_BOUTON bt_seuil_plus, bt_seuil_moins;
// ---------- gridPad ------------
GRID_PAD gridPad1;
// ---------- numPad ------------
NUM_PAD numPad1;
// ---------- presetPad1 ------------
PRESET_PAD presetPad1;
// ---------- swPad1 ------------
SW_PAD swPad1;
// -------------------------------
TOUCH_BOUTON bt_SW, bt_FM, bt_AIR, bt_SCN;
TOUCH_BOUTON bt_LED;
TOUCH_BOUTON bt_mute;
TOUCH_BOUTON bt_reset;
TOUCH_BOUTON bt_cal;
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"
//les variables globales sont le Mal, et il faut éviter à tous prix de s'en servir, m'enfin!
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;
boolean quiet = false;
uint16_t FRQ_x0;
uint16_t FRQ_y0;
uint16_t x0_box_SD;
uint16_t y0_box_SD;
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; // en bas à gauche
uint16_t y0_box_info1;
uint16_t x0_box_info2; // à la place du vu-metre
uint16_t y0_box_info2;
uint16_t dx_box_info2;
uint16_t dy_box_info2;
uint16_t x0_gridPad;
uint16_t y0_gridPad;
uint16_t dx_gridPad;
uint16_t dy_gridPad;
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 = VERT_FONCE;
String s_recue;
String memo_s_recue="";
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_SD = 2; y0_box_SD = 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 = 140;
x0_box_info1 = 2; 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_gridPad = x0_vu_metre;
y0_gridPad = y0_vu_metre;
dx_gridPad = 140; dy_gridPad = 70;
x0_saisie = 2; y0_saisie = 2;
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;
valeur_bargraph=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) );
}
}
}
// Fonction optimisée pour l'afficheur ILI9341 320x240 avec la library 'TFT_eSPI'
// ne convient PAS pour les ESP32 Wroom + afficheur 3.5" TFT 480x320
void write_TFT_on_SDcard() // enregistre image bmp 320x240 RGB565 (5+6+5 = 16bits/px)
{
Serial.println("write_TFT_on_SDcard()");
if (SDcardOk==0) {return;}
int32_t x, y;
uint16_t color565;
uint8_t lineBuffer8[(320*2)];
uint16_t lineBuffer16[320];
uint8_t octet_A, octet_B;
String s1;
s1 +="/bmp565/capture";
s1 += String(num_capture);
s1 += ".bmp" ;
File file1 = SD.open(s1, FILE_WRITE); // crée le fichier si pas présent
if (file1)
{
// création entête bmp565 - 138 octets; voir bmp565_header[] dans le fichier main.h
for(uint8_t i=0; i<138; i++) { file1.write(bmp565_header[i]); }
for (int16_t y=239; y>=0; y--)
{
TFT.readRect(0, y, 320, 1, lineBuffer16); // lit une ligne
TFT.drawString("A", 200, 200); // pour terminer par une écriture
uint16_t i=0;
for (int16_t x=0; x<320; x++) //320
{
color565px = lineBuffer16[x]; // BBBBBrrr rrrVVVVV
octet_A = (color565px & 0b1111111100000000) >> 8;
octet_B = (color565px & 0b0000000011111111);
lineBuffer8[i] = octet_A;
lineBuffer8[i+1] = octet_B;
i+=2;
}
file1.write(lineBuffer8, sizeof(lineBuffer8));
}
num_capture ++;
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF1);
TFT.drawString("Capture ok", 20, 100);
delay(1000);
init_affichages();
}
}
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, GRIS_5); bt_1.affiche(c2, 1); x+=31;
bt_2.init(x, y, 20, 5, 0, GRIS_5); bt_2.affiche(c2, 1); x+=31;
bt_3.init(x, y, 20, 5, 0, GRIS_5); bt_3.affiche(c2, 1); x+=46;
bt_4.init(x, y, 20, 5, 0, GRIS_5); bt_4.affiche(c2, 1); x+=31;
bt_5.init(x, y, 20, 5, 0, GRIS_5); bt_5.affiche(c2, 1); x+=31;
bt_6.init(x, y, 20, 5, 0, GRIS_5); bt_6.affiche(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, 3, GRIS_5);
bt_moins.cliked = false;
bt_moins.label= s1;
bt_plus.init(x0+35, y0, 30, 15, 3, GRIS_5);
bt_plus.cliked = false;
bt_plus.label= 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, GRIS_5);
bt_SW.cliked = false;
bt_SW.selected = false;
bt_SW.label="SW";
x+=25;
bt_FM.init(x, y, 20, 15, 3, GRIS_5);
bt_FM.cliked = false;
bt_FM.selected = false;
bt_FM.label="FM";
x+=25;
bt_AIR.init(x, y, 22, 15, 3, GRIS_5);
bt_AIR.cliked = false;
bt_AIR.selected = false;
bt_AIR.label="AIR";
x+=27;
bt_SCN.init(x, y, 20, 15, 3, GRIS_5);
bt_SCN.cliked = false;
bt_SCN.selected = false;
bt_SCN.label="SC";
}
void init_1_bouton(uint8_t n_font, 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, GRIS_5);
bouton_i->cliked = false;
bouton_i->selected = false;
bouton_i->label = si;
bouton_i->affiche(c2, n_font);
}
void init_1_bouton_rouge(uint8_t n_font, uint16_t xi, uint16_t yi, uint8_t dx, uint8_t dy, String si, TOUCH_BOUTON *bouton_i)
{
uint16_t c2 = BLANC;
bouton_i->init(xi, yi, dx, dy, 3, ROUGE);
bouton_i->cliked = false;
bouton_i->selected = false;
bouton_i->label = si;
bouton_i->affiche(c2, n_font);
}
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, 24);
TFT.drawFastVLine(45, 15, 72, couleur_traits);
bt_mode_FRQ.init(5, 35, 37, 20, 2, GRIS_5);
bt_mode_FRQ.selected = false;
bt_mode_FRQ.label="FRQ";
bt_mode_FRQ.affiche(c2, 2);
bt_mode_MEM.init(5, 60, 37, 20, 2, GRIS_5);
bt_mode_MEM.selected = true;
bt_mode_MEM.label="MEM";
bt_mode_MEM.affiche(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, GRIS_5);
bouton_i->cliked = false;
bouton_i->selected = false;
bouton_i->label = s_i;
bouton_i->affiche(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();
}
/*
static void Tuner_Patch_Load(const unsigned char *pLutBytes, uint16_t size)
{
unsigned char buf[24 + 1];
uint16_t i, len;
uint16_t r;
buf[0] = 0x1b;
while (size)
{
len = (size > 24) ? 24 : size;
size -= len;
for (i = 0; i < len; i++) buf[1 + i] = pgm_read_byte(&pLutBytes[i]);
pLutBytes += len;
if (1 != (r = Tuner_WriteBuffer(buf, len + 1))) break;
}
}
void Tuner_Patch()
{
Tuner_Reset();
delay(100);
Wire.beginTransmission(0x64);
Wire.write(0x1c);
Wire.write(0x00);
Wire.write(0x00);
Wire.endTransmission();
delay(100);
Wire.beginTransmission(0x64);
Wire.write(0x1c);
Wire.write(0x00);
Wire.write(0x74);
Wire.endTransmission();
Tuner_Patch_Load(pPatchBytes102, PatchSize102);
Wire.beginTransmission(0x64);
Wire.write(0x1c);
Wire.write(0x00);
Wire.write(0x00);
Wire.endTransmission();
delay(100);
Wire.beginTransmission(0x64);
Wire.write(0x1c);
Wire.write(0x00);
Wire.write(0x75);
Wire.endTransmission();
Tuner_Patch_Load(pLutBytes102, LutSize102);
Wire.beginTransmission(0x64);
Wire.write(0x1c);
Wire.write(0x00);
Wire.write(0x00);
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 Fi)
{
TFT.setFreeFont(FF0);
//TFT.setTextColor(BLEU, NOIR);
String s1 = String(Fi);
//TFT.drawString(s1, 80, 2);
quiet = false; // anti-parasites
bt_quiet.selected = false;
bt_quiet.affiche(VERT, 1);
frequence = Fi;
if (Fi == 1500)
{
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString("MINIMUM ", 130, 2);
}
if (bande_SW)
{
modulation_active = AM;
Tune_Frequence_AM(Fi);
TFT.setTextColor(VERT, NOIR);
efface_box_entete2();
TFT.drawString("SW ", 130, 2);
}
if (bande_interdite1)
{
efface_box_entete2();
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString("FRQ non disponible", 80, 2);
}
if (bande_FM)
{
modulation_active = WFM;
Tune_Frequence_FM(Fi/10); // envoi les data au TEF6686
efface_box_entete2();
TFT.setTextColor(VERT, NOIR);
TFT.drawString("bande FM", 130, 2);
}
if (bande_interdite2)
{
efface_box_entete2();
TFT.setTextColor(ROUGE, NOIR);
TFT.drawString("FRQ NON DISPONIBLE", 80, 2);
}
if (bande_AIR)
{
modulation_active = AM;
Tune_Frequence_AM(Fi-110000); // nécessite un convertisseur de fréquence 110MHz en entrée antenne
TFT.setTextColor(BLEU_CLAIR, NOIR);
efface_box_entete2();
TFT.drawString("AIR BAND", 130, 2);
}
if (Fi == 138000)
{
TFT.setTextColor(ROUGE, NOIR);
efface_box_entete2();
TFT.drawString("F MAX ", 130, 2);
}
}
void load_GRP_FREQ_SD() // SD --> to RAM
{
Serial.println("--- Frequences lues sur la SDcard ---------------");
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(); // SD --> 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é
}
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_SDcard()
{
Serial.println("---------------------");
Serial.println("init_SDcard()");
String s1;
TFT.fillRect(0, 0, 480, 320, NOIR); // efface
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF1);
if(!SD.begin(5, mySpi2))
{
Serial.println("Card Mount Failed");
SDcardOk=0;
}
else
{
Serial.println("SDcard OK");
SDcardOk=1;
TFT.fillRect(0, 0, 480, 320, VERT);
delay(100);
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE)
{
Serial.println("NO SDcard");
SDcardOk=0;
return;
}
Serial.print("SDcard Type: ");
if(cardType == CARD_SD) {Serial.print("SDSC");}
else if(cardType == CARD_SDHC) {Serial.println("SDHC");}
uint32_t cardSize = SD.cardSize() / (1024 * 1024);
s1=(String)cardSize + " GB";
Serial.println(s1); Serial.println();
delay (100);
TFT.fillRect(0, 0, 480, 320, NOIR); // efface
}
void init_affichages()
{
Serial.println("init_affichages()");
TFT.fillRect(0, 0, 319, 239, couleur_fond_ecran);
efface_box_entete1();
efface_box_entete2();
efface_box_entete3();
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_SD();
init_1_bouton(1, x0_box_SD+4, y0_box_SD+16, 40, 15, " LST", &bt_LST);
init_1_bouton(1, x0_box_SD+4, y0_box_SD+33, 40, 15, "Write", &bt_SD_write);
TFT.setFreeFont(FF0);
init_boutons_Plus_Moins();
init_boutons_GROUPE(); // (SW - FM - AIR - SC)
init_1_bouton(1, 305, 15, 15, 15, "?", &bt_info);
init_1_bouton(1, 2, 15, 10, 10, "C", &bt_capture);
uint16_t xi, yi, dx, dy;
//1ere ligne, celle du dessus
xi = 167; yi = 212; dx = 35; dy = 11;
init_1_bouton(1, xi, yi, dx, dy, " LED", &bt_LED); xi+=3*dx+3*2; // LED backlight
init_1_bouton(1, xi, yi, dx, dy, " CAL", &bt_cal); xi+=dx+2;
//2eme ligne, en dessous
xi = 130; yi = 224; dx = 35; dy = 11;
init_1_bouton(1, xi, yi, dx, dy, "Mute", &bt_mute); xi+=dx+2;
init_1_bouton(1, xi, yi, dx, dy, "sleep", &bt_sleep); xi+=dx+2;
init_1_bouton(1, xi, yi, dx, dy, "quiet", &bt_quiet); xi+=dx+2;
init_1_bouton(1, xi, yi, dx, dy, " RST", &bt_reset); xi+=dx+2;
init_1_bouton(1, xi, yi, dx, dy, "Color", &bt_coul); xi+=dx+2;
init_1_bouton(1, 160, 120, 40, 14, "TEST", &bt_TEST);
TFT.fillRect(x0_box_boutons_scan, y0_box_boutons_scan + 10, 60, 25, NOIR);
init_1_bouton(2, 5, 118, 55, 20, "SCAN", &Bt_SCAN);
//init_1_bouton(1, 5, 135, 55, 15, "scan AIR", &bt_scan_air);
init_1_bouton(1, 168, 97, 30, 15, "set", &bt_set);
init_1_bouton(1, x0_box_SD+4, y0_box_SD+33, 40, 15, "Write", &bt_SD_write);
init_1_bouton(1, x0_box_SD+4, y0_box_SD+50, 40, 15, "raz 1F", &bt_erase_1F);
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(VERT ,1);
bt_plus.affiche(VERT ,1);
bt_SW.affiche(VERT, 1);
bt_FM.affiche(VERT, 1);
bt_AIR.affiche(VERT, 1);
bt_SCN.affiche(VERT, 1);
}
bt_4.selected = true;
bt_4.cliked = true;
bt_4.affiche(JAUNE,1);
bt_mute.selected = false;
bt_mute.cliked = false;
bt_mute.affiche(ROUGE, 1);
bt_sleep.affiche(VERT, 1);
bt_LED.affiche(VERT, 1);
bt_cal.affiche(VERT, 1);
bt_TEST.affiche(VERT, 1);
bt_reset.affiche(VERT, 1);
bt_quiet.affiche(VERT, 1);
bt_coul.affiche(VERT, 1);
affiche_frequence(frequence);
valeur_bargraph=0;
if (vu_metre_actif)
{
dessine_VuMetre();
}
else
{
//affi_image_from_SD("/bmp565/montagne170x140.bmp", x0_vu_metre, y0_vu_metre);
}
TFT.drawRect(0, 0, 319, 240, couleur_traits); // cadre principal pourtour de l'écran
}
void read_FRQ_File(FS &fs, String filename, String cible) // en mémoire SD
{
Serial.print("Reading file: "); Serial.println(filename);
File file = fs.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="";
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 = SD.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 read_params()
{
Serial.println("---------------------------------------------");
// lecture du fichier '/params.txt' en SD
Serial.println("lecture du fichier '/params.txt' en SD");
String s1;
int valeur;
//Serial.println("read params() ");
//for(uint8_t n=1; n<=6; n++) // lit toutes(6) lignes du fichier
s1 = "Z";
uint8_t n=1;
while (s1 !="")
{
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;}
//couleur_fond_ecran = VERT_FONCE; // pour TEST
valeur = extract_params(s1, "frequence");
if(valeur != -1) {frequence = valeur;}
valeur = extract_params(s1, "Ax");
if(valeur != -1) {A.x = valeur;}
valeur = extract_params(s1, "Ay");
if(valeur != -1) {A.y = valeur;}
valeur = extract_params(s1, "Bx");
if(valeur != -1) {B.x = valeur;}
valeur = extract_params(s1, "By");
if(valeur != -1) {B.y = valeur;}
n++;
}
Serial.print("---------------------------------------------");
}
void draw_AEC(uint16_t x0, uint16_t y0, uint16_t L, uint8_t sens)
{
// ligne arc-en-ciel
// affiche une ligne de pixels colorés à partir de la variable 'couleurs_aec' mémorisée en PROGMEM (voir fichier Couleurs_AEC.h)
// L = longueur de la ligne
//Serial.println("draw_draw_AEC()");
uint16_t x, i, j;
uint16_t y1;
uint16_t couleur_i;
for (int16_t i=0; i<L; i++)
{
float f = 470.0/L * i; // pour balayer toute l'échelle des couleurs disponibles
j=uint16_t(f);
couleur_i = couleurs_aec[2*j] | couleurs_aec[2*j+1]<<8;
if (sens==0){x=i;} else {x=L-i;}
TFT.drawPixel(x0+x, y0, couleur_i);
}
}
void set_frq_default()
{
presetPad1.bt_preset[0].frequence_FM = 88000;
presetPad1.bt_preset[1].frequence_FM = 90000;
presetPad1.bt_preset[2].frequence_FM = 92000;
presetPad1.bt_preset[3].frequence_FM = 94000;
presetPad1.bt_preset[4].frequence_FM = 96000;
presetPad1.bt_preset[5].frequence_FM = 100000;
presetPad1.bt_preset[6].frequence_FM = 104000;
presetPad1.bt_preset[7].frequence_FM = 108000;
}
void setup()
{
// étalonnage touch screen; ces valeurs peuvent varier d'un afficheur à l'autre
// pour l'instant il faut les fixer ici à la main...
eTS.x0 = -30; eTS.y0 = -30;
eTS.dx = 11; eTS.dy = 14;
Serial.begin(115200);
delay(20);
pinMode(GPIO_BL, OUTPUT);
digitalWrite(GPIO_BL, HIGH);
init_variables_globales();
Wire.begin(GPIO_SDA, GPIO_SCL, 2000000);
Tuner_Init(tuner_init_tab9216);
//affiche_frequence(frequence);
// 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);
// mySpi2 -> pour le lecteur de SDcard
// mySpi2 -> partage du bus SPI - mêmes valeurs de GPIO (sck=14, miso=12)
// que pour l'afficheur ILI9341 , sauf CS=5. Voir sur le schéma ainsi que le fichier User_Setup.h
mySpi2.begin(14, 12, 13, 5);
init_SDcard();
delay(20);
TFT.init();
TFT.setRotation(3); // 0..3 à voir, suivant disposition de l'afficheur
TFT.fillScreen(NOIR);
if (SDcardOk == false)
{
affi_message
(
"SDcard absente",
"Les parametres vont manquer, freq",
"(freq preset)",
"couleurs...",
"calibrage Touch Screen"
);
}
init_sprites();
affi_image_from_SD("/bmp565/7.bmp", 0, 0); // IMAGE D'ACCEUIL
delay(500);
if (SDcardOk == true)
{
read_params(); // sur la SDcard
}
else
{
frequence = 88000;
}
// si les coordonnées des points de calibrage sont aux fraises...
if (abs(A.x-600)>100 || abs(A.y-500)>100 || (abs(B.x-3700)>500 || abs(B.y-3600)>500 ) )
{
TS_calibrate();
}
groupe_SW.filename = "/FRQ_SW.txt"; // nom du fichier sur la SDcard
groupe_FM.filename = "/FRQ_FM.txt";
groupe_AIR.filename = "/FRQ_AIR.txt";
if (SDcardOk == true)
{
load_GRP_FREQ_SD();
groupe_SCAN.RAZ();
presetPad1.set_frequences_PRST();
presetPad1.set_couleurs();
} // -> to RAM
else
{
set_frq_default();
}
init_affichages();
saut_freq = 100;
//Tuner_Patch(); // envoi une tartine (6000 bytes) de code, non documentée; Je ne constate aucun effet bénéfique...
/*
Le PDF de NXP précise : "Use of these I2C transmissions is required for proper and full function and performance
as described in this user manual". (une sorte de vaccin anti-Covid donc...)
Toutefois si quelqu'un a réussi à déchiffrer le truc et peut me donner la liste des fonctions améliorées
je serais très heureux de le publier ici. Vous avez mon e-mail sur mon site www.silicium628.fr
*/
//delay(50);
Tuner_Init(tuner_init_tab9216);
delay(50);
// 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(c2, 2); // bt en haut à gauche
bt_mode_MEM.affiche(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(c2, 1);
bt_FM.affiche(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));
//couleur_fond_ecran = VERT_FONCE;
Serial.print("frequence="); Serial.println(frequence);
affiche_frequence(frequence);
Tune_Frequence(frequence);
Set_Volume(+70); // +60
delay(20);
//clic_logiciel_bouton(&bt_mode_MEM);
mode_s = _MEM;
efface_index_frq();
if (test_touch_screen == true) {printTouchToDisplay();}
// TS_calibrate(); pour forcer le calibrage
Serial.print("- FIN DU SETUP -----------------");
// FIN DU SETUP
}
void get_XY_touch()
{
TS_Point p = ts.getPoint();
float dx = B.x - A.x;
float ech_x = 300.0 / dx;
float x0 = A.x;
float dy = B.y - A.y;
float ech_y = 220.0 / dy;
float y0 = A.y;
memo_x_touch = x_touch;
memo_y_touch = y_touch;
x_touch = 10 + uint16_t( (p.x - x0) * ech_x);
y_touch = 10 + uint16_t( (p.y - y0) * ech_y);
/*
TFT.pushRect(memo_x_touch, memo_y_touch-10, 1, 20, memo_tiret_V); // efface avec l'image enregistrée
TFT.pushRect(memo_x_touch-10, memo_y_touch, 20, 1, memo_tiret_H); // efface avec l'image enregistrée
TFT.readRect(x_touch, y_touch-10, 1, 20, memo_tiret_V); // mémorise le segment avant de tracer
TFT.readRect(x_touch-10, y_touch, 20, 1, memo_tiret_H); // mémorise le segment avant de tracerfloat sy = sin((i - 90) * deg_to_rad);
TFT.drawFastVLine(x_touch, y_touch-10, 20, NOIR); // tiret vertical
TFT.drawFastHLine(x_touch-10, y_touch, 20, NOIR); // tiret horizontal
*/
}
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())
{
get_XY_touch();
TFT.drawRect(x_touch, y_touch, 1, 1, JAUNE);
}
}
}
// -------------------------------------------------------------------------
// 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() // en bas à gauche
{
TFT.fillRect(x0_box_info1+1, y0_box_info1+1, 118, 16, NOIR); // efface
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 FrSD_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) // à droite des gros chiffres
{
//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() // tout en haut à gauche
{
TFT.fillRect(1, 1, 50, 12, NOIR);
TFT.drawFastVLine(50, 0, 12, BLANC);
}
void efface_box_entete2() // tout en haut au centre
{
TFT.fillRect(50, 1, 180, 12, NOIR);
TFT.drawFastVLine(50, 0, 12, BLANC);
TFT.drawFastVLine(230, 0, 12, BLANC);
}
void efface_box_entete3() // tout en haut à droite
{
TFT.fillRect(230, 1, 89, 12, BLEU);
TFT.drawFastVLine(230, 0, 12, BLANC);
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);
//TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, NOIR);
}
void affiche_box_SD() // Raz, Write, Raz 1F, LST
{
TFT.fillRect(x0_box_SD, y0_box_SD + 10, 46, 58, NOIR);
TFT.setFreeFont(FF0);
TFT.setTextColor(GRIS_3, NOIR);
TFT.drawString("SD", x0_box_SD+6, y0_box_SD+6);
}
void affiche_box_scan(uint16_t dy)
{
init_1_bouton_rouge(1, 295, y0_box_SCAN+1, 20, 20, "x", &bt_stop_scan);
if (bande_active != AIR)
{
init_1_bouton(1, 275, y0_box_SCAN+40, 40, 15, "rescan", &bt_re_scan);
init_1_bouton(1, 275, y0_box_SCAN+58, 40, 14, " >>", &bt_scan_suivant);
}
init_1_bouton(1, 255, y0_box_SCAN+1, 25, 15, "+", &bt_seuil_plus);
init_1_bouton(1, 255, y0_box_SCAN+20, 25, 15, "-", &bt_seuil_moins);
init_1_bouton(1, 4, y0_box_SCAN+3, 15, 15, "L", &bt_LEV);
init_1_bouton(1, 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(c2, 1);
bt_FM.affiche(c2, 1);
bt_AIR.affiche(c2, 1);
bt_SCN.affiche(BLEU_CLAIR, 1);
bt_mute.affiche(ROUGE, 1);
}
void affiche_frequence(uint32_t frq)
{
Serial.println("affiche_frequence()");
TFT.fillRect(x0_box_info1+2, y0_box_info1, 118, 16, NOIR); // efface (en bas à gauche)
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);
}
else 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;
}
else 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);
}
else if(bande_interdite1 || bande_interdite2) // bandes interdites par le module TEF6686
{
affiche_band("---");
TFT.setTextColor(ROUGE, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("FRQ non disponible", 80, 2);
//delay(2000);
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(GRIS_1, 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");
bt_mute.selected = true;
bt_mute.affiche(ROUGE, 1);
bt_mute.selected = false;
mute = true;
Set_Mute(mute); // fonction située dans le fichier 'driverTEF6686_628.h'
}
else
{
affiche_band("---");
TFT.setTextColor(ROUGE, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("FRQ non disponible", 80, 2);
//delay(2000);
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(GRIS_1, 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");
bt_mute.selected = true;
bt_mute.affiche(ROUGE, 1);
bt_mute.selected = false;
mute = true;
Set_Mute(mute); // fonction située dans le fichier 'driverTEF6686_628.h
}
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(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) -5) ) && (y_touch < ((bouton_i->y0) + (bouton_i->read_dy())+5) ) )
{
bouton_i->cliked = true;
bouton_i->selected = true;
bouton_i->affiche(c2, 1);
delay(100);
}
}
void test_clic_6_boutons_frq() // 6 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-20)) && (y_touch < (bt_1.y0 + bt_1.read_dy()+20)) ) // 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(c2,1);
bt_2.cliked = false; bt_2.selected = false; test_clic_boutons(&bt_2 ); bt_2.affiche(c2,1);
bt_3.cliked = false; bt_3.selected = false; test_clic_boutons(&bt_3 ); bt_3.affiche(c2,1);
bt_4.cliked = false; bt_4.selected = false; test_clic_boutons(&bt_4 ); bt_4.affiche(c2,1);
bt_5.cliked = false; bt_5.selected = false; test_clic_boutons(&bt_5 ); bt_5.affiche(c2,1);
bt_6.cliked = false; bt_6.selected = false; test_clic_boutons(&bt_6 ); bt_6.affiche(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;}
delay(10);
}
}
void affiche_saisie(String s1)
{
efface_box_entete1();
TFT.setFreeFont(FF0); TFT.setTextColor(VERT, NOIR);
TFT.drawString(s1, x0_saisie+2, y0_saisie);
}
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");
efface_box_entete1();
efface_box_entete2();
//affiche_saisie(""); // efface
mode_s = _FRQ;
bt_mode_MEM.selected = false;
bt_mode_FRQ.selected = true;
bt_mode_MEM.affiche(c2, 2);
bt_mode_FRQ.affiche(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 = "";
n_appui = 0;
}
num_touche = 0;
}
void write_fichier_params() // sur la SDcard
{
Serial.println("write fichier '/params.txt'");
File file1 = SD.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);
s1 ="[Ax]";
s1 += "<";
s1 += String(A.x);
s1 +=">";
file1.println(s1);
s1 ="[Ay]";
s1 += "<";
s1 += String(A.y);
s1 +=">";
file1.println(s1);
s1 ="[Bx]";
s1 += "<";
s1 += String(B.x);
s1 +=">";
file1.println(s1);
s1 ="[By]";
s1 += "<";
s1 += String(B.y);
s1 +=">";
file1.println(s1);
file1.close();
delay(100);
}
void record_fichier_FRQ_SW_PRST()
{
Serial.println("record_fichier_FRQ_SW_PRST()");
File file1 = SD.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 = SD.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 = SD.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)
{
if(bande_active == SCN)
{
bande_active = FM; // afin de pouvoir traiter les fréquences preset attribuées aux boutons
groupe_actif = gFM;
modulation_active = WFM;
bt_FM.selected = true;
bt_SW.selected = false;
bt_AIR.selected = false;
bt_SCN.selected = false;
affi_boutons_SW_FM_AIR_SCN();
}
efface_index_frq();
mode_s = _MEM;
bt_mode_MEM.selected = true;
bt_mode_FRQ.selected = false;
bt_mode_MEM.affiche(c2, 2);
bt_mode_FRQ.affiche(c2, 2);
affiche_frequence(frequence);
// 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(100);
}
if(bande_active == FM)
{
presetPad1.bt_preset[n_bt].frequence_FM = frequence;
record_fichier_FRQ_FM_PRST();
mode_affi = NORMAL;
delay(100);
}
if(bande_active == AIR)
{
presetPad1.bt_preset[n_bt].frequence_AIR = frequence;
record_fichier_FRQ_AIR_PRST();
mode_affi = NORMAL;
delay(100);
}
mode_affi = NORMAL;
vu_metre_actif = true;
init_affichages();
}
vu_metre_actif = true;
dessine_VuMetre();
affiche_frequence(frequence);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF0);
Tune_Frequence(frequence);
write_fichier_params();
}
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;
//--------------------------------------------------------------------
if(mode_s == _FRQ) // on va modifier directement la fréquence
{
test_clic_boutons(&bt_plus );
bt_plus.affiche(c2, 1);
if (bt_plus.cliked)
{
efface_box_entete2();
presetPad1.deselect_boutons();
frequence += saut_freq;
bouton_cliked = true;
}
delay(100);
if (bt_plus.cliked && ((frequence + saut_freq) <= 138000 ))
{
Tune_Frequence(frequence);
}
bt_plus.cliked = false;
bt_plus.selected = false;
bt_plus.affiche(c2, 1); // fugitif
test_clic_boutons(&bt_moins );
bt_moins.affiche(c2, 1);
delay(100);
if (bt_moins.cliked)
{
efface_box_entete2();
if (frequence > saut_freq) // évite de se retrouver avec une F négative !
{
presetPad1.deselect_boutons();
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(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(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);
write_fichier_params();
vu_metre_actif = true;
dessine_VuMetre();
affiche_frequence(frequence);
delay(100);
}
bt_plus.cliked = false;
bt_plus.selected = false;
bt_plus.affiche(c2, 1); // fugitif
test_clic_boutons(&bt_moins );
bt_moins.affiche(c2, 1);
delay(100);
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);
write_fichier_params();
vu_metre_actif = true;
dessine_VuMetre();
affiche_frequence(frequence);
}
bt_moins.cliked = false;
bt_moins.selected = false;
bt_moins.affiche(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(VERT, 1);
init_affichages();
}
}
void test_clic_bt_coul() // bouton au coin en bas à droite
{
uint16_t c1 = GRIS_5;
uint16_t c2 = BLANC;
uint8_t n;
test_clic_boutons(&bt_coul );
if (bt_coul.cliked)
{
bt_coul.cliked = false;
bt_coul.selected = true;
bt_coul.affiche(VERT, 1);
vu_metre_actif = false;
//delay(1000);
TFT.fillRect(x0_gridPad, y0_gridPad, dx_gridPad, dy_gridPad, NOIR);
gridPad1.init(x0_gridPad, y0_gridPad);
gridPad1.set_couleurs();
gridPad1.affiche();
boolean ok = false;
while(! ok)
{
if (ts.tirqTouched() && ts.touched())
{
get_XY_touch();
delay(100);
test_clic_bt_capture(); // capture écran
n = gridPad1.test_clic();
if (n != 253)
{
Serial.println(n);
if ((n != 32) && (n != 255))
{
couleur_fond_ecran = gridPad1.bt_grid[n].couleur;
write_fichier_params();
}
ok = true;
mode_affi = NORMAL;
vu_metre_actif = true;
init_affichages();
}
}
}
}
}
void test_clic_bouton_mute()
{
test_clic_boutons(&bt_mute );
if (bt_mute.cliked)
{
bt_mute.affiche(ROUGE, 1);
delay(10);
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(ROUGE, 1);
if (mute == false) {Tune_Frequence(frequence);}
delay(10);
}
}
void test_clic_bt_quiet()
{
test_clic_boutons(&bt_quiet );
if (bt_quiet.cliked)
{
bt_quiet.cliked = false;
bt_quiet.selected = true;
bt_quiet.affiche(VERT, 1);
if(quiet==false)
{
quiet = true; // anti-parasites
vu_metre_actif = false;
affi_image_from_SD("/bmp565/montagne170x140b.bmp", x0_vu_metre, y0_vu_metre);
}
else
{
quiet = false;
vu_metre_actif = true;
dessine_VuMetre();
}
bt_quiet.cliked = false;
bt_quiet.selected = quiet;
bt_quiet.affiche(VERT, 1);
delay(300);
}
}
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(VERT, 1);
delay(10);
// 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(10);
attente_clic();
}
}
void test_clic_bt_capture() // capture écran
{
test_clic_boutons(&bt_capture);
if (bt_capture.cliked)
{
bt_capture.cliked = false;
bt_capture.selected = true;
bt_capture.affiche(VERT, 1);
delay(10);
write_TFT_on_SDcard();
}
}
void affi_message(String L1, String L2, String L3, String L4, String L5)
{
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF1);
uint16_t y = 50;
uint16_t dy = 20;
TFT.drawString(L1, 20, y); y+=dy;
TFT.drawString(L2, 20, y); y+=dy;
TFT.drawString(L3, 20, y); y+=dy;
TFT.drawString(L4, 20, y); y+=dy;
TFT.drawString(L5, 20, y);
delay(10);
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(ROUGE, 1);
delay(10);
//todo: save en SD
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(10);
attente_clic();
esp_deep_sleep_start();
}
}
void test_clic_bt_LED()
{
test_clic_boutons(&bt_LED );
if (bt_LED.cliked)
{
bt_LED.cliked = false;
bt_LED.selected = true;
bt_LED.affiche(ROUGE, 1);
delay(10);
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF1);
TFT.drawString("ECRAN NOIR", 20, 50);
TFT.drawString("Clic pour rallumer", 20, 90);
for(int n=10; n>0; n--)
{
TFT.drawString(String(n) + " ", 20, 110);
delay(500);
}
digitalWrite(GPIO_BL, LOW);
attente_clic();
digitalWrite(GPIO_BL, HIGH);
}
}
void test_clic_bt_CAL()
{
test_clic_boutons(&bt_cal );
if (bt_cal.cliked)
{
bt_cal.cliked = false;
bt_cal.selected = true;
bt_cal.affiche(BLEU, 1);
delay(10);
TFT.fillScreen(NOIR);
TS_calibrate();
}
}
uint16_t read_16(File fp)
{
uint8_t low;
uint16_t high;
low = fp.read();
high = fp.read();
return (high<<8)|low;
}
uint32_t read_32(File fp)
{
uint16_t low;
uint32_t high;
low = read_16(fp);
high = read_16(fp);
return (high<<8)|low;
}
void affi_image_from_SD(String filename, uint16_t x0, uint16_t y0)
{
Serial.println("----------------------------");
Serial.println("affi_image_from_SD()");
uint8_t bmp_data[2]={0,0};
uint8_t a, b;
uint16_t x=0;
uint16_t y=0;
int16_t xmax;
uint32_t seekOffset;
uint16_t w, h, row, col;
File fp = SD.open(filename, "r");
if (!fp) { Serial.println("ERREUR open file on SD"); return; }
uint16_t etiq1 = read_16(fp);
// test bmp_header
if (etiq1 == 0x4D42)
{
read_32(fp);
read_32(fp);
seekOffset = read_32(fp);
Serial.print("seekOffset ="); Serial.println(seekOffset); // 138
Serial.print("seekOffset= "); Serial.println(seekOffset);
read_32(fp);
w = read_32(fp);
h = read_32(fp);
Serial.print("w= "); Serial.println(w); // 75
Serial.print("h= "); Serial.println(h); // 50
Serial.println(read_16(fp)); // 1
Serial.println(read_16(fp)); // 16
Serial.println(read_16(fp)); // 3
fp.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++)
{
fp.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--;
}
fp.close();
}
/*
void ajout_1_freq()
{
// AJOUT d'une fréquence en fin d'une liste de fréquences. Travaille directement sur la mémoire SD
File file = SD.open("/FRQ_FM.txt", FILE_APPEND);
file.print("<88800>"); // ok ; attention à ne pas oublier les < >
file.close(); // enregistre CE fichier en mémoire SD, sans toucher aux autres
delay(100);
}
*/
void affi_nuances_de_gris()
{
TFT.fillScreen(NOIR);
uint16_t x, dx, y;
x=30;
dx=21;
y=100;
TFT.fillRect(x, y, dx, dx, BLANC); x+=dx;
TFT.fillRect(x, y, dx, dx, GRIS_1); x+=dx;
TFT.fillRect(x, y, dx, dx, GRIS_2); x+=dx;
TFT.fillRect(x, y, dx, dx, GRIS_3); x+=dx;
TFT.fillRect(x, y, dx, dx, GRIS_4); x+=dx;
TFT.fillRect(x, y, dx, dx, GRIS_5); x+=dx;
TFT.fillRect(x, y, dx, dx, GRIS_6); x+=dx;
attente_clic();
}
void TS_verif()
{
TFT.fillScreen(BLANC);
TFT.setTextColor(NOIR, BLANC);
TFT.setFreeFont(FF1);
TFT.drawString("VERIF CALIBRATION", 10, 50);
init_1_bouton(1, 280, 20, 20, 20, "X", &bt_close);
boolean stop = false;
while(! stop)
{
get_XY_touch();
test_clic_boutons(&bt_close );
if (bt_close.cliked)
{
bt_close.cliked = false;
stop = true;
}
delay(10);
}
TFT.fillScreen(NOIR);
init_affichages();
}
void TS_calibrate() // calibrage de l'écran tactile
{
uint8_t L = 20;
boolean ok;
String s1;
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF1);
// traitement point A
TFT.fillScreen(NOIR);
TFT.drawString("Cliquez sur le point A", 20, 50);
delay(300);
TFT.drawFastVLine(10, 0, L, JAUNE);
TFT.drawFastHLine(0, 10, L, JAUNE);
ok = false;
while (! ok)
{
if (ts.tirqTouched() && ts.touched())
{
memo_y_touch = y_touch;
TS_Point p = ts.getPoint();
s1 = "Ax=" + String(p.x) + " "; TFT.drawString(s1, 50, 100);
s1 = "Ay=" + String(p.y) + " "; TFT.drawString(s1, 50, 120);
delay(100);
if( (p.x<600) && (p.y < 600)) // évite de valider une position irréaliste
{
A.x = p.x; // point A : variable globale
A.y = p.y;
ok = true;
}
}
}
// traitement point B
TFT.fillScreen(NOIR);
delay(300);
TFT.drawString("Cliquez sur le point B", 20, 70);
TFT.drawFastVLine(310, 230-L/2, L, JAUNE);
TFT.drawFastHLine(310-L/2, 230, L, JAUNE);
ok = false;
while (! ok)
{
if (ts.tirqTouched() && ts.touched())
{
memo_y_touch = y_touch;
TS_Point p = ts.getPoint();
s1 = "Bx=" + String(p.x) + " "; TFT.drawString(s1, 50, 150);
s1 = "By=" + String(p.y) + " "; TFT.drawString(s1, 50, 170);
delay(100);
if( (p.x>3600) && (p.y > 3400)) // évite de valider une position irréaliste
{
B.x = p.x;
B.y = p.y;
ok = true;
}
}
}
TFT.fillScreen(NOIR);
TFT.drawString("Ok", 20, 60);
TFT.setFreeFont(FF0);
TFT.drawString("Write fichier params sur la SD", 10, 90);
write_fichier_params();
delay(1000);
TFT.fillScreen(NOIR);
init_affichages();
//TS_verif();
//printTouchToDisplay(); // POUR TESTER LA CALIBRATION DE L'ECRAN TACTILE
}
void affi_lst_codes_PI_RDS() // lecture directement sur la SDcard, pas de mise en mémoire RAM
{
Serial.println("liste_codes_RDS()");
int i = 1;
char buffer1[64];
//uint32_t valeur_lue;
uint16_t line_num;
uint16_t nombre =0;
uint16_t y=0;
String s1;
boolean stop = false;
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("Liste codes PI RDS (en memoire SD)", 0, y);
y+=30;
init_1_bouton(1, 280, 20, 50, 15, "stop", &bt_annuler);
bt_annuler.affiche(BLANC, 1);
File file1 = SD.open("/RDS_codes_PI.lst", "r");
while (file1.available() && stop == false )
{
int nb_bytes = file1.readBytesUntil('\n', buffer1, sizeof(buffer1));
buffer1[nb_bytes] = 0; // zéro terminal afin d'obtenir un string
//if (line_num == i)
{
//if(s1 != "") // n'affiche pas les emplacements vides
{
nombre++;
s1 = String(nombre);
TFT.setTextColor(BLEU, NOIR);
TFT.drawString(s1, 5, y);
s1 = buffer1;
//s1 += " ";
TFT.setTextColor(BLANC, NOIR);
TFT.drawString(s1, 30, y);
y+=10;
if(y>230)
{
delay(500); //300
if (ts.tirqTouched() && ts.touched())
{
stop = true;
TFT.fillScreen(NOIR);
TFT.drawString("STOP", 100, 100);
return;
}
else
{
delay(300); //200
TFT.fillScreen(NOIR);
y=0;
TFT.drawString("Liste codes PI RDS (en memoire SD)", 0, y);
bt_annuler.affiche(BLANC, 1);
y+=30; //30
}
}
}
}
i++;
}
file1.close();
attente_clic2();
}
void affi_deroulant(String titre, String filename)
{
//decale le texte fichier texte vers le haut et le complète en bas comme dans un générique de film
delay(300);
uint16_t memo_line_H[1920]; // 1280
char buffer1[64];
String s1, s2, s3, s4;
TFT.setFreeFont(FF0);
TFT.fillScreen(NOIR);
TFT.drawRect(1, 0, 319, 165, BLANC);
TFT.setTextColor(JAUNE, NOIR);
TFT.drawString(titre, 10, 5);
TFT.drawFastHLine(1, 14, 318, GRIS_5);
TFT.setTextColor(BLANC, NOIR);
init_1_bouton(1, 280, 220, 50, 15, "stop", &bt_annuler);
bt_annuler.affiche(BLANC, 1);
File file1 = SD.open(filename, "r");
int n=0;
boolean stop = false;
while (file1.available() && stop == false )
{
for(int y=22; y<160; y+=6) // 4
{
TFT.readRect(2, y, 317, 6, memo_line_H); // 4 mémorise la ligne
TFT.pushRect(2, y-4, 317, 6, memo_line_H); // la recopie un ligne au dessus
}
if(n%3 == 0) // 2
{
int nb_bytes = file1.readBytesUntil('\n', buffer1, sizeof(buffer1));
buffer1[nb_bytes] = 0; // zéro terminal afin d'obtenir un string
s1 = String(n/3); // 2
s2 = buffer1;
s3 = s2.substring(0, 4);
s4 = s2.substring(5);
//TFT.fillRect(10, 148, 339, 8, NOIR);
TFT.setTextColor(BLEU, NOIR);
TFT.drawString(s1, 10, 148);
TFT.setTextColor(JAUNE, NOIR);
TFT.drawString(s3, 40, 148);
TFT.setTextColor(GRIS_3, NOIR);
TFT.drawString(s4, 70, 148);
}
n++;
if ((ts.tirqTouched() && ts.touched()))
{
get_XY_touch();
test_clic_boutons(&bt_annuler);
if (bt_annuler.cliked)
{
bt_annuler.cliked = false;
TFT.fillScreen(NOIR);
x_touch = 0;
y_touch = 0;
delay(500);
stop = true;
}
}
}
file1.close();
}
void test_clic_bouton_TEST()
{
test_clic_boutons(&bt_TEST );
bt_TEST.affiche(ROUGE, 1);
if (bt_TEST.cliked)
{
delay(10);
Serial.println("-------------------------------");
Serial.println("bt_TEST.cliked");
bt_TEST.cliked = false;
bt_TEST.selected = true;
bt_TEST.affiche(ROUGE, 1);
//TFT.fillscreen(GRIS_3); // effface
//affi_image_from_SD("/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);
}
*/
//TS_calibrate();
//affi_nuances_de_gris();
//TFT.fillScreen(NOIR); // effface
//draw_AEC(0, 100, 320, 1);
//affi_lst_codes_PI_RDS();
//TFT.fillScreen(GRIS_3); // effface
//affi_deroulant("Liste codes PI RDS", "/RDS_codes_PI.lst");
//TFT.drawString("Lecture faite", 10, 90);
//attente_clic2();
bt_TEST.cliked = false;
bt_TEST.selected = false;
bt_TEST.affiche(ROUGE, 1);
init_affichages();
Serial.println("-------------------------------");
}
}
void test_clic_Bt_reset()
{
test_clic_boutons(&bt_reset );
bt_reset.affiche(NOIR, 1);
if (bt_reset.cliked)
{
delay(10);
bt_reset.cliked = false;
bt_reset.selected = true;
bt_reset.affiche(VERT, 1);
delay(10);
bt_reset.selected = false;
bt_reset.affiche(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(VERT, 1);
bt_SNR.selected = false; bt_SNR.affiche(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(VERT, 1);
bt_LEV.selected = false; bt_LEV.affiche(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(BLANC, 1);
mode_affi = NORMAL;
bt_stop_scan.cliked = false;
bt_stop_scan.affiche(BLANC, 1);
}
}
void test_clic_bt_annuler()
{
test_clic_boutons(&bt_annuler);
if (bt_annuler.cliked)
{
bt_annuler.cliked = false;
bt_annuler.affiche(BLANC, 1);
mode_affi = NORMAL; // ce qui repasse les boutons 'preset' en mode sélection et empêche l'écriture en SD
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()
{
// le scan de la bande aviation civile nécessite un convertisseur de fréquence 110MHz en entrée antenne
// le scan_AIR ne teste pas toutes les fréquences de la gamme mais seulement celles prédéfinies
// dans le fichier 'FRQ_AIR.txt' (sur la SDcard)
// ces fréquences peuvent avoir été écrites par le programme (touche 'Write') ou manuellement
// avec un éditeur de texte en respectant le syntaxe, par exemple <123500>
Serial.println("scan_mem_AIR()");
bande_active = AIR;
efface_box_GROUPE();
TFT.fillScreen(couleur_fond_ecran);
uint16_t couleur_ciel = 10739;
TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, GRIS_6);
affi_image_from_SD("/bmp565/avion1.bmp", 1, 80);
affiche_box_scan(dy_box_SCAN);
TFT.setFreeFont(FF0);
TFT.setTextColor(JAUNE, NOIR);
TFT.fillRect(2, 2, 42, 80, couleur_ciel); // efface
affi_image_from_SD("/bmp565/avion3.bmp", 1, 15);
affi_image_from_SD("/bmp565/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];
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(VERT, 1);
bt_LEV.selected = false; bt_LEV.affiche(VERT, 1);
TFT.setFreeFont(FM9);
TFT.setTextColor(JAUNE, NOIR);
frequence = 124075;
Tune_Frequence(frequence);
affiche_frequence(frequence);
TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(0, base -seuil, 319, JAUNE); // seuil (trait horizontal sur toute la largeur)
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())
{
get_XY_touch();
test_clic_bt_stop_scan();
test_clic_bt_capture(); // capture écran
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 , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(0, base -seuil, 319, JAUNE); // seuil (trait horizontal sur toute la largeur)
TFT.setFreeFont(FF0); TFT.setTextColor(JAUNE, NOIR);
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +190 , y0_box_SCAN +15);
}
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(0, base -seuil, 319, JAUNE); // seuil (trait horizontal sur toute la largeur)
TFT.setFreeFont(FF0); TFT.setTextColor(JAUNE, NOIR);
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +190 , y0_box_SCAN +15);
}
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(VERT, 2);
bt_mode_FRQ.selected = false; bt_mode_FRQ.affiche(VERT, 2);
//boutons_preset_set_frequences();
init_affichages();
frequence = 89400;
Tune_Frequence(frequence);
affiche_frequence(frequence);
bt_FM.selected = true; bt_FM.affiche(VERT, 1);
bt_AIR.selected = false; bt_AIR.affiche(VERT, 1);
}
void affi_passes(String band_name, int num_passe, int nb_passes)
{
TFT.setTextColor(NOIR, BLANC); TFT.setFreeFont(FMB9);
String s1 = "SW bande" + band_name;
s1 += "_";
TFT.drawString(s1, 2, 14);
s1 = String(num_passe);
s1 += "/";
s1 += String(nb_passes);
TFT.drawString(s1, 284, 14); // en haut à droite
TFT.drawString(s1, 10, 200); // en bas à gauche
}
void scan_frq(uint32_t freq_iA, uint32_t freq_iB, String band_name) // toutes les fréquences de la bande, incrémental, saut_freq = constant
{
Serial.println("scan_frq()");
Serial.print("freq_iA = "); Serial.println(freq_iA);
Serial.print("freq_iB = "); Serial.println(freq_iB);
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;
uint32_t freq;
uint32_t largeur_bande = freq_iB - freq_iA;
uint16_t nb_F;
int n_max;
int nb_passes = 1;
int num_passe = 1;
int16_t signal_i;
uint16_t base = y0_box_SCAN + dy_box_SCAN -5; // bas du graphique
uint16_t memo_line_H[320];
uint16_t decal_x;
uint16_t decal_y;
TFT.fillScreen(couleur_fond_ecran);
TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, NOIR);
memo_freq = freq_iA; // 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(VERT, 1);
bt_LEV.selected = false; bt_LEV.affiche(VERT, 1);
groupe_SCAN.RAZ();
efface_box_GROUPE();
//TFT.setFreeFont(FM9);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF0);
freq = freq_iA;
uint8_t module;
if(bande_active == FM)
{
saut_freq = 100; // kHz
module = 32;
n_max = 190;
nb_passes = 1;
}
else
{
saut_freq = 5; // kHz
module = 33;
n_max = largeur_bande / saut_freq;
nb_passes = 1 + n_max / 200;
if(nb_passes < 1) {nb_passes=1;}
}
y = y0_box_SCAN + 5;
decal_x=0;
decal_y=0;
nb_F=0;
// sA = String(freq);
// sB = String(freq + n_max * saut_freq);
// TFT.drawString(sA, x0_box_SCAN +5 , base-5);
// TFT.drawString(sB, x0_box_SCAN +dx_box_SCAN -40, base-5);
sA = String(freq_iA + (num_passe-1) * 200 * saut_freq);
sB = String(freq_iA + num_passe * 200 * saut_freq);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString(sA, x0_box_SCAN +5 , base-5);
TFT.drawString(sB, x0_box_SCAN +dx_box_SCAN -40, base-5);
TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(0, base -seuil, 319, VIOLET); // seuil (trait horizontal sur toute la largeur)
TFT.setTextColor(VIOLET, NOIR);
TFT.setFreeFont(FF0);
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +190 , y0_box_SCAN +15);
boolean scan_complet;
boolean rescan = false;
do
{
groupe_SCAN.RAZ();
nb_F = 0;
affiche_box_scan(dy_box_SCAN);
uint32_t freq_min = freq;
if(bande_active == SW)
{
affi_passes(band_name, num_passe, nb_passes);
s1 = "[" + String(freq_iA) + "-" + String(freq_iB) + "]";
TFT.setTextColor(BLANC, couleur_fond_ecran); TFT.setFreeFont(FF1);
TFT.drawString(s1, 145, 14);
}
//......................................................................
int n = n_max;
while((n>0) && !(bande_interdite1 || bande_interdite2))
{
if (ts.tirqTouched() && ts.touched()) // écran tactile
{
get_XY_touch();
test_clic_boutons(&bt_stop_scan);
if (bt_stop_scan.cliked)
{
//bt_stop_scan.cliked = false;
n=0; // force la sortie de la boucle while()
}
}
freq += saut_freq;
affiche_frequence(freq);
if( (freq + saut_freq) <= 138000 )
{
Tune_Frequence(freq);
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-=5;
//uint16_t c1;
xi32 = x0_box_SCAN + (uint32_t)xi;
// BARRES VERTICALES ----------------------------
if (xi32 < 318) // limite d'affichage à droite
{
// on va les tracer les barres verticales point par point afin de pouvoir les coloriser
int a = base;
int b = a - dy;
uint16_t x, y1, j, L;
uint16_t couleur_i;
L = dy; // longueur (verticale) de la barre
for (int16_t i=0; i<L; i++)
{
float f = 10.0 * i; // pour balayer toute l'échelle des 470 couleurs disponibles
j=uint16_t(f);
if(j>460){j=460;}
couleur_i = couleurs_aec[2*j] | couleurs_aec[2*j+1]<<8; //couleurs arc-en-ciel, voir fichier Couleurs_AEC.h
y1=225-i;
TFT.drawPixel(xi32, y1, couleur_i);
}
}
else // on arrive en bout d'affichage à droite, on passe à la plage suivante si necessaire...
{
TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, NOIR);
affiche_box_scan(dy_box_SCAN); // efface le tracé et re-dessine les boutons dans la boite
TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(0, base -seuil, 319, VIOLET); // seuil (trait horizontal sur toute la largeur)
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +190 , y0_box_SCAN +15);
xi = 0;
num_passe ++;
if(bande_active == SW)
{
affi_passes(band_name, num_passe, nb_passes);
sA = String(freq_iA + (num_passe-1) * 200 * saut_freq);
sB = String(freq_iA + num_passe * 200 * saut_freq);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString(sA, x0_box_SCAN +5 , base-5);
TFT.drawString(sB, x0_box_SCAN +dx_box_SCAN -40, base-5);
}
}
// --------------------------------------------------
if(signal_i > seuil*10) // 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(freq);
TFT.setTextColor(BLANC, NOIR);
TFT.drawString(s1, x0_box_SCAN + 20 + 45*decal_x, y0_box_SCAN + 9*decal_y); // affiche FREQUENCE
nb_F++;
TFT.setFreeFont(FF0);
TFT.setTextColor(VERT, NOIR);
s1 = String(nb_F);
TFT.drawString(s1, x0_box_SCAN +3 , y0_box_SCAN + 45); // nb freq
TFT.setFreeFont(FF0);
groupe_SCAN.add_frq(freq); // 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(freq);
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 (n<10) {scan_complet = true;}
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
{
get_XY_touch();
test_clic_bt_capture(); // capture écran
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 , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(0, base -seuil, 319, VIOLET); // seuil (trait horizontal sur toute la largeur)
TFT.setFreeFont(FF0); TFT.setTextColor(VIOLET, NOIR);
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +190 , y0_box_SCAN +15);
}
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(0, base -seuil, 319, VIOLET); // seuil (trait horizontal sur toute la largeur)
TFT.setFreeFont(FF0); TFT.setTextColor(VIOLET, NOIR);
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +190 , y0_box_SCAN +15);
}
// 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;
TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, NOIR);
affiche_box_scan(dy_box_SCAN); // efface le tracé et re-dessine les boutons dans la boite
freq = memo_freq; // 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;
TFT.readRect(0, base - seuil , 319, 1, memo_line_H); // mémorise la ligne avant de tracer
TFT.drawFastHLine(0, base -seuil, 319, VIOLET); // seuil (trait horizontal sur toute la largeur)
si = "seuil:" + String(seuil*10); TFT.drawString(si+" ", x0_box_SCAN +190 , y0_box_SCAN +15);
}
}
} // fin de la boucle while()
//.......................................................................
if(nb_passes == 1) // because la fonction d'écoute au stylet incorrecte si spectre partiel
{
TFT.setTextColor(CYAN, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("On peut ecouter les freq", 10, 145);
TFT.drawString("en deplacant le stylet sur le spectre", 10, 155);
}
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())
{
get_XY_touch();
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);
freq = F1;
affiche_frequence(freq);
Tune_Frequence(freq);
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;
freq = memo_freq; // 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;
TFT.fillRect(x0_box_SCAN, y0_box_SCAN, dx_box_SCAN, dy_box_SCAN, NOIR);
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_freq = freq;
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)
{
n=0;
stop =true; // sortira de la boucle while()
rescan = false; // ne rebouclera PAS dans la boucle do()
}
}
}
} while (rescan == true); // Fin de la boucle do()
groupe_SCAN.bloc_to_serial(); // pour test avec moniteur série (CuteCom par exemple)
mode_affi = NORMAL;
mode_s = _MEM;
bt_mode_FRQ.selected = false; bt_mode_FRQ.affiche(VERT, 2);
bt_mode_MEM.selected = true; bt_mode_MEM.affiche(VERT, 2);
write_fichier_params();
if (bt_stop_scan.cliked == false)
{
// si on est sorti de la boucle normalement, (pas par clic sur bouton stop), on passe ici
uint16_t ya = 20;
uint8_t dya = 15;
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, 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("On peut les enregistrer en SD", 5, ya); ya += dya;
TFT.drawString("une a une avec le bouton 'Write'", 5, ya); ya += dya;
TFT.drawString("sinon -> perdues si stop radio", 5, ya); ya += dya;
attente_clic();
delay(300);
}
}
void choix_type_scan()
{
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF1);
TFT.drawString("CHOIX TYPE SCAN", 10, 5);
init_1_bouton(2, 10, 70, 85, 20, "scan SW", &bt_scan_SW);
init_1_bouton(2, 120, 70, 85, 20, "scan FM", &bt_scan_FM);
init_1_bouton(2, 60, 100, 95, 20, "scan AIR", &bt_scan_air);
boolean ok1 = false;
while (! ok1)
{
if ((ts.tirqTouched() && ts.touched()))
{
get_XY_touch();
test_clic_boutons(&bt_scan_SW);
if (bt_scan_SW.cliked == true)
{
ok1 = true;
// -------------------------- BANDES SW choisies ----------------
bt_scan_SW.cliked = false;
TFT.fillScreen(NOIR);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("CHOIX BANDE SW", 230, 2);
swPad1.init(5, 2); // initialise et affiche les 14 boutons des 14 bandes d'ondes courtes (SW)
swPad1.set_frequences_SW();// voir la fonction 'void SW_PAD::set_frequences_SW()' pour les fréquences SW
affi_image_from_SD("/bmp565/3r.bmp", 150, 60);
boolean ok2 = false;
while (! ok2)
{
if ((ts.tirqTouched() && ts.touched()))
{
// ---------------- choix de la bande AM SW (impose la fréquence de départ) ---------------
get_XY_touch();
uint8_t n = swPad1.test_clic();
uint32_t FA = swPad1.bt_SW[n].freq_A; // fréquence de départ du scan AM
uint32_t FB = swPad1.bt_SW[n].freq_B; // fréquence de fin du scan AM
if (FA != 0) // si on n'a pas cliqué en dehors des clous...
{
String band_name = " "; // espace à gauche
uint16_t L = swPad1.bt_SW[n].lambda;
band_name += String(L)+"m";
TFT.setTextColor(NOIR, BLANC);
TFT.setFreeFont(FMB12);
TFT.drawString(band_name + " ", 150, 10);
String s2 = String(FA) + ".." + String(FB)+ " kHz";
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF1);
TFT.drawString(s2, 140, 35);
bande_active = SW;
ok2=true;
mode_affi = SCAN_F;
mode_s = _FRQ;
delay(2500);
scan_frq(FA, FB, band_name); // scanner (AM-SW ou FM )
}
}
}
}
if ((ts.tirqTouched() && ts.touched()))
{
get_XY_touch();
test_clic_boutons(&bt_scan_FM);
if (bt_scan_FM.cliked == true)
{
// ------------------------------ BANDE FM choisie -----------------
bt_scan_FM.cliked = false;
bande_active = FM;
ok1=true;
mode_affi = SCAN_F;
mode_s = _FRQ;
scan_frq(88000, 108000, "bande FM");
}
}
test_clic_boutons(&bt_scan_air);
if (bt_scan_air.cliked == true)
{
// ------------------------------ BANDE AIR ----------------
bt_scan_air.cliked = false;
mode_affi = SCAN_M;
bande_active == AIR;
ok1=true;
scan_mem_AIR();
mode_s = _MEM;
}
}
}
}
void test_clic_Bt_SCAN()
{
if ((ts.tirqTouched() && ts.touched()))
{
get_XY_touch();
test_clic_boutons(&Bt_SCAN);
if (Bt_SCAN.cliked == true)
{
Bt_SCAN.cliked = false;
choix_type_scan(); // choix bande à scanner (SW - FM) et type FRQ ou AIR (puis déclenche le scan)
init_affichages();
groupe_actif = gSCN;
bande_active = SCN;
//bt_SCN.selected = true; bt_SCN.affiche(CYAN, 1);
bt_SW.selected = false; bt_SW.affiche(VERT, 1);
bt_FM.selected = false; bt_FM.affiche(VERT, 1);
bt_AIR.selected = false;bt_AIR.affiche(VERT, 1);
//affiche_numero_frq(String(1), String(nb_F));
affiche_frequence(frequence);
}
}
}
void retour_normal()
{
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(VERT, 1);
//bt_FM.affiche(VERT, 1);
}
void attente_clic()
{
delay(300);
init_1_bouton(1, 300, 5, 20, 20, "X", &bt_close);
while ( !(ts.tirqTouched() && ts.touched()) ) {;}
retour_normal();
}
void attente_clic2() // et anti-parasite !!!
{
delay(300);
while ( !(ts.tirqTouched() && ts.touched()) ) {;}
}
void SD_listFiles()
{
uint16_t y=0;
String s1;
TFT.fillScreen(NOIR);
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString("Liste des fichiers (en memoire SD)", 0, y); y+=30;
File root = SD.open("/");
File file = root.openNextFile();
while (file)
{
s1 = String(file.name());
TFT.setTextColor(VERT, NOIR);
TFT.drawString(s1, 0, y);
s1 = "size:";
TFT.setTextColor(BLANC, NOIR);
TFT.drawString(s1, 100, y);
s1 = file.size();
TFT.setTextColor(JAUNE, NOIR);
TFT.drawString(s1, 140, y);
y+=10;
file = root.openNextFile();
}
}
void SD_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 SD_RAZ()", 50, 180);
delay(3000);
init_affichages();
return;
}
SD.remove("FRQ_SW.txt");
SD.remove("FRQ_SW_PRST.txt");
SD.remove("FRQ_FM.txt");
SD.remove("FRQ_FM_PRST.txt");
SD.remove("FRQ_AIR.txt");
SD.remove("FRQ_AIR_PRST.txt");
Serial.println("fin RAZ SD");
}
void test_clic_bouton_LST()
{
uint16_t c1 = NOIR;
uint16_t c2 = VERT;
test_clic_boutons(&bt_LST );
if(bt_LST.cliked)
{
if (SDcardOk == false) { affi_message ( "SDcard absente", "...", "", "", "" ); return; }
bt_LST.cliked = false;
bt_LST.selected = false;
bt_LST.affiche( c1, 1);
SD_listFiles();
init_1_bouton(1, 300, 5, 15, 15, "OK", &bt_annuler);
attente_clic2();
TFT.fillScreen(NOIR);
groupe_SW.affiche_bloc("SW",0);
groupe_FM.affiche_bloc("FM",100);
groupe_AIR.affiche_bloc("AIR",200);
init_1_bouton(1, 300, 5, 15, 15, "OK", &bt_annuler);
attente_clic2();
mute = true;
Set_Mute(true); // fonction située dans le fichier 'driverTEF6686_628.h'
delay(50);
bt_mute.selected = true;
bt_mute.affiche(ROUGE, 1);
delay(500);
affi_deroulant("Liste codes PI RDS", "/RDS_codes_PI.lst");
retour_normal();
}
}
void test_clic_bouton_SD_write() // en SD, dans un des fichiers ("/FRQ_SW.txt" ...)
{
uint16_t c1 = GRIS_6;
uint16_t c2 = VERT;
String s1;
test_clic_boutons(&bt_SD_write );
if(bt_SD_write.cliked)
{
bt_SD_write.cliked=false;
bt_SD_write.selected=false;
bt_SD_write.affiche( GRIS_5, 1);
Serial.println("--------------------------------");
Serial.println("bouton_SD_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 SD
File file = SD.open("/FRQ_SW.txt", FILE_APPEND);
file.print(s1);
file.print('\n');
file.close(); // enregistre CE fichier en mémoire SD, sans toucher aux autres
delay(300);
ok = true;
}
}
if (bande_FM)
{
if (! groupe_FM.test_Frq_presente(frequence))
{
File file = SD.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 = SD.open("/FRQ_AIR.txt", FILE_APPEND);
file.print(s1);
file.close();
delay(300);
ok = true;
}
}
String s1, s2;
if (ok) {s1 = "Enregistrement OK"; s2 = ""; }
else {s1 = "Freq. deja presente"; s2 = "NOT SAVE";}
Serial.println(s1);
if (ok) {load_GRP_FREQ_SD();} // recharge les listes de fréquences depuis la SD pour être à jour
TFT.fillScreen(NOIR);
TFT.setTextColor(JAUNE, NOIR);
TFT.setFreeFont(FF1);
TFT.drawString(s1, 5, 40);
TFT.drawString(s2, 5, 60);
delay(1000);
retour_normal();
}
}
void test_clic_bt_erase_1F() // en SD
{
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(c1, 1);
delay (100);
bt_erase_1F.cliked = false;
bt_erase_1F.selected = false;
bt_erase_1F.affiche(c2, 1); // fugitif
uint16_t F;
//todo: en SD
}
}
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
{
presetPad1.deselect_boutons();
mode_s = _FRQ;
affiche_index_frq();
bt_4.selected=true; // 100kHz
bt_4.affiche(c2, 1);
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(c2, 2);
bt_mode_MEM.affiche(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(VERT ,1);
bt_plus.affiche(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+1, 118, 12, NOIR); // efface
efface_box_entete2();
//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);
frequence = 15000; // 15MHz
Tune_Frequence(frequence);
affiche_frequence(frequence);
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");
efface_box_entete2();
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;
affi_boutons_SW_FM_AIR_SCN();
//traite_boutons_presetPad(0);
frequence = presetPad1.bt_preset[0].frequence_FM;
Tune_Frequence(frequence);
affiche_frequence(frequence);
clic_logiciel_bouton(&presetPad1.bt_preset[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+1, 118, 12, NOIR); // efface
efface_box_entete2();
//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;
affi_boutons_SW_FM_AIR_SCN();
frequence = 123500;
Tune_Frequence(frequence);
affiche_frequence(frequence);
//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)
{
efface_box_entete2();
Serial.println("bt_SCN.cliked");
bt_SCN.cliked = false;
groupe_actif = gSCN;
bande_active = SCN;
bt_SCN.selected = true;
bt_SW.selected = false;
bt_FM.selected = false;
bt_AIR.selected = false;
affi_boutons_SW_FM_AIR_SCN();
presetPad1.deselect_boutons();
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 SD
// 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(1, x0_box_info2+82, y0_box_info2+50, 50, 15, "annuler", &bt_annuler);
bt_annuler.affiche(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(BLANC, 1);
}
}
void affi_bargraph(uint16_t x, uint16_t y, uint16_t dx, int16_t vi)
{
if(! quiet)
{
//TFT.fillRect(x, y, dx, 8, NOIR); // efface
if (valeur_bargraph < vi) {valeur_bargraph ++;} // pour déplassements progressifs
if (valeur_bargraph > vi) {valeur_bargraph --;} // pour déplassements progressifs
if(valeur_bargraph<0) {valeur_bargraph =0;}
if(valeur_bargraph > dx) {valeur_bargraph = dx;}
TFT.drawRect(x, y, dx, 5, couleur_traits);
//TFT.fillRect(x, y, valeur_bargraph, 5, JAUNE);
TFT.fillRect(x + valeur_bargraph, y, 1, 5, VERT); // affiche juste l'extrémité
TFT.fillRect(x + valeur_bargraph+1, y, 1, 5, NOIR); // efface juste l'extrémité +1
}
else
{
TFT.fillRect(x, y, dx, 5, couleur_fond_ecran); // efface le bargraph
}
}
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);
TFT.drawRect(0, 0, 319, 240, couleur_traits); // cadre principal pourtour de l'écran
}
/*
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 !!!)
*/
char buffer1[64];
uint16_t nombre =0;
String s_recue, s1, s2, s3;
s_recue = int_to_hex(A_block); // exemple: 'F201' ; mis à jour par le 'Get_RDS_Data()'
if (s_recue == memo_s_recue) {return; } // puisque rien de nouveau à traiter
memo_s_recue = s_recue;
TFT.fillRect(x0_box_info1+2, y0_box_info1, 118, 16, NOIR); // efface (en bas à gauche)
TFT.setTextColor(BLEU_CLAIR, GRIS_6);
TFT.setFreeFont(FF0);
File file1 = SD.open("/RDS_codes_PI.lst", "r");
while (file1.available())
{
int nb_bytes = file1.readBytesUntil('\n', buffer1, sizeof(buffer1));
buffer1[nb_bytes] = 0; // zéro terminal afin d'obtenir un string
s1 = buffer1;
s2 = s1.substring(0, 4); // exemple: 'F218'
s3 = s1.substring(4); // la suite
if (s_recue == s2) // la station reçue figure dans la liste
{
TFT.setTextColor(JAUNE, GRIS_6);
TFT.drawString(s2, x0_box_info1+5, y0_box_info1 +4);
TFT.setTextColor(BLEU_CLAIR, GRIS_6);
TFT.drawString(s3, x0_box_info1+30, y0_box_info1 +4);
return; // on ne continue pas à boucler si trouvé
}
}
}
void affiche_force_signal()
{
//----------------------------------------------------------------------------------------------------------
// AFFICHE FORCE SIGNAL HF
compteur1 =0;
//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;
//affi_bargraph(170, 90, 60, mod/2);
if ((mode_affi == NORMAL) && (! mute) && (! quiet))
{
plotAiguille(position_aiguille/6.0); // génère des parasites audibles !
}
if ((mode_affi == NORMAL) && (mute) )
{
//plotAiguille(0);
}
}
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())
{
memo_y_touch = y_touch;
get_XY_touch();
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_SD_RAZ();
test_clic_bouton_SD_write();
test_clic_bouton_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_bt_LED();
test_clic_bt_CAL(); // calibration de l'écran tactile
test_clic_bt_quiet();
test_clic_bouton_TEST();
test_clic_bouton_info();
test_clic_bt_capture(); // capture écran
test_clic_Bt_reset();
test_clic_Bt_SCAN(); // choix bande à scanner (SW - FM) et type FRQ ou AIR (puis déclenche le scan)
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_coul();
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
uint8_t module;
if(bande_active == FM) {module = 32;} else {module = 33;}
Get_Quality( module, &status, &level, &usn, &wam, &offset, &bandwidth, &mod, &snr );
affi_bargraph(170, 90, 60, mod/2);
if (compteur1 >= 20)
{
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;
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();}
}
if (quiet == true)
{
affi_image_from_SD("/bmp565/montagne140x70.bmp", x0_vu_metre, y0_vu_metre);
attente_clic2();
// quiet (anti-parasites audio, surtout pour les stations faibles)
// inconvéniants: fige les affichages (vu_metre, bargraph signal audio...)
}
/*
if (compteur3 >= 1000)
{
// passe en mode quiet automatiquement, avec ses inconvéniants !
compteur3 =0;
bt_quiet.cliked = false;
bt_quiet.selected = true;
bt_quiet.affiche(VERT, 1);
attente_clic2(); // quiet (anti-parasites)
bt_quiet.cliked = false;
bt_quiet.selected = false;
bt_quiet.affiche(VERT, 1);
}
*/
delay(5); // détermine la réactivité du bargraph
compteur1++;
compteur2++;
compteur3++;
}
}
/** ***************************************************************************************
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()
{
}
// Constructeur
TOUCH_BOUTON_SW::TOUCH_BOUTON_SW()
{
}
void TOUCH_BOUTON::init(uint16_t x_i, uint16_t y_i, uint8_t dx_i, uint8_t dy_i, uint8_t dr_i, uint16_t couleur_i)
{
x0 = x_i;
y0 = y_i;
dx = dx_i;
dy = dy_i;
dr = dr_i;
couleur = couleur_i;
cliked = false;
selected = false;
}
void TOUCH_BOUTON::affiche(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, couleur); // efface
TFT.drawRoundRect(x0, y0, dx, dy, dr, couleur_contour); // retrace juste le contour
TFT.setTextColor(couleur_texte);
}
//FM9 FMB9 FSS9... voir le fichier FrSD_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(label, x0+3, y0 + 2);
}
uint8_t TOUCH_BOUTON::read_dx()
{
return dx;
}
uint8_t TOUCH_BOUTON::read_dy()
{
return dy;
}
/** ***************************************************************************************
CLASS grid_PAD
********************************************************************************************/
// Constructeur
GRID_PAD::GRID_PAD()
{
}
void GRID_PAD::init(uint16_t xi, uint16_t yi)
{
x0 = xi;
y0 = yi;
uint16_t x, y;
x = x0+2;
y = y0+1;
for(uint8_t n =1; n <= nb_t; n++)
{
bt_grid[n].init(x, y, dxt, dyt, 3, n * 100);
bt_grid[n].label="";
//bt_grid[n].affiche(BLEU, 1);
x += dxt+1;
if (x > (x0 + nb_bt_x * dxt)) {x = x0+2; y += dyt+1; }
}
}
void GRID_PAD::affiche()
{
for(uint8_t n =1; n <= nb_t; n++)
{
bt_grid[n].affiche(BLEU, 1);
}
}
void GRID_PAD::set_couleurs() // F = facteur d'assombrissement
{
/*
voir la page:
https://rgbcolorpicker.com/565
qui permet de reconfigurer les couleurs RGB565 (5+6+5 = 16 bits) très simplement
*/
uint16_t c565i, c565i2;
uint8_t R, G, B;
int16_t j, k;
// les deux premières lignes couleurs arc-en-ciel
k=-16;
uint8_t F=1;
for(uint8_t n=0; n<32; n++)
{
j=30*(32-n);
c565i = couleurs_aec[2*j] | couleurs_aec[2*j+1]<<8;
RGB565_to_888(c565i, &R, &G, &B);
R /= F;
G /= F;
B /= F;
c565i2 = Color_To_565(R, G, B);
if((k>=0) && (k<16)) {bt_grid[k].couleur = c565i2;}
k++;
}
// les lignes 3 et 4 couleurs plus sombres
k=0;
F=3;
for(uint8_t n=0; n<32; n++)
{
j=30*(32-n);
c565i = couleurs_aec[2*j] | couleurs_aec[2*j+1]<<8;
RGB565_to_888(c565i, &R, &G, &B);
R /= F;
G /= F;
B /= F;
c565i2 = Color_To_565(R, G, B);
if((k>=16) && (k<32)) {bt_grid[k].couleur = c565i2;}
k++;
}
bt_grid[16].couleur = 49174; // violet
//bt_grid[25].couleur = 0b1111100000000000; // R
//bt_grid[26].couleur = 0b0000011111100000; // V
//bt_grid[27].couleur = 0b0000000000011111; // B
//bt_grid[28].couleur = 0xFFFF;
//bt_grid[29].couleur = 0;
bt_grid[32].couleur = GRIS_4;
bt_grid[32].label="X";
}
uint8_t GRID_PAD::test_clic()
{
if ( (( x_touch > x0) && (x_touch < (x0 + dxt*nb_bt_x +20))) && (( y_touch > y0) && (y_touch < (y0 + dyt*nb_bt_y +10))))
{
uint8_t num_bouton =255;
for(uint8_t n = 0; n<nb_t; n++)
{
test_clic_boutons(&bt_grid[n] );
if(bt_grid[n].cliked)
{
num_bouton = n;
}
}
delay(100);
return num_bouton;
}
return 253;
}
/** ***************************************************************************************
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, GRIS_5);
bt_pad[n].label=String(n);
bt_pad[n].affiche(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, GRIS_5); bt_pad[0].label="0"; bt_pad[0].affiche(c2, 2); x += dxt+1;
bt_point.init(x, y, dxt, dyt, 3, GRIS_5); bt_point.label="."; bt_point.affiche(c2, 2);
x += dxt+1;
bt_ok.init(x, y, dxt, dyt, 3, GRIS_5); bt_ok.label="ok";
bt_ok.affiche(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, GRIS_5);
bt_preset[n].label=String(n+1);
if(mode_affi == COUL) {c1 = bt_preset[n].couleur;}
bt_preset[n].affiche(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 SD et les attribue à chaque bouton PRESET
{
Serial.println("void PRESET_PAD::set_frequences()");
uint8_t n=0;
read_FRQ_File(SD, "/FRQ_SW_PRST.txt", "SW");
read_FRQ_File(SD, "/FRQ_FM_PRST.txt", "FM");
read_FRQ_File(SD, "/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 = 28672; // rouge sombre
bt_preset[1].couleur = 43584; // orange
bt_preset[2].couleur = 832; // vert
bt_preset[3].couleur = 14407; // violet
bt_preset[4].couleur = 58157; // rose
bt_preset[5].couleur = 975; // cyan
bt_preset[6].couleur = 21819; // bleu ciel
bt_preset[7].couleur = 12; // 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(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(JAUNE, 1);
num_bouton = n;
//Serial.print("BB num_bouton= "); Serial.println(num_bouton);
}
}
delay(300);
return num_bouton;
}
return 253;
}
/** ***************************************************************************************
CLASS SW_PAD
********************************************************************************************/
// Constructeur
SW_PAD::SW_PAD()
{
}
void SW_PAD::init(uint16_t xi, uint16_t yi)
{
x0 = xi;
y0 = yi;
uint16_t x2, y2;
x2 = x0;
y2 = y0;
set_frequences_SW();
for(uint8_t n=0; n<14; n++)
{
bt_SW[n].init(x2, y2, 30, 12, 3, GRIS_5);
String sA = String(bt_SW[n].freq_A);
String sB = String(bt_SW[n].freq_B);
bt_SW[n].affiche(JAUNE, 1);
TFT.setTextColor(CYAN, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString(sA + "..", x2+35, y2);
TFT.drawString(sB, x2+80, y2);
if (n==0) {TFT.drawString("kHz", x2+110, y0);}
y2 += 16;
}
}
void SW_PAD::set_frequences_SW()
{
// bandes plus larges que les 'bandes officielles de radiodiffusion' afin de couvrir tt les frq sans trous
bt_SW[0].freq_A=2300; bt_SW[0].freq_B=3200; bt_SW[0].lambda=120;
bt_SW[1].freq_A=3200; bt_SW[1].freq_B=3900; bt_SW[1].lambda=90;
bt_SW[2].freq_A=3900; bt_SW[2].freq_B=4750; bt_SW[2].lambda=75;
bt_SW[3].freq_A=4750; bt_SW[3].freq_B=5950; bt_SW[3].lambda=60;
bt_SW[4].freq_A=5950; bt_SW[4].freq_B=7100; bt_SW[4].lambda=49;
bt_SW[5].freq_A=7100; bt_SW[5].freq_B=9500; bt_SW[5].lambda=41;
bt_SW[6].freq_A=9500; bt_SW[6].freq_B=11650; bt_SW[6].lambda=31;
bt_SW[7].freq_A=11650; bt_SW[7].freq_B=13600; bt_SW[7].lambda=25;
bt_SW[8].freq_A=13600; bt_SW[8].freq_B=15100; bt_SW[8].lambda=22;
bt_SW[9].freq_A=15100; bt_SW[9].freq_B=17550; bt_SW[9].lambda=19;
bt_SW[10].freq_A=17550; bt_SW[10].freq_B=18900; bt_SW[10].lambda=16;
bt_SW[11].freq_A=18900; bt_SW[11].freq_B=21450; bt_SW[11].lambda=15;
bt_SW[12].freq_A=21450; bt_SW[12].freq_B=25670; bt_SW[12].lambda=13;
bt_SW[13].freq_A=25670; bt_SW[13].freq_B=27900; bt_SW[13].lambda=11;
for(int n =0; n<=13; n++)
{
bt_SW[n].label = String(bt_SW[n].lambda) + "m";
}
}
uint8_t SW_PAD::test_clic()
{
if ( (( x_touch > x0) && (x_touch < (x0+40))) && (( y_touch > y0) && (y_touch < 240)))
{
uint8_t num_bouton =0;
for(uint8_t n=0; n<=13; n++)
{
test_clic_boutons(&bt_SW[n]);
if(bt_SW[n].cliked)
{
deselect_boutons(); // les autres
bt_SW[n].selected =true; // pour l'affichage de celui-ci
bt_SW[n].affiche(JAUNE, 1);
num_bouton = n;
}
}
delay(300);
return num_bouton;
}
return 253;
}
void SW_PAD::deselect_boutons()
{
uint16_t c1 = GRIS_5;
uint16_t c2 = JAUNE;
for(int n =0; n<=13; n++)
{
bt_SW[n].selected=false;
bt_SW[n].cliked=false;
bt_SW[n].affiche(c2, 1);
}
}
/** ***************************************************************************************
CLASS GROUPE_FREQUENCES // objet image d'un bloc mémoire en SD
permet diverses manipulations en RAM (tri...) sans toucher à la SD (é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 SDcard --> vers groupe en RAM
{
Serial.println("--------------------------");
Serial.println("GROUPE_FREQUENCES::load_bloc()");
Serial.print("Reading file: "); Serial.println(filename);
File file = SD.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 SD
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]);
}
// voir la fonction 'void affi_liste()// des aérodromes' du ND.ino
void GROUPE_FREQUENCES::affiche_bloc(String nom, uint16_t x)
{
// travaille en RAM uniquement, sans toucher aux fichiers SD
uint32_t valeur_lue;
uint16_t nombre =0;
uint16_t y;
String s1;
TFT.setTextColor(BLANC, NOIR);
TFT.setFreeFont(FF0);
TFT.drawString(nom, x, 0);
y=20;
for(uint16_t n = 0; n<100; n++ )
{
valeur_lue = G_freq[n];
if(valeur_lue != 0) // n'affiche pas les emplacements vides
{
nombre++;
s1 = String(nombre);
TFT.setTextColor(BLEU, NOIR);
TFT.drawString(s1, x, y);
s1 = valeur_lue;
TFT.setTextColor(BLANC, NOIR);
TFT.drawString(s1, x+20, y);
y+=10;
}
}
Serial.print(nombre); Serial.println(" frequences");
}
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();
}