From 175f9c46363aeae18b306d20e6c2ad0b41a640c3 Mon Sep 17 00:00:00 2001 From: eadmaster <925171+eadmaster@users.noreply.github.com> Date: Tue, 6 Aug 2024 04:00:41 +0200 Subject: [PATCH 1/5] =?UTF-8?q?extension-based=20comman=C4=91s=20for=20the?= =?UTF-8?q?=20file=20browser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/mykeyboard.cpp | 4 + src/core/sd_functions.cpp | 46 +++++++-- src/modules/ir/TV-B-Gone.cpp | 10 +- src/modules/others/audio.cpp | 182 +++++++++++++++++------------------ src/modules/rf/rf.cpp | 20 ++-- 5 files changed, 149 insertions(+), 113 deletions(-) diff --git a/src/core/mykeyboard.cpp b/src/core/mykeyboard.cpp index f5b1ffdf..514101e9 100644 --- a/src/core/mykeyboard.cpp +++ b/src/core/mykeyboard.cpp @@ -1,10 +1,12 @@ #include "mykeyboard.h" #include "powerSave.h" +#include "sd_functions.h" #include "modules/ir/TV-B-Gone.h" #include "modules/rf/rf.h" #include "modules/others/bad_usb.h" #include "modules/others/webInterface.h" + #if defined(HAS_TOUCH) struct box_t { @@ -176,6 +178,8 @@ void checkShortcutPress(){ if(Keyboard.isKeyPressed('r') || Keyboard.isKeyPressed('s')) otherRFcodes(); if(Keyboard.isKeyPressed('b')) usb_setup(); // badusb if(Keyboard.isKeyPressed('w')) loopOptionsWebUi(); + if(Keyboard.isKeyPressed('f')) { setupSdCard() ? loopSD(SD) : loopSD(LittleFS); } + if(Keyboard.isKeyPressed('l')) loopSD(LittleFS); // TODO: other boards? // TODO: user-configurable } diff --git a/src/core/sd_functions.cpp b/src/core/sd_functions.cpp index 126a5bf8..73db0b45 100644 --- a/src/core/sd_functions.cpp +++ b/src/core/sd_functions.cpp @@ -2,7 +2,10 @@ #include "sd_functions.h" #include "mykeyboard.h" // usinf keyboard when calling rename #include "display.h" // using displayRedStripe as error msg -#include "../modules/others/audio.h" +#include "modules/others/audio.h" +#include "modules/rf/rf.h" +#include "modules/ir/TV-B-Gone.h" +#include "modules/others/bad_usb.h" struct FilePage { int pageIndex; @@ -27,6 +30,10 @@ bool setupSdCard() { sdcardMounted = false; return false; } + + // avoid unnecessary remounting + if(sdcardMounted) return true; + #if TFT_MOSI == SDCARD_MOSI if (!SD.begin(SDCARD_CS)) #else @@ -410,12 +417,15 @@ String loopSD(FS &fs, bool filePicker, String allowed_ext) { tft.drawRoundRect(5,5,WIDTH-10,HEIGHT-10,5,FGCOLOR); closeSdCard(); setupSdCard(); + bool exit = false; + returnToMenu=true; // make sure menu is redrawn when quitting in any point readFs(fs, Folder, fileList, allowed_ext); for(int i=0; iLittleFS", [=]() { copyToFs(SD,LittleFS, fileList[index][1]); }}); if(&fs == &LittleFS && sdcardMounted) options.push_back({"Copy->SD", [=]() { copyToFs(LittleFS, SD, fileList[index][1]); }}); + // custom file formats commands added in front + if(fileList[index][1].endsWith(".ir")) options.insert(options.begin(), {"IR Tx SpamAll", [&]() { + delay(200); + txIrFile(&fs, fileList[index][1]); + }}); + if(fileList[index][1].endsWith(".sub")) options.insert(options.begin(), {"Subghz Tx", [&]() { + delay(200); + txSubFile(&fs, fileList[index][1]); + }}); + if(fileList[index][1].endsWith(".txt")) options.insert(options.begin(), {"BadUSB Run", [&]() { + Kb.begin(); + USB.begin(); + key_input(fs, fileList[index][1]); + }}); #if defined(HAS_NS4168_SPKR) - if(isAudioFile(fileList[index][1])) options.push_back({"Play Audio", [=]() { - playAudioFile(const_cast(&fs), fileList[index][1]); + if(isAudioFile(fileList[index][1])) options.insert(options.begin(), {"Play Audio", [&]() { + delay(200); + playAudioFile(&fs, fileList[index][1]); setup_gpio(); //TODO: remove after fix select loop - }}); #endif - options.push_back({"Main Menu", [=]() { backToMenu(); }}); + options.push_back({"Main Menu", [&]() { exit = true; }}); delay(200); if(!filePicker) loopOptions(options); else { @@ -592,6 +616,8 @@ void viewFile(FS fs, String filepath) { file = fs.open(filepath, FILE_READ); if (!file) return; + + // TODO: detect binary file, switch to hex view while (file.available()) { fileContent = file.readString(); diff --git a/src/modules/ir/TV-B-Gone.cpp b/src/modules/ir/TV-B-Gone.cpp index 831ed523..1172301d 100644 --- a/src/modules/ir/TV-B-Gone.cpp +++ b/src/modules/ir/TV-B-Gone.cpp @@ -402,6 +402,8 @@ void otherIRcodes() { FS *fs = NULL; struct Codes selected_code; + returnToMenu = true; // make sure menu is redrawn when quitting in any point + options = { {"Recent", [&]() { selected_code = selectRecentIrMenu(); }}, {"LittleFS", [&]() { fs=&LittleFS; }}, @@ -411,7 +413,7 @@ void otherIRcodes() { delay(200); loopOptions(options); delay(200); - + if(fs == NULL) { // recent menu was selected if(selected_code.filepath!="") { // a code was selected, switch on code type if(selected_code.type=="raw") sendRawCommand(selected_code.frequency, selected_code.data); @@ -453,8 +455,8 @@ void otherIRcodes() { if (!databaseFile) { Serial.println("Failed to open database file."); - displayError("Fail to open file"); - delay(2000); + //displayError("Fail to open file"); + //delay(2000); return; } Serial.println("Opened database file."); @@ -499,8 +501,6 @@ void otherIRcodes() { if(checkEscPress() || exit) break; delay(200); } - - returnToMenu=true; } // end of otherIRcodes diff --git a/src/modules/others/audio.cpp b/src/modules/others/audio.cpp index 159c5556..934eb180 100644 --- a/src/modules/others/audio.cpp +++ b/src/modules/others/audio.cpp @@ -1,5 +1,6 @@ #include "audio.h" #include +#include #include #include "core/mykeyboard.h" @@ -7,114 +8,113 @@ #if defined(HAS_NS4168_SPKR) bool playAudioFile(FS* fs, String filepath) { - - AudioOutputI2S* audioout = new AudioOutputI2S(); // https://github.com/earlephilhower/ESP8266Audio/blob/master/src/AudioOutputI2S.cpp#L32 - audioout->SetPinout(BCLK, WCLK, DOUT); - - AudioFileSource* source = new AudioFileSourceFS(*fs, filepath.c_str()); - if(!source) return false; - - AudioGenerator* generator = NULL; + + AudioFileSource* source = new AudioFileSourceFS(*fs, filepath.c_str()); + if(!source) return false; + + AudioOutputI2S* audioout = new AudioOutputI2S(); // https://github.com/earlephilhower/ESP8266Audio/blob/master/src/AudioOutputI2S.cpp#L32 + audioout->SetPinout(BCLK, WCLK, DOUT); - // switch on extension - filepath.toLowerCase(); // case-insensitive match - if (filepath.endsWith(".txt") || filepath.endsWith(".rtttl")) - generator = new AudioGeneratorRTTTL(); - if (filepath.endsWith(".wav")) - generator = new AudioGeneratorWAV(); - if (filepath.endsWith(".mod")) - generator = new AudioGeneratorMOD(); - if (filepath.endsWith(".mp3")) { - generator = new AudioGeneratorMP3(); - source = new AudioFileSourceID3(source); - } - if (filepath.endsWith(".opus")) generator = new AudioGeneratorOpus(); - /* 2FIX: compilation issues - if(song.endsWith(".mid")) { - // need to load a soundfont - AudioFileSource* sf2 = NULL; - if(setupSdCard()) sf2 = new AudioFileSourceSD("1mgm.sf2"); // TODO: make configurable - if(!sf2) sf2 = new AudioFileSourceLittleFS("1mgm.sf2"); // TODO: make configurable - if(sf2) { - // a soundfount was found - AudioGeneratorMIDI* midi = new AudioGeneratorMIDI(); - generator->SetSoundfont(sf2); - generator = midi; - } - }*/ - - if (generator && source && audioout) { - Serial.println("Start audio"); - generator->begin(source, audioout); - while (generator->isRunning()) { - if (!generator->loop()) generator->stop(); // || checkEscPress() - - } - audioout->stop(); - source->close(); - Serial.println("Stop audio"); + AudioGenerator* generator = NULL; - delete generator; - delete source; - delete audioout; - - return true; + // switch on extension + filepath.toLowerCase(); // case-insensitive match + if (filepath.endsWith(".txt") || filepath.endsWith(".rtttl")) + generator = new AudioGeneratorRTTTL(); + if (filepath.endsWith(".wav")) + generator = new AudioGeneratorWAV(); + if (filepath.endsWith(".mod")) + generator = new AudioGeneratorMOD(); + if (filepath.endsWith(".opus")) + generator = new AudioGeneratorOpus(); + if (filepath.endsWith(".mp3")) { + generator = new AudioGeneratorMP3(); + source = new AudioFileSourceID3(source); + } + /* 2FIX: compilation issues + if(filepath.endsWith(".mid")) { + // need to load a soundfont + AudioFileSource* sf2 = NULL; + if(setupSdCard()) sf2 = new AudioFileSourceFS(SD, "1mgm.sf2"); // TODO: make configurable + if(!sf2) sf2 = new AudioFileSourceLittleFS(LittleFS, "1mgm.sf2"); // TODO: make configurable + if(!sf2) return false; // a soundfount was not found + AudioGeneratorMIDI* midi = new AudioGeneratorMIDI(); + midi->SetSoundfont(sf2); + generator = midi; + } */ + + if (generator && source && audioout) { + Serial.println("Start audio"); + generator->begin(source, audioout); + while (generator->isRunning()) { + if (!generator->loop() || checkAnyKeyPress() ) generator->stop(); } + audioout->stop(); + source->close(); + Serial.println("Stop audio"); + + delete generator; + delete source; + delete audioout; - return false; // init error + return true; + } + // else + return false; // init error } bool playAudioRTTTLString(String song) { - // derived from https://github.com/earlephilhower/ESP8266Audio/blob/master/examples/PlayRTTTLToI2SDAC/PlayRTTTLToI2SDAC.ino - - song.trim(); - if(song=="") return false; - - AudioOutputI2S* audioout = new AudioOutputI2S(); - audioout->SetPinout(BCLK, WCLK, DOUT); - - AudioGenerator* generator = new AudioGeneratorRTTTL(); - - AudioFileSource* source = new AudioFileSourcePROGMEM( song.c_str(), song.length() ); + // derived from https://github.com/earlephilhower/ESP8266Audio/blob/master/examples/PlayRTTTLToI2SDAC/PlayRTTTLToI2SDAC.ino + + song.trim(); + if(song=="") return false; + + AudioOutputI2S* audioout = new AudioOutputI2S(); + audioout->SetPinout(BCLK, WCLK, DOUT); + + AudioGenerator* generator = new AudioGeneratorRTTTL(); + + AudioFileSource* source = new AudioFileSourcePROGMEM( song.c_str(), song.length() ); - if (generator && source && audioout) { - Serial.println("Start audio"); - generator->begin(source, audioout); - while (generator->isRunning()) { - if (!generator->loop()) generator->stop(); - } - audioout->stop(); - source->close(); - Serial.println("Stop audio"); - - delete generator; - delete source; - delete audioout; - - return true; + if (generator && source && audioout) { + Serial.println("Start audio"); + generator->begin(source, audioout); + while (generator->isRunning()) { + if (!generator->loop() || checkAnyKeyPress() ) generator->stop(); } - return false; // init error + audioout->stop(); + source->close(); + Serial.println("Stop audio"); + + delete generator; + delete source; + delete audioout; + + return true; + } + // else + return false; // init error } bool tts(String text){ - text.trim(); - if(text=="") return false; - - AudioOutputI2S* audioout = new AudioOutputI2S(); - audioout->SetPinout(BCLK, WCLK, DOUT); - - // https://github.com/earlephilhower/ESP8266SAM/blob/master/examples/Speak/Speak.ino - audioout->begin(); - ESP8266SAM *sam = new ESP8266SAM; - sam->Say(audioout, text.c_str()); - delete sam; - return true; + text.trim(); + if(text=="") return false; + + AudioOutputI2S* audioout = new AudioOutputI2S(); + audioout->SetPinout(BCLK, WCLK, DOUT); + + // https://github.com/earlephilhower/ESP8266SAM/blob/master/examples/Speak/Speak.ino + audioout->begin(); + ESP8266SAM *sam = new ESP8266SAM; + sam->Say(audioout, text.c_str()); + delete sam; + return true; } bool isAudioFile(String filepath) { - return filepath.endsWith(".txt") || filepath.endsWith(".rtttl") || + return filepath.endsWith(".opus") || filepath.endsWith(".rtttl") || filepath.endsWith(".wav") || filepath.endsWith(".mod") || filepath.endsWith(".mp3") ; } #endif diff --git a/src/modules/rf/rf.cpp b/src/modules/rf/rf.cpp index cca9bbde..f7a0697f 100644 --- a/src/modules/rf/rf.cpp +++ b/src/modules/rf/rf.cpp @@ -668,6 +668,9 @@ void otherRFcodes() { FS *fs = NULL; String filepath = ""; struct RfCodes selected_code; + + returnToMenu=true; // make sure menu is redrawn when quitting in any point + options = { {"Recent", [&]() { selected_code = selectRecentRfMenu(); }}, {"LittleFS", [&]() { fs=&LittleFS; }}, @@ -677,18 +680,21 @@ void otherRFcodes() { delay(200); loopOptions(options); delay(200); - + if(fs == NULL) { // recent menu was selected if(selected_code.filepath!="") sendRfCommand(selected_code); // a code was selected return; // no need to proceed, go back } - - filepath = loopSD(*fs, true, "SUB"); - if(filepath=="") return; // cancelled - // else - txSubFile(fs, filepath); - returnToMenu=true; + + while (1) { + delay(200); + filepath = loopSD(*fs, true, "SUB"); + if(filepath=="" || checkEscPress()) return; // cancelled + // else trasmit the file + txSubFile(fs, filepath); + delay(200); + } } From dbf04b51fb37c3084ff392d3776f113d6ce0a7c0 Mon Sep 17 00:00:00 2001 From: eadmaster <925171+eadmaster@users.noreply.github.com> Date: Tue, 6 Aug 2024 04:07:10 +0200 Subject: [PATCH 2/5] fix for non-cardputer targets --- src/core/sd_functions.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/sd_functions.cpp b/src/core/sd_functions.cpp index 73db0b45..c0451b25 100644 --- a/src/core/sd_functions.cpp +++ b/src/core/sd_functions.cpp @@ -515,11 +515,13 @@ String loopSD(FS &fs, bool filePicker, String allowed_ext) { delay(200); txSubFile(&fs, fileList[index][1]); }}); + #if defined(USB_as_HID) if(fileList[index][1].endsWith(".txt")) options.insert(options.begin(), {"BadUSB Run", [&]() { Kb.begin(); USB.begin(); key_input(fs, fileList[index][1]); }}); + #endif #if defined(HAS_NS4168_SPKR) if(isAudioFile(fileList[index][1])) options.insert(options.begin(), {"Play Audio", [&]() { delay(200); From cba38b0ca207a87d70631bb55303cba0f982333c Mon Sep 17 00:00:00 2001 From: eadmaster <925171+eadmaster@users.noreply.github.com> Date: Tue, 6 Aug 2024 04:18:21 +0200 Subject: [PATCH 3/5] fix for broken qrcode menu --- src/modules/others/qrcode_menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/others/qrcode_menu.cpp b/src/modules/others/qrcode_menu.cpp index b6f33c3f..63a38d93 100644 --- a/src/modules/others/qrcode_menu.cpp +++ b/src/modules/others/qrcode_menu.cpp @@ -32,7 +32,7 @@ String calculate_crc(String input) { void qrcode_display(String qrcodeUrl) { -#ifdef DHAS_SCREEN +#ifdef HAS_SCREEN QRcode qrcode(&tft); qrcode.init(); From cda5ba1580b007bd9a12fa5172ca7acc5e7f3f63 Mon Sep 17 00:00:00 2001 From: eadmaster <925171+eadmaster@users.noreply.github.com> Date: Tue, 6 Aug 2024 08:50:22 +0200 Subject: [PATCH 4/5] added playTone and beep cmds (#113) --- src/core/globals.cpp | 7 ---- src/core/globals.h | 2 +- src/core/serialcmds.cpp | 15 +++++++ src/modules/others/audio.cpp | 76 +++++++++++++++++++++++++++++++++++- src/modules/others/audio.h | 6 ++- 5 files changed, 96 insertions(+), 10 deletions(-) diff --git a/src/core/globals.cpp b/src/core/globals.cpp index f649d943..f85ded4e 100644 --- a/src/core/globals.cpp +++ b/src/core/globals.cpp @@ -71,10 +71,3 @@ void updateTimeStr(struct tm timeInfo) { snprintf(timeStr, sizeof(timeStr), "%02d:%02d", timeInfo.tm_hour, timeInfo.tm_min); } -void _tone(unsigned int frequency, unsigned long duration = 0UL) { -#if defined(BUZZ_PIN) - tone(BUZZ_PIN, frequency, duration); -//#elif defined(HAS_NS4168_SPKR) -//TODO: alt. implementation using the speaker -#endif -} diff --git a/src/core/globals.h b/src/core/globals.h index aded9606..d977c99f 100644 --- a/src/core/globals.h +++ b/src/core/globals.h @@ -112,4 +112,4 @@ extern String wui_pwd; extern int tmz; void setup_gpio(); -void _tone(unsigned int frequency, unsigned long duration); + diff --git a/src/core/serialcmds.cpp b/src/core/serialcmds.cpp index 7e09386d..f12488f6 100644 --- a/src/core/serialcmds.cpp +++ b/src/core/serialcmds.cpp @@ -291,6 +291,21 @@ bool processSerialCommand(String cmd_str) { } #endif + #if defined(HAS_NS4168_SPKR) || defined(BUZZ_PIN) + if(cmd_str.startsWith("tone" ) || cmd_str.startsWith("beep" )) { + const char* args = cmd_str.c_str() + 4; + unsigned long frequency = 500UL; + unsigned long duration = 500UL; // default to 2 sec + if(strlen(args)>1) sscanf(args, " %lu %lu", &frequency, &duration); // try to read the args, keep the defaults if missing + //Serial.print((int) frequency); + //Serial.print((int) duration); + _tone(frequency, duration); + //delay(1000); + //playTone(frequency, duration, 1); // sine + return true; + } + #endif + #if defined(HAS_NS4168_SPKR) //M5StickCs doesn't have speakers.. they have buzzers on pin 02 that only beeps in different frequencies if(cmd_str.startsWith("music_player " ) ) { // || cmd_str.startsWith("play " ) String song = cmd_str.substring(13, cmd_str.length()); diff --git a/src/modules/others/audio.cpp b/src/modules/others/audio.cpp index 934eb180..716b061d 100644 --- a/src/modules/others/audio.cpp +++ b/src/modules/others/audio.cpp @@ -1,6 +1,9 @@ #include "audio.h" #include -#include +#include "AudioGeneratorMIDI.h" +#include "AudioFileSourceFunction.h" +#include "AudioGeneratorWAV.h" +#include "AudioOutputI2SNoDAC.h" #include #include "core/mykeyboard.h" @@ -117,4 +120,75 @@ bool isAudioFile(String filepath) { return filepath.endsWith(".opus") || filepath.endsWith(".rtttl") || filepath.endsWith(".wav") || filepath.endsWith(".mod") || filepath.endsWith(".mp3") ; } + + +void playTone(unsigned int frequency, unsigned long duration, short waveType) +{ + // derived from https://github.com/earlephilhower/ESP8266Audio/blob/master/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino + + if(frequency==0 || duration==0) return; + + float hz = frequency; + + AudioGeneratorWAV* wav; + AudioFileSourceFunction* file; + AudioOutputI2S* out = new AudioOutputI2S(); + out->SetPinout(BCLK, WCLK, DOUT); + + file = new AudioFileSourceFunction( duration/1000.0); // , 1, 44100 + // + // you can set (sec, channels, hz, bit/sample) but you should care about + // the trade-off between performance and the audio quality + // + // file = new AudioFileSourceFunction(sec, channels, hz, bit/sample); + // channels : default = 1 + // hz : default = 8000 (8000, 11025, 22050, 44100, 48000, etc.) + // bit/sample : default = 16 (8, 16, 32) + + // ===== set your sound function ===== + + if(waveType==0) { // square + file->addAudioGenerators([&](const float time) { + float v = ( sin(hz * time) >= 0 ) ? 1.0f : -1.0f;; // generate square wave + v *= 0.1; // scale + return v; + }); + } + else if(waveType==1) { // sine + file->addAudioGenerators([&](const float time) { + float v = sin(TWO_PI * hz * time); // generate sine wave + v *= fmod(time, 1.f); // change linear + v *= 0.1; // scale + return v; + }); + } + // TODO: more wave types: triangle, sawtooth + // + // sound function should have one argument(float) and one return(float) + // param : float (current time [sec] of the song) + // return : float (the amplitude of sound which varies from -1.f to +1.f) + + wav = new AudioGeneratorWAV(); + wav->begin(file, out); + + while (wav->isRunning()) { + if (!wav->loop() || checkAnyKeyPress()) wav->stop(); + } + + delete file; + delete wav; + delete out; +} + #endif + + +void _tone(unsigned int frequency, unsigned long duration) { +#if defined(BUZZ_PIN) + tone(BUZZ_PIN, frequency, duration); +#elif defined(HAS_NS4168_SPKR) + // alt. implementation using the speaker + playTone(frequency, duration, 0); +#endif +} + diff --git a/src/modules/others/audio.h b/src/modules/others/audio.h index 272dfb5e..50489dad 100644 --- a/src/modules/others/audio.h +++ b/src/modules/others/audio.h @@ -9,4 +9,8 @@ bool playAudioRTTTLString(String song); bool tts(String text); -bool isAudioFile(String filePath); \ No newline at end of file +bool isAudioFile(String filePath); + +void playTone(unsigned int frequency, unsigned long duration = 0UL, short waveType=0); + +void _tone(unsigned int frequency, unsigned long duration = 0UL); \ No newline at end of file From 3e12f7e12a93c9d5d4f19f6f32e0c3c405a4b147 Mon Sep 17 00:00:00 2001 From: eadmaster <925171+eadmaster@users.noreply.github.com> Date: Tue, 6 Aug 2024 08:55:38 +0200 Subject: [PATCH 5/5] fix for BUZZ_PIN missing (#113) --- src/core/serialcmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/serialcmds.cpp b/src/core/serialcmds.cpp index f12488f6..391eedd8 100644 --- a/src/core/serialcmds.cpp +++ b/src/core/serialcmds.cpp @@ -15,7 +15,7 @@ #include "modules/ir/TV-B-Gone.h" #include "modules/others/bad_usb.h" -#if defined(HAS_NS4168_SPKR) +#if defined(HAS_NS4168_SPKR) || defined(BUZZ_PIN) #include "modules/others/audio.h" #endif