1+ #pragma once
2+
3+ #include " Screen.h"
4+ #include " fonts/GillSans_25_vlw.h"
5+ #include < vector>
6+ #include < cmath>
7+
8+ class TestScreen : public Screen {
9+ private:
10+ // HSV to RGB conversion (returns 8-bit per channel)
11+ void hsvToRgb (float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
12+ float c = v * s;
13+ float x = c * (1 - fabs (fmod (h / 60.0 , 2 ) - 1 ));
14+ float m = v - c;
15+ float r1, g1, b1;
16+ if (h < 60 ) { r1 = c; g1 = x; b1 = 0 ; }
17+ else if (h < 120 ) { r1 = x; g1 = c; b1 = 0 ; }
18+ else if (h < 180 ) { r1 = 0 ; g1 = c; b1 = x; }
19+ else if (h < 240 ) { r1 = 0 ; g1 = x; b1 = c; }
20+ else if (h < 300 ) { r1 = x; g1 = 0 ; b1 = c; }
21+ else { r1 = c; g1 = 0 ; b1 = x; }
22+ r = (uint8_t )((r1 + m) * 255 );
23+ g = (uint8_t )((g1 + m) * 255 );
24+ b = (uint8_t )((b1 + m) * 255 );
25+ }
26+
27+ void drawHSVGradient () {
28+ m_tft.startWrite ();
29+ int w = m_tft.width ();
30+ int h = m_tft.height ();
31+ std::vector<uint16_t > rowBuf (w);
32+ for (int y = 0 ; y < h; ++y) {
33+ float v = 1 .0f ;
34+ float s = 1 .0f - (float )y / (h - 1 );
35+ for (int x = 0 ; x < w; ++x) {
36+ float hue = 360 .0f * x / (w - 1 );
37+ uint8_t r, g, b;
38+ hsvToRgb (hue, s, v, r, g, b);
39+ rowBuf[x] = Display::swapBytes (Display::color565 (r, g, b));
40+ }
41+ m_tft.setWindow (0 , y, w - 1 , y);
42+ m_tft.pushPixels (rowBuf.data (), w);
43+ }
44+ m_tft.endWrite ();
45+ }
46+
47+ // Generate a square wave buffer for a note (frequency in Hz, duration in ms)
48+ std::vector<uint8_t > generateNoteBuffer (float freq, int durationMs, int sampleRate = 15600 ) {
49+ int samples = (sampleRate * durationMs) / 1000 ;
50+ std::vector<uint8_t > buf (samples);
51+ int period = (int )(sampleRate / freq / 2 );
52+ for (int i = 0 ; i < samples; ++i) {
53+ buf[i] = (i / period) % 2 ? 255 : 0 ;
54+ }
55+ return buf;
56+ }
57+
58+ // Play a sequence of notes: 'a', 'b', 'c', 'd'
59+ void playNotes () {
60+ struct Note { float freq; int duration; };
61+ // Frequencies for notes a, b, c, d (approximate, in Hz)
62+ Note notes[] = {
63+ {440 .0f , 180 }, // A4
64+ {493 .88f , 180 }, // B4
65+ {523 .25f , 180 }, // C5
66+ {587 .33f , 180 } // D5
67+ };
68+ if (!m_files->isAvailable (StorageType::SD)) {
69+ // Play notes in reverse order if SD card is not mounted
70+ for (int i = 3 ; i >= 0 ; --i) {
71+ auto buf = generateNoteBuffer (notes[i].freq , notes[i].duration );
72+ if (m_audioOutput) m_audioOutput->write (buf.data (), buf.size ());
73+ }
74+ } else {
75+ // Play notes in normal order if SD card is mounted
76+ for (int i = 0 ; i < 4 ; ++i) {
77+ auto buf = generateNoteBuffer (notes[i].freq , notes[i].duration );
78+ if (m_audioOutput) m_audioOutput->write (buf.data (), buf.size ());
79+ }
80+ }
81+ }
82+
83+ public:
84+ TestScreen (Display &tft, HDMIDisplay *hdmiDisplay, AudioOutput *audioOutput, IFiles *files)
85+ : Screen(tft, hdmiDisplay, audioOutput, files) {}
86+
87+ void didAppear () override {
88+ drawHSVGradient ();
89+ m_tft.loadFont (GillSans_25_vlw);
90+ std::string msg = " Test Screen and Audio" ;
91+ auto textSize = m_tft.measureString (msg.c_str ());
92+ int textX = (m_tft.width () - textSize.x ) / 2 ;
93+ int textY = 20 ;
94+ m_tft.fillRect (textX-5 , textY-5 , textSize.x +10 , textSize.y +10 , TFT_BLACK);
95+ m_tft.setTextColor (TFT_WHITE, TFT_BLACK);
96+ m_tft.drawString (msg.c_str (), textX, textY);
97+
98+ // SD card status
99+ std::string sdMsg;
100+ uint16_t sdColor;
101+ if (m_files && m_files->isAvailable (StorageType::SD)) {
102+ sdMsg = " SD Card: Mounted" ;
103+ sdColor = TFT_GREEN;
104+ } else {
105+ sdMsg = " SD Card: Not Mounted" ;
106+ sdColor = TFT_RED;
107+ }
108+ auto sdSize = m_tft.measureString (sdMsg.c_str ());
109+ int sdX = (m_tft.width () - sdSize.x ) / 2 ;
110+ int sdY = m_tft.height ()/2 - 20 ;
111+ m_tft.fillRect (sdX-5 , sdY-5 , sdSize.x +10 , sdSize.y +10 , TFT_BLACK);
112+ m_tft.setTextColor (sdColor, TFT_BLACK);
113+ m_tft.drawString (sdMsg.c_str (), sdX, sdY);
114+
115+ std::string footer = " Press any key to return" ;
116+ auto footerSize = m_tft.measureString (footer.c_str ());
117+ int footerX = (m_tft.width () - footerSize.x ) / 2 ;
118+ int footerY = m_tft.height () - 40 ;
119+ m_tft.fillRect (footerX-5 , footerY-5 , footerSize.x +10 , footerSize.y +10 , TFT_BLACK);
120+ m_tft.setTextColor (TFT_WHITE, TFT_BLACK);
121+ m_tft.drawString (footer.c_str (), footerX, footerY);
122+ playNotes ();
123+ }
124+
125+ void pressKey (SpecKeys key) override {
126+ m_navigationStack->pop ();
127+ }
128+ };
0 commit comments